Und hier kommt - die 1000ste Variante der LED-Soft-PWM mit AVR.
Das Rad ist ja wahrscheinlich auch mehr als einmal erfunden worden...
Freilich geht das viel eleganter mit PWM-Treibern oder gleich
WS2812-Stripes.
Und auf den ersten Blick könnte es scheinen, als ginge es alternativ zum
gewählten parallelen Ansatz auch seriell via SPI, z.B. mit
'595-Schieberegistern - würde eine Menge Pins am Controller sparen, aber
für 256 LEDs ist die erforderliche Durchsatzrate an einem SPI (oder auch
an zwei) nicht zu schaffen.
Bei der Beschäftigung mit der Frage, wieviele LEDs wohl von einem AVR8
mit Soft-PWM gesteuert werden können, habe ich dann die
Bitwinkelmodulation nochmal neu kreiert (den Begriff fand ich erst
später im Internet, Beschreibung z.B.
https://www.mikrocontroller.net/attachment/207919/BitAngleModulation.pdf).
Um's auf die Spitze zu treiben, hab ich einen Proof of Concept mit 256
LEDs aufgebaut. Ist ziemlich Retro geworden...
Die LEDs sind nicht gemultiplext, jede LED hat ihren eigenen
Treiber-Ausgang. Da ich noch einige 74ALS574 hier liegen hatte, kamen
diese zum Einsatz. 24 mA pro Ausgang bei Low-Pegel reichen dicke für die
Standard-LEDs. Die LEDs sind diffuse 3mm Ultrahell-Typen, die alle ihre
ca. 20 mA bekommen. Das ist möglicherweise etwas zu viel des Guten -
sind alle an, strahlen locker 1000 Cd. Die ganze Konstruktion ist auf
Lochraster (zwei 200x100 Platinen, in der Mitte zusammengenäht)
aufgebaut, in den vier Ecken sitzt je ein 1,7 A-StepDown-Wandler, der
die 5V Versorgungsspannung für jeweils 64 LEDs + Treiber bereitstellt.
Die gesamte Schaltung wird von einem 12V/36W-Netzteil gespeist.
Als Antrieb dient ein ATmega1284P mit 20 MHz Takt (oder ein bißchen
mehr, sagen wir 22).
Passend zur Jahreszeit ist's ein Stern geworden (vierzackig, die
üblichen fünf Zacken lassen sich auf dem Lochraster nicht vernünftig
umsetzen). Es sind 108 blaue, 88 rote und 60 grüne LEDs, mit dieser
Verteilung gibt's tatsächlich so etwas wie weißes Licht, wenn alle
zusammen eingeschaltet sind.
Die anhängende Schaltung soll nur das das Prinzip der Ansteuerung
verdeutlichen und stellt keine Nachbauanleitung dar (alle ICs sind
natürlich mit einem Stützkondensator versehen, die LEDs haben
entsprechend ihrer unterschiedlichen Flußspannung auch unterschiedliche
Vorwiderstandswerte usw.).
Im Prinzip wäre es auch möglich, die CLK-Eingänge der Treiber über einen
1-aus-16 Decoder (2 x '238 oder ein '4514) zu steuern, statt "sbi
PORTx,y" mit zwei Taktzyklen wäre dann halt "ldi r16,y : out PORTx,r16"
mit je einem Taktzyklus zu verwenden, damit blieben ein paar Portpins
verfügbar.
Bei der Inbetriebnahme hat sich gezeigt, daß durch die unvermeidlich
weitläufige Verdrahtung und die schnellen Treiber Übersprecheffekte
auftreten, durch die auch nicht direkt angesteuerte LEDs mit geleuchtet
haben. Ein 220 pF-Kerko an jedem Treiber-CLK-Eingang schaffte
zuverlässig Abhilfe.
Die softwaremäßige Umsetzung trägt vielleicht doch den einen oder
anderen neuen Aspekt zum Thema bei.
Erreicht wurde ein 10 Bit-PWM-Äquivalent mit gut 110 Hz "PWM"-Frequenz
(bei 20 MHz Controller-Takt), ein Flimmern ist nicht wahrnehmbar.
Die Interrupt-Routine ist vollkommen linear - weniger Jitter geht nicht
- und verändert keine Flags.
1
;r15=0
2
interrupt: ;4 clocks for interrupt latency
3
ld r14,X+ ;2
4
out PORTB,r14 ;1
5
ld r14,X+ ;2
6
out PORTC,r14 ;1
7
sbi PORTA,0 ;2
8
out PORTA,r15 ;1
9
ld r14,X+ ;2
10
out PORTB,r14 ;1
11
ld r14,X+ ;2
12
out PORTC,r14 ;1
13
sbi PORTA,1 ;2
14
out PORTA,r15 ;1
15
ld r14,X+ ;2
16
out PORTB,r14 ;1
17
ld r14,X+ ;2
18
out PORTC,r14 ;1
19
sbi PORTA,2 ;2
20
out PORTA,r15 ;1
21
ld r14,X+ ;2
22
out PORTB,r14 ;1
23
ld r14,X+ ;2
24
out PORTC,r14 ;1
25
sbi PORTA,3 ;2
26
out PORTA,r15 ;1
27
ld r14,X+ ;2
28
out PORTB,r14 ;1
29
ld r14,X+ ;2
30
out PORTC,r14 ;1
31
sbi PORTA,4 ;2
32
out PORTA,r15 ;1
33
ld r14,X+ ;2
34
out PORTB,r14 ;1
35
ld r14,X+ ;2
36
out PORTC,r14 ;1
37
sbi PORTA,5 ;2
38
out PORTA,r15 ;1
39
ld r14,X+ ;2
40
out PORTB,r14 ;1
41
ld r14,X+ ;2
42
out PORTC,r14 ;1
43
sbi PORTA,6 ;2
44
out PORTA,r15 ;1
45
ld r14,X+ ;2
46
out PORTB,r14 ;1
47
ld r14,X+ ;2
48
out PORTC,r14 ;1
49
sbi PORTA,7 ;2
50
out PORTA,r15 ;1
51
ld r14,X+ ;2
52
out PORTB,r14 ;1
53
ld r14,X+ ;2
54
out PORTC,r14 ;1
55
sbi PORTD,0 ;2
56
out PORTD,r15 ;1
57
ld r14,X+ ;2
58
out PORTB,r14 ;1
59
ld r14,X+ ;2
60
out PORTC,r14 ;1
61
sbi PORTD,1 ;2
62
out PORTD,r15 ;1
63
ld r14,X+ ;2
64
out PORTB,r14 ;1
65
ld r14,X+ ;2
66
out PORTC,r14 ;1
67
sbi PORTD,2 ;2
68
out PORTD,r15 ;1
69
ld r14,X+ ;2
70
out PORTB,r14 ;1
71
ld r14,X+ ;2
72
out PORTC,r14 ;1
73
sbi PORTD,3 ;2
74
out PORTD,r15 ;1
75
ld r14,X+ ;2
76
out PORTB,r14 ;1
77
ld r14,X+ ;2
78
out PORTC,r14 ;1
79
sbi PORTD,4 ;2
80
out PORTD,r15 ;1
81
ld r14,X+ ;2
82
out PORTB,r14 ;1
83
ld r14,X+ ;2
84
out PORTC,r14 ;1
85
sbi PORTD,5 ;2
86
out PORTD,r15 ;1
87
ld r14,X+ ;2
88
out PORTB,r14 ;1
89
ld r14,X+ ;2
90
out PORTC,r14 ;1
91
sbi PORTD,6 ;2
92
out PORTD,r15 ;1
93
ld r14,X+ ;2
94
out PORTB,r14 ;1
95
ld r14,X+ ;2
96
out PORTC,r14 ;1
97
sbi PORTD,7 ;2
98
out PORTD,r15 ;1
99
ld r14,X+ ;2
100
sts (OCR3AH),r14 ;2
101
ld r14,X+ ;2
102
sts (OCR3AL),r14 ;2
103
ld r14,X+ ;2
104
ld XH,X ;2
105
mov XL,r14 ;1
106
reti ;5
107
;165 clock cycles
Die vom Interrupt verwendeten Register sind exklusiv reserviert und
werden deshalb nicht gesichert.
Die im RAM liegende Tabelle enthält für jeden Interrupt-Zyklus das
auszugebende LED-Bitmuster, den Timer-Wert für den nächsten Zyklus und
einen Pointer auf die Tabellendaten für den nächsten Schritt (im letzten
Schritt dann halt wieder zurück zum Tabellenanfang).
Das Setzen des Bitmusters für eine LED in der Tabelle erfordert ca. 6
us, die Berechnung der Effekte erfolgt in der letzten Periode (512
Bitzeiten, ca. 4,5 ms) - Zeit genug, um bei Bedarf alle LEDs upzudaten.
Der Prozessor wartet im Sleep-Modus auf den nächsten Timer-Interrupt,
auch hier gibt's also keinen Jitter.
Beim Testen von langsamen Helligkeitsänderungen hat sich noch ein
grundsätzliches Problem mit dieser Methode der LED-Modulation gezeigt -
bei einigen Schritten war ein deutliches Flackern zu erkennen.
Ursache sind Inhomogenitäten im Ausgabe-Bitstrom bei kritischen
Übergängen.
Beispiel (4 Bit, sonst wird's zu unübersichtlich):
Änderung von 7 auf 8
Für eine statische 7 werden acht Null-Bitzeiten ausgegeben, für eine 8
entsprechend sieben.
Beim Wechsel von 7 auf 8 gibt es jedoch 15 Null-Bitzeiten
hintereinander, die LED flackert (bei Änderung von 8 auf 7 sind's 15
Eins-Bitzeiten, es flackert ebenfalls).
Bei 10 Bit Auflösung sind's natürlich entsprechend mehr Bitzeiten, wenn
z.B. von 511 auf 512 gewechselt wird.
Ich habe mir dazu etwas einfallen lassen, bei Übergängen auf den beiden
höchstwertigen Ausgabebits 8/9 werden die niederwertigen Bits
entsprechend ausmaskiert bzw. auf 1 gesetzt. Damit ließ sich eine
deutliche Verbesserung erreichen, ein Flackern ist nicht mehr
wahrnehmbar. Das Handling erhöht die Zeit für das Setzen des Bitmusters
pro LED auf 7.2 us (@20 MHz), immer noch kurz genug, um pro PWM-Zyklus
alle LEDs updaten zu können (inkl. Effektberechnung).
Die Definition der Effekte erfolgt über Tabellen, der Code selbst ist
sehr kompakt. Das Mapping der LED-Nummern auf die Ausgänge der Treiber
wird mit einem Macro (bzw. 16 Sub-Macros) beim Assemblieren gemacht und
kostet deshalb keine zusätzliche Rechenzeit des Controllers; es ist also
vollkommen egal, welche LED an welchem Ausgang hängt.
Hier gibt's ein Beispielvideo, die Smartphonekamera war allerdings
deutlich überfordert.
https://youtu.be/GGLlUPStPn8
Da klappt einem glatt die Kinnlade runter!
Damit man noch länger an dem Gerät freude hat empfehle ich dir die
Stepdowns auszutauschen.
Die dort verwendeten sind leider ziemliche Chinaböller.
So stimmt zB nichtmal der angegebene PWM Takt und beim durchtsten hatten
die auch nen ziemlich miesen Wirkungsgrad.
Wer weis wann die Vollstoff auf die LEDs geben :/
Mw E. schrieb:> Da klappt einem glatt die Kinnlade runter!>> Damit man noch länger an dem Gerät freude hat empfehle ich dir die> Stepdowns auszutauschen.> Die dort verwendeten sind leider ziemliche Chinaböller.> So stimmt zB nichtmal der angegebene PWM Takt und beim durchtsten hatten> die auch nen ziemlich miesen Wirkungsgrad.> Wer weis wann die Vollstoff auf die LEDs geben :/
Die sehen für mich wie die von muRata aus, mit denen habe ich bisher nur
gute Erfahrungen gemacht.
Checker schrieb:> Nur der Sinn vom Sleepmode erschliesst sich einem nicht.
Durch das Warten auf den nächsten Interrupt im Idle-Status ist
sichergestellt, daß immer eine identische Anzahl von Prozessortakten bis
zum Sprung in die Interrupt-Routine verwendet wird. Arbeitet der
Prozessor irgendwelchen Code ab, kann es - abhängig von der gerade
ausgeführten Instruktion - ein bis vier Takte dauern, bis es mit der
Interruptbearbeitung losgeht --> Jitter.
Ob das eine wahrnehmbare Rolle spielt (Flicker), habe ich nicht
untersucht, denn mit dem Sleep ist die Synchronisation auf die
Interrupt-Zyklen auch viel einfacher.
Berthold schrieb:> Wie lange hast du für den Aufbau gebraucht?
Naja, das ist schon eine ziemliche Verdrahter- und Löterei gewesen, da
stecken etliche "zweite Schichten" nach dem regulären Feierabend drin...
Bzgl. StepDowns: Ja, das sind diese Chinaböller (einer war gleich von
Anfang an defekt). Den Murata OKI515W36C hatte ich bei der Suche bereits
im Fokus, aber zum Probieren waren mir vier Stück bei den üblichen
Verdächtigen (Reichelt etc.) zu teuer.