Damit erzeuge ich einen 3Phasen RGB PWM.
Den Timer habe ich wie folgt konfiguriert:
1
voidtimer_init(void)
2
{
3
4
TCCR0A|=(1<<WGM01);
5
TCCR0B|=(1<<CS01);
6
OCR0A=10;
7
TIMSK0|=(1<<OCIE0A);//iNTERRUPT BEIM erreichen des TOP wertes
8
}
Controller: Atmega324PV mit 10MHz
Wenn ich nun als Counter ein Byte also ein Char verwende,
dann läuft mir der PWM mommentan mit einer Frequenz von knapp 500Hz
wenn ich jedoch den typ auf int ändere also:
1
volatileunsignedintuiPWMCounter;
Dann erhalte ich zwar immer noch knapp 500Hz jedoch wird die Ausführung
des Restlichen Programmes massiv verzögert.
Etwa um den Faktor 50 mal langsamer.
Nun meine Vermutung:
Dauert das vergleichen eines Integers so viel länger als das eines
chars?
Hat jemand Empfehlungen, wie ich meinen Code auf speed optimieren
könnte?
Ich würde gerne mehr als nur 8bit PWM haben.
10bit und mehr wäre mein Ziel.
Danke schon mal.
@ Claudio Hediger (hedie)
>volatile unsigned char uiPWMCounter;
Warum volatile hier? Die Variable interessiert nur die ISR. Also sollte
sie auch dort lokal sein.
static char uiPWMCounter;
>unsigned char uiPWMRed;>unsigned char uiPWMGreen;>unsigned char uiPWMBlue;
Und hier fehlt das volatile ;-)
Siehe Interrupt.
>void timer_init(void)>{> TCCR0A |= (1<<WGM01);> TCCR0B |= (1<<CS01);> OCR0A = 10;> TIMSK0 |= (1<<OCIE0A); //iNTERRUPT BEIM erreichen des TOP wertes>}
Das ist Prescaler 1/8, sprich 1,25 MHz, macht bei einem 8-Bit Zähler
4,88 kHz PWM-Frequenz. Unsinnig hoch.
>Wenn ich nun als Counter ein Byte also ein Char verwende,>dann läuft mir der PWM mommentan mit einer Frequenz von knapp 500Hz
Wirklich? Da fehlt eher Faktor 10. ODer dein Controller läuft mit dem
internen RC-Oszillator von 1 MHz. AVR Fuses geprüft?
>Dann erhalte ich zwar immer noch knapp 500Hz jedoch wird die Ausführung>des Restlichen Programmes massiv verzögert.>Etwa um den Faktor 50 mal langsamer.
Ist ein Nebeneffekt. Wenn gleich die 16 Bit Rechung etwas länger dauert,
sooo viel ist das nicht.
>Dauert das vergleichen eines Integers so viel länger als das eines>chars?
Nicht soooo viel.
>Hat jemand Empfehlungen, wie ich meinen Code auf speed optimieren>könnte?
Indem du VOLLSTÄNDIGEN Code als Anhang postest.
>Ich würde gerne mehr als nur 8bit PWM haben.>10bit und mehr wäre mein Ziel.
Siehe Soft-PWM
* volatile wegmachen (da du den Counter nur in der ISR verwendest)
* counter runterzählen und mit 0 vergleichen
* die drei Leds in einem Portzugriff ausschalten
Aber eigentlich sollte der Code, wenn er auch nicht ganz effektiv ist,
reichen. Bei noch mehr Leds würde ich zu BAM greifen.
Falk Brunner schrieb:> Das ist Prescaler 1/8, sprich 1,25 MHz, macht bei einem 8-Bit Zähler> 4,88 kHz PWM-Frequenz. Unsinnig hoch.
Das ist nicht korrekt.
Du vergisst meinen TOP Value von 10.
Damit liege ich bei 125Khz und dann zählt er auf 250 was dann
einer PWM Frequenz von 500Hz entspricht!
Falk Brunner schrieb:>>Wenn ich nun als Counter ein Byte also ein Char verwende,>>dann läuft mir der PWM mommentan mit einer Frequenz von knapp 500Hz>> Wirklich? Da fehlt eher Faktor 10. ODer dein Controller läuft mit dem> internen RC-Oszillator von 1 MHz. AVR Fuses geprüft?
Ich spreche hier nur vom Datentyp. Der Topwert welcher verglichen wird
(250) belibt der selbe.
Falk Brunner schrieb:>>Hat jemand Empfehlungen, wie ich meinen Code auf speed optimieren>>könnte?>> Indem du VOLLSTÄNDIGEN Code als Anhang postest.
Ich bezog mich nur auf meinen PWM Code in sich.
Falk Brunner schrieb:>>Ich würde gerne mehr als nur 8bit PWM haben.>>10bit und mehr wäre mein Ziel.>> Siehe Soft-PWM
Das was ich hier tue ist bereits Soft-PWM.
Aber trozdem Danke für deine Antwort :)
avr schrieb:> * volatile wegmachen (da du den Counter nur in der ISR verwendest)> * counter runterzählen und mit 0 vergleichen> * die drei Leds in einem Portzugriff ausschalten
Das war die Rettung! :)
avr schrieb:> Bei noch mehr Leds würde ich zu BAM greifen.
BAM? Bill at Monday? :)
@Claudio Hediger (hedie)
>> Das ist Prescaler 1/8, sprich 1,25 MHz, macht bei einem 8-Bit Zähler>> 4,88 kHz PWM-Frequenz. Unsinnig hoch.>Das ist nicht korrekt.>Du vergisst meinen TOP Value von 10.>Damit liege ich bei 125Khz und dann zählt er auf 250 was dann>einer PWM Frequenz von 500Hz entspricht!
Hmm, dann hst du aber ebenfalls unsinnige 125 kHz Interruptfrequenz.
Macht bei 10 MHz CPU-Takt gerade mal noch 80 Takte pro ISR. Das ist SEHR
knapp. Siehe Artikel Soft-PWM.
>Ich spreche hier nur vom Datentyp. Der Topwert welcher verglichen wird>(250) belibt der selbe.
Jaja, hab den Waveform Mode übersehen.
>> Indem du VOLLSTÄNDIGEN Code als Anhang postest.>Ich bezog mich nur auf meinen PWM Code in sich.
Ich ebenfalls ;-)
>Das was ich hier tue ist bereits Soft-PWM.
Nur schlecht implementiert.
>> * volatile wegmachen (da du den Counter nur in der ISR verwendest)>> * counter runterzählen und mit 0 vergleichen>> * die drei Leds in einem Portzugriff ausschalten>Das war die Rettung! :)
Nur minimal. Deine CPU dampft immern noch kurz vor der
Überlastungsgrenze.
Claudio Hediger schrieb:> Das war die Rettung! :)
Du bist aber immer ganz hart an der Grenze.
Claudio Hediger schrieb:> TCCR0B |= (1<<CS01);> OCR0A = 10;
Dein Timer zählt bis 80 und löst einen Interrupt aus.
Das bedeutet, du hast 80 Takte, bis der nächste Interrupt kommt.
Dafür ist deine ISR aber viel zu lang. Wenn die fertig ist, steht sofort
wieder das nächste Flag an. Das Hauptprogramm wird dadurch nach nach
jedem
(Assembler-)Befehl unterbrochen. Sozusagen in Einzelschritten
abgearbeitet.
Mit dieser Maßnahme:
Claudio Hediger schrieb:> avr schrieb:>> * volatile wegmachen (da du den Counter nur in der ISR verwendest)>> * counter runterzählen und mit 0 vergleichen>> * die drei Leds in einem Portzugriff ausschalten
hast du dir für den Moment ein paar Takte Luft verschafft. Aber mit 10
Bit wird das nichts.
Wozu 500Hz? 100Hz reichen auch. Da hast du 5x soviel Zeit.
Claudio Hediger schrieb:> Controller: Atmega324PV mit 10MHz
Und ein 324P mit 20MHz verdoppelt die Zeit nochmal.
mfg.
Schau mal in den anderen Thread:
Beitrag "Poti Wert zu PWM Signal verarbeiten"
Da macht jemand das gleiche und ich und andere haben ihm was dazu
geschrieben.
Was Du eigentlich willst, ist, den Timer so zu konfigurieren, dass Du in
OCR0A die Helligkeit der LED schreibst. Der Counter zählt immer von 0
bis 255 durch. Bei 0 wird die LED eingeschaltet (Counter Overflow) und
bei Erreichen von Compare (OCR0A) wieder aus. Das Ein- und Ausschalten
kannst Du entweder in der Overflow- und Compare-Match-ISR machen oder Du
schließt die LED an dem Pin an, der zum Timer gehört. Dann geht das
völlig automatisch ohne Interrupts und ohne Flackern und der
Mikrocontroller kann sinnvollere Dinge tun.
Sehe gerade erst, Du willst eigentlich mehr als 8 Bit PWM. Dann solltest
Du trotzdem einen Hardware-Timer benutzen und Dir mehrere 16-Bit-Timer
in Software erzeugen. Allerdings nicht, indem Du in der Overflow-ISR
immer nur um eins hochzählst. Sonder Du rechnest Dir aus, wie viele
Zyklen es bis zur nächsten Aktion sind und schreibst den Wert ins
Compare-Register. Bei einem 8-Bit-Timer sind dazu möglicherweise erstmal
mehrere Overflows nötig. Aber die erhöhen den Zähler dann gleich um 256.
Die Feinarbeit machst Du mit dem Compare-Register.
xfr schrieb:> Sonder Du rechnest Dir aus, wie viele> Zyklen es bis zur nächsten Aktion sind und schreibst den Wert ins> Compare-Register.
Da ist BAM nun wirklich bei Weitem einfacher.
Bei der intelligenten Softpwm Methode muss man die PWM-Werte sortieren.
Ok bei 3 Werten fällt das noch nicht ins Gewicht. Je mehr Kanäle man
braucht desto eher eignet sich BAM.
Bei 10bit BAM braucht man ein Array mit 10 Werten. Diese werden so
gefüllt, dass man sie in der ISR nur nacheinander ausgeben muss. Bei
einer guten Implementierung ist das auch relativ schnell.
Thomas Eckmann schrieb:> Wozu 500Hz? 100Hz reichen auch. Da hast du 5x soviel Zeit.
Diese 500Hz hatte ich mit einem TopWert von 250
Ich wollte jedoch 1000 folglich faktor 4 mehr und damit sinkt die
Frequenz auf 125Hz.
Thomas Eckmann schrieb:>> Controller: Atmega324PV mit 10MHz> Und ein 324P mit 20MHz verdoppelt die Zeit nochmal.
Habe eben 160 PV's hier. deshalb mache ich das mit denen.
xfr schrieb:> ...Sonder Du rechnest Dir aus, wie viele> Zyklen es bis zur nächsten Aktion sind und schreibst den Wert ins> Compare-Register...
Ich verstehe deine Idee leider nicht ganz.
schnupp schrieb:> Auf was ist denn die code optimierung eingestellt?
Auf Size Optimaizations (-Os)
------------------------------------
Habe nun folgende Anpassungen vorgenommen:
TIMSK0|=(1<<OCIE0A);//Interrupt beim erreichen des TOP wertes
8
}
Damit erreiche ich eine PWM-Frequenz von 62.5Hz.
Und habe beim Timer einen Topwert von 20 was also 160 "übrigen"
Taktzyklen entsprechen würde zwischen jedem Interrupt.
Das restliche Programm wird nun nicht merklich beeinträchtigt und der
PWM sauber erzeugt.
So wie ich gelesen habe, gibt es jetzt nicht die ultimative Lösung für
mich, wie ich meinen PWM eleganter erzeugen könnte.
Wenn ich da etwas falsch verstanden habe, bitte korrigiert mich.
Claudio Hediger schrieb:> So wie ich gelesen habe, gibt es jetzt nicht die ultimative Lösung für> mich, wie ich meinen PWM eleganter erzeugen könnte.> Wenn ich da etwas falsch verstanden habe, bitte korrigiert mich.
Doch, ist hier im Artikel beschrieben:
http://www.mikrocontroller.net/articles/Soft-PWM (unter intelligenter
Lösungsansatz). Ist zugegebenermaßen nicht ganz trivial, aber der Code
steht da ja schon fertig.