Morgähn zusammen :)
Ja, ich hab die Suche benutzt. Nein, nichts passendes gefunden. Ich habe
einen LED-Controller gebaut (3 Kanäle a 3 Farben), der die LEDs dimmen
soll. Zum Steuern wird ein serielles Protokoll verwendet (momolight,
R1R2R3G1G2G3B1B2B3 byteweise über 19k2 Baud). Prozessortakt 14,7456 Mhz
(so dass es vom UART her paßt). Gammakorrektur mit Faktor 2,2 ist
eingebaut.
Problem: 8 Bit SoftPWM hat bei dunklen Farben viel zu wenig Dynamik,
die dunkelste Einstellung (also 1:1:1) gibt viel zu helle Farben, 0:0:0
macht die LEDs aber aus.
Ich möchte deswegen eine 12bit PWM verwenden, die Werte der
Gammakorrektur kann ich ja entsprechend berechnen. Mein Programm schaut
in etwa so aus:
1
//Compiler: Codevision, Optimize4Speed
2
3
//Gammakorrektur
4
flashunsignedintgammaArray22[256]={
5
0,0,1,1,2,3,4,.......,4090,4095
6
};
7
8
//Variablen
9
unsignedintc1r,c1g,c1b;
10
unsignedintc2r,c2g,c2b;
11
unsignedintc3r,c3g,c3b;
12
unsignedintpwmCounter;
13
unsignedcharrxCounter;
14
15
// Atmega IO konfigurieren
16
DDRA=0xFF;
17
DDRB=0xFF;
18
19
//USART
20
UCSRA=0x00;
21
UCSRB=0x10;
22
UCSRC=0x86;
23
UBRRH=0x00;
24
UBRRL=0x2F;
25
26
//PWM
27
while(1){
28
29
//Bei 0 alle einknipsen
30
if(++pwmCounter==4095){
31
pwmCounter=0;
32
PORTA=0xFF;//hier alle
33
PORTB=0x80;//hier nur einer
34
}
35
36
//Bei match pro Kanal LED wieder ausknipsen
37
if(pwmCounter==c1r){PORTA.0=0;}
38
if(pwmCounter==c2r){PORTA.1=0;}
39
//...
40
if(pwmCounter==c3b){PORTB.7=0;}
41
42
//Serielle Behandeln
43
if(UCSRA&RX_COMPLETE){//RX_COMPLETE ist von CV definiert
44
rxCounter++;
45
if(rxCounter==1){c1r=gammaArray22[UDR];}
46
if(rxCounter==2){c2r=gammaArray22[UDR];}
47
//...
48
if(rxCounter==9){
49
c2r=gammaArray22[UDR];
50
rxCounter=0;
51
}
52
}
53
}
Da das ganze über einen FTDI am USB hängt, hab ich mir Code zur
Erkennung des Sync-Verlustes gespart. MAcht aber auch nichts, es geht so
ganz gut, bis auf, dass ca. alle 1/4 Sekunde sporadisch die LEDs
aufblitzen. Ich hab keinerlei Interrupts an, keine Timer, USART wird
gepollt. Nunja, ein Blitzen der LEDs ist ja nicht tragbar, aber was
könnte denn falsch sein?
Danke,
Christoph
@Christoph Söllner (mcseven)
>Ja, ich hab die Suche benutzt. Nein, nichts passendes gefunden.
Dann hast du schlecht gesucht.
Soft-PWM>Problem: 8 Bit SoftPWM hat bei dunklen Farben viel zu wenig Dynamik,>die dunkelste Einstellung (also 1:1:1) gibt viel zu helle Farben, 0:0:0>macht die LEDs aber aus.LED-Fading>Ich möchte deswegen eine 12bit PWM verwenden, die Werte der
Naja, 12 Bit als Soft-PWM wird eng. Denn 100 Hz*4096=40kHz = 25us. Macht
bei 16 MHz Prozessortakt gerade mal noch 400 CPU Takte pro PWM Takt.
Geht aber mit der Software im Artikel ;-)
MFG
Falk
Ja, aber wenn noch der Interrupt von der seriellen dazukommt (oder ein
positiver Match beim Pollen), dann gibts ja wieder geflacker... Im
Programm oben, das was mit xx% CPU Last läuft (ist mir aber egal :))
flackert nix, wenn kein Empfang auf der seriellen Schnittstelle
stattfindet.
Das wird ja im Artikel nicht behandelt. Denn wenn grade der Timer
Interrupt die LEDs setzt und da dazwischen die serielle bedient werden
möchte, flackerts. Auch würde für eine LED ja die Gammakorrektur mittels
Array benötigt, das kostet wieder CPU.
Gibts denn sowas nicht in Hardware? Hab so ein 4 Kanal-Ding gefunden,
das aber nicht mehr hergestellt wird (M66240). Die TI Treiber sind für
Displays gedacht und erwarten, dass an den Ausgängen Strom fließt. Bei
mir hängt aber ein MOSFET dran, der ne ganze LED-Leiste treibt. Deswegen
werden die TI Dinger mit ihrer Fehlerkorrektur (Temperatur, kaputte LED)
wohl nicht funktionieren.
Ein mega AVR 640 würde diese Anforderung zwar erfüllen, aber weder die
Platine, noch das Löten dieses Monsters trau ich mir zu. Der 1281 hat
wieder nur 6 OCXn.
Auch die dsPICs haben "nur" 3 DutyCycle Generatoren und könnten nur eine
LED-Leiste antreiben, ich hätte aber gerne ein einziges IC :)
Naja, vielleicht habt ihr noch Ideen? Bitte nicht FPGA/CLPD. Ich such
etwas, was ich mit meinem auf MCU/C beschränkten Wissen ^^ und
vorhandener IDE (CodeVision, AVR Studio/ WinAVR) benutzen kann.... Also
einen Chip etwa, dem ich seriell die Daten reinschiebe und der schiebt
sie per PWM am anderen Ende wieder raus...
Danke, Christoph
Dann nimm doch keinen Interrupt für die Serielle Schnittstelle, sondern
polle sie in einer Unterroutine. Die PWM sollte per Timer-ISR laufen und
hat Vorrang, alles andere darf unterbrochen werden. Bei der nicht allzu
hohen Baudrate von 19200 ist das kein Problem.
@Christoph Söllner (mcseven)
>Gibts denn sowas nicht in Hardware? Hab so ein 4 Kanal-Ding gefunden,
Ja, TLC5920 & Co.
>Ein mega AVR 640 würde diese Anforderung zwar erfüllen,
Wieso? Der hat ausser viel Flash und RAM nicht mehr als ein Tiny, was
Soft-PWM angeht.
>vorhandener IDE (CodeVision, AVR Studio/ WinAVR) benutzen kann.... Also>einen Chip etwa, dem ich seriell die Daten reinschiebe und der schiebt>sie per PWM am anderen Ende wieder raus...
Hast du schon. AVR. Geht wunderbar. Für deine 9 Kanäle reicht eine
kleiner ATtiny2313.
MFG
Falk
Hi, Danke Dir.
> Dann nimm doch keinen Interrupt für die Serielle Schnittstelle, sondern> polle sie in einer Unterroutine.
Meinst Du damit eine Schleife (while (1) {...}) des Hauptprogramms?
> Die PWM sollte per Timer-ISR laufen und hat Vorrang,
Wie stelle ich "Vorrang" ein? Interrupt-Priorität kennt ein AVR nicht.
> alles andere darf unterbrochen werden. Bei der nicht allzu> hohen Baudrate von 19200 ist das kein Problem.
So einfach ist das nicht. Realisiere ich das dritte Beispiel im Artikel
und es passiert, dass alle Kanäle dunkel sind, dann kommt der Timer IR
sehr oft hintereinander, der serielle Empfang wird dann oft genug
unterbrochen, um selbst bei 19200=2400 byte / Sekunde einen Datenverlust
zu haben.
@falk
:) Wenn es nur um PWM ginge, habt ihr Recht. Das tut ja. Siehe oben.
Aber wenn noch Empfang auf der seriellen dazukommt, mit unregelmäßiger
(wenig Zeit bei Kanal 2-8, mehr Zeit bei Kanal 1 und 9) Bearbeitungszeit
der seriellen ServiceRoutine (egal ob ISR oder Hauptprogramm), dann
flackerts... Wie kann ich das denn beheben?
Hallo Christoph,
könnte das Flackern vielleicht von Seiteneffekten der seriellen
Empfangsroutine verursacht werden? Du benutzt schließlicht 16-Bit
Zahlen.
@Christoph Söllner (mcseven)
>> polle sie in einer Unterroutine.>Meinst Du damit eine Schleife (while (1) {...}) des Hauptprogramms?
Ja.
>Wie stelle ich "Vorrang" ein? Interrupt-Priorität kennt ein AVR nicht.
Indem du keinen anderen Interrupt nutzt, auch nicht für den UART.
>sehr oft hintereinander, der serielle Empfang wird dann oft genug>unterbrochen, um selbst bei 19200=2400 byte / Sekunde einen Datenverlust>zu haben.
Mit welchem Takt läuft dein AVR? Für 12 Bit PWM brauchst du schon 16
MHz.
>Aber wenn noch Empfang auf der seriellen dazukommt, mit unregelmäßiger>(wenig Zeit bei Kanal 2-8, mehr Zeit bei Kanal 1 und 9) Bearbeitungszeit>der seriellen ServiceRoutine (egal ob ISR oder Hauptprogramm), dann>flackerts...
Dann ist deine Routine noch nicht so wie sie sein soll.
Poste mal VOLLSTÄNDIGEN Code im Anhang.
MFG
Falk
Naja, die Empfangsroutine ist ja oben zu sehen. Es hatte keine Rolle
gespielt, ob ich die in der Hauptschleife oder einer ISR arbeiten lasse.
Tatsache ist mMn eben, dass der USART mit seinem unregelmäßigen
Rechenzeitverlangen die 12bit PWM sporadisch unmöglich macht.
Deswegen auch meine Frage, ob es Alternativen gäbe. Ein 640 hätte
nämlich 12 16bit Output Compares und würde das Problem nicht haben,
wegen Hardware PWM. Aber das ist ja der reinste Overkill :)
Was ich heute abend noch probieren werde, ist, ob es nicht ausreicht,
den USART immer bei "0" des pwmCounter zu pollen: 14745600/4096 = 3600,
bei kontinuierlichem Senden würden aber "nur" 2400 Bytes/sek reinkommen,
und wegen des PC-Programms zum steuern, dass nur alle 10ms die 9 Byte
sendet, sogar noch viel weniger. Aber ich fürchte, dass es auch da
sporadisch zu hellen Flecken kommt, werde aber nochmal berichten.
@falk
Code anbei, es werden nur die ersten 6 Variablen auf R4, R6, R8, R10,
R12, R14 gemappt, alles andere kommt in RAM, vermutlich, weil der
Compiler den Rest an Registern für seine Makros braucht.
Hi,
ich würde die PWM im Timerinterrupt machen.
Die serielle in der Main() pollen und dabei gleich die gammakorrektur
anwenden und die Bits so umsortieren das kein IF mehr im Interrupt
notwendig ist.
Du hast ja PORTA und PORTB verwendet, also kannst Du eine Routine haben
die du in der main() aufruftst die etwa so aussieht:
uint16_t led_array[12];
SetLed(uint8_t num, uint16_t value)
{
for (i = 0; i < 12; i++)
{
if ((_BV(i) & value) != 0)
led_array[i] |= _BV(num);
else
led_array[i] &= !_BV(num);
}
}
im Interrupt dann sowas:
Int() // Sollte ein 16Bit Timer sein!
{
static uint8_t bit_count;
static uint16_t timer_count;
bit_count++;
if (bit_count >= 12) bit_count = 0;
PORTA = led_array[bit_count] & 0xff;
PORTB = led_array[bit_count] >> 8;
TCNT1 += 1 << bit_count;
}
dabei den Timer so einstellen das er abwärts zählt und immer bei 0 einen
Interrupt auslöst.
Gruß Alex
@ Christoph Söllner (mcseven)
>Naja, die Empfangsroutine ist ja oben zu sehen. Es hatte keine Rolle>gespielt, ob ich die in der Hauptschleife oder einer ISR arbeiten lasse.
Das ist aber ein Unterschied.
>Tatsache ist mMn eben, dass der USART mit seinem unregelmäßigen>Rechenzeitverlangen die 12bit PWM sporadisch unmöglich macht.
Das ist ja auch ein Fehler. Wurde mehrfach gesagt. Die PWM muss in die
Timer ISR, um in regelmässigen Anständen aufgerufen zu werden. Der Rest
bleibt in der Hauptschleife. Kann man noch ein wenig verbessern. Anstatt
der vielen If ein einfacher Array-Zugriff.
Aber es fehlt eine Synchronisarion deiner UART-Daten. Woher weisst du,
wo in der Reihenfolge Byte 0 ist? Das kann Flackern bzw. direkte
Farbfehler erzeugen.
>wegen Hardware PWM. Aber das ist ja der reinste Overkill :)
Ein wenig ;-)
>Was ich heute abend noch probieren werde, ist, ob es nicht ausreicht,>den USART immer bei "0" des pwmCounter zu pollen: 14745600/4096 = 3600,
Falsch. Dort fehlt die PWM-Freqeuenz von z.B. 100 Hz.
>bei kontinuierlichem Senden würden aber "nur" 2400 Bytes/sek reinkommen,>und wegen des PC-Programms zum steuern, dass nur alle 10ms die 9 Byte>sendet, sogar noch viel weniger.
Egasl, du musst aber die 9 Byte in einem Ruscht empfangen.
> Aber ich fürchte, dass es auch da>sporadisch zu hellen Flecken kommt, werde aber nochmal berichten.
Denk mal drüber nach. Das funktioniert soo einfach nicht. Aber pollen
ist der richtige Weg.
MFG
Falk
> Aber es fehlt eine Synchronisarion deiner UART-Daten. Woher weisst du,> wo in der Reihenfolge Byte 0 ist? Das kann Flackern bzw. direkte> Farbfehler erzeugen.
Ja, ein Schwachpunkt des Momolight-Protokolls, nachdem der serielle Weg
aber nur ein paar cm lang ist, war's mir egal. Und bei 8 Bit PWM hatte
er auch nach 11h Film gucken ^^ keinen Sync-Verlust.
Wenn es mit 16bit geht, würde ich einen 2. Timer einbauen, der beim
Empfang eines Bytes auf 0 gesetzt wird und nach 5ms den rxCounter wieder
auf 0 setzt. Die PC-SW sendet ja nur alle 10ms die 9 Bytes. 9 Bytes
dauern 9/2400= 0,00375s, wenn also 1 Bytes flöten geht, würde nach 0,005
rechtzeitig der Index vor dem nächsten Schwung bei 0,010s zurückgesetzt.
@Christoph Söllner (mcseven)
>Wenn es mit 16bit geht,
16 Bit?
> würde ich einen 2. Timer einbauen, der beim>Empfang eines Bytes auf 0 gesetzt wird und nach 5ms den rxCounter wieder>auf 0 setzt.
Ja, per Timeout kann man recht leicht synchronisieren. Kannst du aber
auch iohen extra Timer machen, einfach in den bestehen TImerinterrupt
für die PWM reinpacken. Der wird dann zwar mit 40kHz gezählt, macht aber
nix.
MFG
Falk
Hi, habe jetzt mal Programm wie im Anhang "verbrochen". Aber es will
immer noch nicht. Sobald schnelle Farbwechsel kommen, flackern die LEDs
sporadisch kurz (~0.5s) hintereinander mit voller Helligkeit auf, was
insbesondere bei dunklen Szenen sehr nervig ist.
Das Flackern ist unabhängig vom Abstand der 9Byte-Pakete zueinander (von
10ms bis 100ms einstellbar).
Wo hab ich denn den Denkfehler?
@ Christoph Söllner (mcseven)
>Das Flackern ist unabhängig vom Abstand der 9Byte-Pakete zueinander (von>10ms bis 100ms einstellbar).>Wo hab ich denn den Denkfehler?
In der Synchronisation von neuen Datenpaketen und deiner PWM. Die PWM
darf erst dann einen neuen Datensatz "ansaugen", wenn sie einen vollen
Zyklus erledigt hat. Während dieser Zeit muss deine UART-Empfangsroutine
die Daten in einen dritten Puffer zeischenspeichern oder muss warten.
Sonst verschluckt sich die PWM mit den von dir beobachteten Effekten.
Das hast du bisher nur begrenzt gemacht. Denn in dem Moment, wo gerade
das 9. Byte per UART empfangen wurde kann es sein, dass die PWM gerade
neu angefangen hat (loopCounter =1). Dann dauer es ~10ms, bis die neuen
Daten übernommen werden können. Du schreibst währenddessen aber schon
wieder Daten in den aktuellen Puffer. Das knallt.
Denn überleg mal. Wen deine Daten im 10ms Raster = 100 Hz ankommen, muss
mit jedem PWM-Zyklus ein neuer Datensatz aktiviert werden. Das geht aber
nur, wenn Datenquelle und PWM synchron laufen. Das kann man z.B.
erreichen, indem deine PWM als Monoflop läuft. Sprich, wenn ein
kompletter Datensatz empfangen wurde, wird dieser EINMALIG als PWM
ausgegeben. Ein neuer PWM-Zyklus startet nur dann, wenn neue Daten
angekommen sind. Jetzt ist deine PWM voll synchron zum Datenatrom. Nun
musst du nur noch mit 100 Hz Daten senden und alles ist OK.
Ausserdem hast du noch ein paar kleine Fehler drin. In der ISR liest du
mehrfach PINC und PINA, wo du aber sicher PORTC und PORTA meinst. Ist
hier im Ergenis gleich, kann aber bisweilen zu komischen Effekten
führen.
Ich bin mit nicht sicher, ob es eine Gute Idee ist, takeNewValuesOK in
der Hauptschleife zu löschen. Das kann im Ausnahmefall ins Auge gehen
und die PWM verschluckt sich. Besser so.
Ausserdem sollte man für sowas den CTC Modus verwenden, macht die Sache
einfacher und genauer.
Probier mal den Code im Anhang, den Namen des Vektors hab ich mal
geraten.
MFG
Falk
Hi, jetzt hab ich mich zwei Tage lang im Bastelkeller verbuddelt, und
wieder einiges zu berichten :)
Also Dein Code hatte nicht sooo viel ausgemacht, ich denke zwischen CTC
und normalem Overflow Modus besteht wenig Unterschied, bei beiden muss
ich ein 16bit Register setzen. Das Flackern war noch vorhanden.
Entscheidend war aber die Idee mit dem Tripple-Buffering, ich hab das
Codevision Programm einmal angepaßt (siehe Anhang). Tut einwandfrei, ist
aber noch immer nicht perfekt.
Ich möchte schließlich ein Ambi-Light bauen, und keine
Disko-Beleuchtung. Bei 75 Hz waren mit der Software maximal 512 Schritte
(9bit) möglich, immer noch zu wenig Dynamik bei dunklen Farben.
Im Artikel Soft-PWM gibts ja noch nen dritten Ansatz, der hat aber
nur 8 Kanäle und zudem gibt's keine Möglichkeit, den Pin für einen Kanal
zu konfigurieren. Es soll ja so sein, dass sich die Software der
Hardware anpaßt und nicht umgekehrt :) Es gab also einiges zu ändern und
langer Rede kurzer Sinn: so ist's meinem Perfektionismus gerecht
geworden (siehe nächster Artikel)...
Also hier jetzt wie versprochen die finale Version. Ich kann einstellen,
wieviele Kanäle ich haben möchte (1-16), kann für jeden Kanal das
Bitmuster für maximal 2 Ports definieren (bin also frei in der Zuordnung
von Kanal zu Portpin(s)) und kann bei 19k2 bps mit 100Hz die Datenpakete
von Boblight (Version von 2007, Visual Studio Programm) in Empfang
nehmen.
Wie im Vorgänger hab ich drei Buffer für die Helligkeitswerte (MAIN,
SERIAL, TISR) und jeweils zwei für die Bitmuster pro PWM-Schritt (MAIN,
TISR).
Funktion:
1. Timer1 läuft im Interruptbetrieb mit 1024 PWM Schritten und lädt
sich für jeden Schritt der PWM a) den Zeitwert des Schrittes, b)
das auszugebende Bitmuster für PORT0 und c) das auszugebende Bit-
muster für PORT1.
Dann einfach nur noch CompareA auf den Wert setzen, Timercounter
auf 0 zurücksetzen, die Bitmuster auf die Ports ausgeben.
2. USART läuft auch im Interruptbetrieb und schreibt die eintreffenden
Helligkeitswerte (0-255) über die Gammakorrektur (0-1023) in den
seriellen Puffer. Wenn 9 Bytes eingetroffen sind, wird das Hauptpro-
gramm benachrichtigt.
3. Hauptprogramm: Es wartet darauf, den seriellen Buffer mit dem MAIN
Buffer zu vertauschen, dann werden auf dem MAIN Buffer und aus den
MAIN Portbitmustern jeweils die Zeiten und die Bitmuster für die
PWM Schritte berechnet und sobald der Timer mit einem PWM Zyklus
fertig ist, diese in die TISR Werte übernommen.
Durch USART Interrupt geht so kein Byte verloren, und es kann höchstens
passieren, dass einmal ein kompletter Frame vom USART verloren geht,
aber das ist besser, als ein Flackern der LEDs. Ich wollte noch
ausprobieren, ob auch 2048 Schritte gehen, um die LEDs noch dunkler zu
machen, aber das gibts erst nach Weihnachten :)
@ Christoph Söllner (mcseven)
>Also Dein Code hatte nicht sooo viel ausgemacht, ich denke zwischen CTC>und normalem Overflow Modus besteht wenig Unterschied,
Jain.
> bei beiden muss>ich ein 16bit Register setzen.
Abert beim CTC ist das Timing 100% sauber, bei deiner Relaod Methode ist
der Abstand der Timerinterrupts bisweilen abhängig von evtl. anderen
aktiven Interrupts und der Interrupt-Reaktionszeit.
> Das Flackern war noch vorhanden.
Klar.
>nur 8 Kanäle und zudem gibt's keine Möglichkeit, den Pin für einen Kanal>zu konfigurieren.
Kann man ja spielend ändern. Einfach statt 8 Bit Werten 16 oder 32 Bit
Werte nehmen. Und statt der linearen Bitmaskenberechung (Schieben) feste
Muster in einem Konstantenarray ablegen. Hast du ja fast so gemacht.
>1. Timer1 läuft im Interruptbetrieb mit 1024 PWM Schritten und lädt> sich für jeden Schritt der PWM a) den Zeitwert des Schrittes, b)
Ist aber immer noch ungünstig, dein Timing ist nicht wasserdicht. Mach
es wie im Artikel. Einfacher und besser.
>2. USART läuft auch im Interruptbetrieb und schreibt die eintreffenden> Helligkeitswerte (0-255) über die Gammakorrektur (0-1023) in den> seriellen Puffer. Wenn 9 Bytes eingetroffen sind, wird das Hauptpro-> gramm benachrichtigt.
Schlecht. Wenn dir der UART-Interrupt in den Timer-Interrupt reinspuckt
hast du vor allem bei dunklen Farben (kleine Pulsbreiten) deutliche
Störungen. Mach es per Polling in der Hauptschleife, die CPU hat sowieso
nix zu tun ;-)
>3. Hauptprogramm: Es wartet darauf, den seriellen Buffer mit dem MAIN> Buffer zu vertauschen, dann werden auf dem MAIN Buffer und aus den> MAIN Portbitmustern jeweils die Zeiten und die Bitmuster für die> PWM Schritte berechnet und sobald der Timer mit einem PWM Zyklus> fertig ist, diese in die TISR Werte übernommen.
Ob das mit deinem Tripple-Buffering jetzt wasserdicht kann ich auf die
Schnelle nicht überblicken. Aber ist alles in Allem schon mal ein
grosser Schritt in die richtige Richtung.
Frohes Fest und Happy LED-Dimming
Falk
Hi, jetzt ist's wieder ein paar Basteltage her :) Und wieder kann ich
berichten etwas mehr aus dem Reiche der LED-Dimmung.
Langer Rede kurzer Sinn: Es geht mit 75 Hertz bei 2048 PWM-Schritten und
die Dynamik am unteren Ende ist in Ordnung. Subjektiv sieht man's aber
gaaaanz leicht flimmern. Also noch nicht optimal.
> Abert beim CTC ist das Timing 100% sauber, bei deiner Relaod Methode ist> der Abstand der Timerinterrupts bisweilen abhängig von evtl. anderen> aktiven Interrupts und der Interrupt-Reaktionszeit.
Mag sein. Ich hab's also umgestellt auf CTC 12 mit ICR1 als
Compare-Register. Läuft auch recht sauber, der Frequenzzähler vom TEC
zittert nur auf der 4. Stelle hinterm Komma, das sollte zu verschmerzen
sein :)
> Schlecht. Wenn dir der UART-Interrupt in den Timer-Interrupt reinspuckt> hast du vor allem bei dunklen Farben (kleine Pulsbreiten) deutliche> Störungen. Mach es per Polling in der Hauptschleife, die CPU hat sowieso> nix zu tun ;-)
Wage gleich zweimal widersprechen zu dürfen, wenn ich die serielle polle
und zufällig gerade die Timer ISR dran ist und das Programm dann in der
Hauptschleife nicht schnell genug zum Abfragen der Seriellen kommt,
verliert man die Synchronisation. Passiert bei 1024 Schritten
gelegentlich, bei 2048 nach spätestens 2 Sekunden.
Auswirkung bei USART ISR-Betrieb: Selbst wenn Start/Ende einer
LED-Einschaltzeit ein wenig jittern (sieht man am Oszi recht gut: Ohne
Daten steht die PWM wie eine eins, mit Daten über USART wie gesagt
Jitter an der 4. Stelle hinterm Komma), so sieht man das nicht.
Es kommt also weniger darauf an, wieviel die ALU im Schnitt zu tun hat,
sondern vielmehr, wie die einzelnen Ereignisse zeitlich zueinander
gesehen abgearbeitet werden können. Schließlich kann sie sich nicht
zweiteilen =)
> Ob das mit deinem Tripple-Buffering [...]
Ja, das sollte soweit passen.
Nun zum Eingemachten: Ich möchte gerne die PWM-Frequenz erhöhen. Wenn
die 2m breite LED-Leiste nämlich passiv an eine Wand strahlt, dann sieht
man auch bei 75Hz gaaanz leicht flimmern.
Ich hab die PWM-Formeln aus dem Software-Artikel übernommen, die machen
ja Sinn. Außerdem hab ich die Cycles der Timer-ISR im Simulator gemessen
und komme auf 89. Wenn ich also die PWM-Frequenz erhöhen möchte, muss
die Timer ISR weiter optimiert werden, und ich sehe da als einzige
Möglichkeit nur noch, das (nur im ASM/*.lss) sichtbare Sichern der
Register auszuschalten.
Unter CodeVision ging das mit "#pragma regsave off" oder so ähnlich. Wie
kann ich das denn im WinAVR machen und wie kann ich dann dem Compiler
sagen, er soll nicht die Register verwenden, die er gesichert hätte
(die werden ja offensichtlich woanders gebraucht, sonst würden sie ja
nicht gesichert)?
Es würden 32 Takte eingespart werden können und das würde dann locker
für die 100 Hz reichen...