Hi, da mich das Stocken an meiner Soft-PWM ein erheblichen Schönheitsfehler darstellt möchte ich der Sache mal auf den Grund gehen. Beitrag "Re: 8-Bit Software PWM für mehr als 8 Kanäle" Wenn ich in der while-schleife in der main bei _delay_ms(); eine Wartezeit von 10 Millisekunden eintrage, dann stockt die ganze PWM ziemlich. Ob das ganze regelmäßig ist oder nicht kann ich leider nicht ganz erkennen. Jedenfalls scheint sie da mehrere Takte lang auszusetzen. Bei 9ms oder 8ms geht es komischerweise wieder. Unterhalb der 8ms wieder nicht. Ich verstehe nun leider nicht warum. Die pwm_update() Funktion setzt das pwm_change flag zu Beginn erstmal auf 0 um zu verhindern, dass die COMPB-ISR die neuen Daten übernimmt während sie gerade zusammengestellt werden. Nachdem die Daten fertig sind wird das pwm_change Flag wieder auf 1 gesetzt um der COMPB-ISR am Ende des Zyklus zu signalisieren dass die neuen Daten bereit stehen. Dann können die Zeiger getauscht werden. Die PWM läuft mit 122,5Hz. Eigentlich sollte es völlig egal sein wie oft/schnell nun die PWMdaten geupdated werden. Sie dürfen nur nicht geupdated werden während die Zeiger gerade getauscht werden, andersrum dürfen die Zeiger nicht getauscht werden während die PWMdaten geupdated werden. Letzteres wird dadurch verhindert, dass pwm_change während der Ausführzeit von pwm_update() auf 0 ist, vorletzeres dadurch, dass pwm_update() während die ISR läuft nicht ausgeführt werden kann. Daher versteh ich nicht warum das flackert, und schon garnicht, warum es bei <5..6..7 und bei 10ms flackert, jedoch bei 8ms und 9ms nicht. Dass das ganze lückend läuft sobald die Update-Frequenz größer ist als die PWM-Frequenz ist klar, aber das sollte nicht bemerkbar sein. Das stocken ist richtig deutlich zu erkennen. Seltsamerweise bessert sich das Stocken sobald ich die COMPB-ISR etwas verkürze indem ich z.b. die Negationen bei PORTB &= ~ptr_PORTB_isr[pwm_cycle]; PORTC &= ~ptr_PORTC_isr[pwm_cycle]; PORTD &= ~ptr_PORTD_isr[pwm_cycle]; in die pwm_update Funktion auslagere. Erkennt da jemand einen Zusammenhang? lg PoWl
@ Paul Hamacher (powl) Warum nimmst du nicht den Code aus dem Tutorial und erweiterst ihn auf mehr Kanäle? Du erfindest das Fahhrad neu, allerdings mit eckigen Rädern. Deine PWM Generatorroutine scheint mir ein wenig zu einfach. Ob die wirklich korrekt läuft? Mit allen möglichen PWM-Kombinationen? Und warum tauschst du die Zeiger in der ISR? Dort ist es vollkommen fehl am Platz. Geh mal davon aus, dass der Autor des Tutorials sich was dabei gedacht hat . . . ;-) MFG Falk
Ich erfinde gern hin und wieder mal das Rad neu um was dabei zu lernen, noch mehr wie als wenn ich alles übernehme und ein paar mal drüberschaue. Die Zeiger tausche ich in der ISR.. ja, nun.. warum nicht? Abgesehen davon dass dadurch die ISR etwas länger wird. Die Zeiger sollen pünktlich getauscht werden. Und zwar in der Zeit von der letzten COMPB-ISR bis zur nächsten COMPA-ISR, damit der neue PWM-Zyklus gleich mit den neuen Daten arbeiten kann. Daher verstehe ich auch nicht warum das mit der Updatefrequenz zusammenhängt. Irgendwann stehen eben neue Daten für die ISR bereit und die Zeiger werden getauscht. Oder habe ich hier einen solchen Fall, dass die pwm_update() Funktion und die COMPB-ISR sich oftmals überschneiden während pwm_changed gerade 0 ist und eine Zeit lang nebenherlaufen wodurch dieses Stocken entsteht? Und ja, die PWM funktioniert prima, mit allen möglichen Kombinationen, wieso scheint sie zu einfach? Ich habe alle fälle bedacht und das schon mehrfach getestet. Bei der Demo sind fast alle Werte von 0 bis 255 mehrfach dabei und die Leucht-Welle läuft zuverlässig durch die 22 LEDs hindurch. Ich werde jetzt mal meinen Code mit dem aus dem Tutorial vergleichen. lg PoWl
push Noch eine Frage zur PWM im Soft-PWM Artikel. Wieso soll es so wichtig sein, dass die Zeiger außerhalb der ISR getauscht werden? In beiden Fällen läuft im Hauptprogramm hin und wieder die pwm_update() Funktion. Um die Zeiger zu tauschen muss die Funktion nun die tmp-Zeiger fertig befüllt haben UND der letzte PWM-Zyklus muss durchgelaufen sein. In meiner Version tauscht die ISR dann selbstständig die Zeiger und blockiert sich selbst für diese Zeit, d.h. wenn das zu lange dauert wird ein Zyklus ausgesetzt (was in jedem Fall wohl zu Flimmern führen wird). Im Soft-PWM Artikel wird ISR durch cli() im Hauptprogramm blockiert und dort werden dann die Zeiger getauscht. Im Endeffekt kommt das aber aufs gleiche hinaus -> die ISR kann nicht weiterlaufen während die Zeiger getauscht werden. Letzere Methode hat meiner Meinung noch auch den Nachteil, dass das Hauptprogramm auf die Synchronisation warten muss, in meiner Version kann es schon mit irgendwas anderem weiterarbeiten während die ISR selbstständig auf den Zeigertausch wartet. Lieg ich da falsch? lg PoWl
@ Paul Hamacher (powl) >Noch eine Frage zur PWM im Soft-PWM Artikel. Wieso soll es so wichtig >sein, dass die Zeiger außerhalb der ISR getauscht werden? Kann man auch in der ISR machen, das wird aber ggf. komplizierter. >Nachteil, dass das Hauptprogramm auf die Synchronisation warten muss, in Synchronisiert werden muss auf alle Fälle. Ob man das ggf. auch ohne Warten machen kann, ist eine andere Frage. Man könnte z.B. die neuen Zeiger in Variablen schreiben und in einer weiteren Variable ein Flag setzen. Die ISR erkennt dies und tauscht dann selber die Zeiger. So muss weder die ISR noch das Hauptprogramm warten. Allerdings muss dann die update-Funktion sicherstellen, dass sie VOR dem wiederbeschreiben der Puffer und Zeiger prüft, ob das letzte Update schon übernommen wurde. Das kann bei hohen Updatefreqeunzen zu Wartezeiten führen. Damit hat man an der Stelle am Ende wenig gewonnen. MFG Falk
Synchronisieren tu ich ja. Die pwm_update()-Funktion setzt, nachdem sie fertig ist, das pwm_change Flag auf 1. Dadurch wird der ISR wenn der letzte PWM-Schritt durchlaufen wurde, dass nun die Zeiger getauscht werden können. Allerdings bleibt das Hauptprogramm währenddessen nicht in der pwm_update()-Funktion hängen sondern kann sich mit etwas anderem beschäftigen. Die ISR weiß dann beim nächsten mal, dass sie die Zeiger tauschen darf. Am Anfang der pwm_update()-Funktion wird das pwm_change Flag wieder auf 0 gesetzt. Falls die ISR bis dahin die Zeiger noch nicht getauscht hat, hat sie halt pech gehabt und muss bis zum nächsten Tausch warten. Das wird sich nur als störend bemerkbar machen wenn die Updatefrequenz in der Nähe der PWMfrequenz liegt. Dann kann es sein, dass es eine Weile lang immer wieder auftritt, dass die pwm_update()-Funktion gerade die neuen Daten bereitstellt während die ISR noch läuft. Im letzten PWM-Schritt sind die Daten dann noch nicht fertig und die ISR verpasst das Update. Einige Zeit später wenn die ISR wieder kurz vorm Ende steht, wird wieder die pwm_update()-Funktion aufgerufen. Diesmal zwar etwas früher, aber es kommt trotzdem wieder dazu, dass die neuen Daten noch nicht fertig sind und die ISR das Update verpasst. Das geht dann eine ganze Weile so, bis die Verschiebung wieder so gering ist, dass es passt. Sowas ist natürlich schlecht. Ließe sich eventuell nur mit einem intelligenteren Buffering lösen.
1 | ISR(TIMER1_COMPB_vect) |
2 | {
|
3 | pwm_cycle++; |
4 | |
5 | PORTB &= ~ptr_PORTB_isr[pwm_cycle]; |
6 | PORTC &= ~ptr_PORTC_isr[pwm_cycle]; |
7 | PORTD &= ~ptr_PORTD_isr[pwm_cycle]; |
8 | |
9 | if(ptr_timing_isr[pwm_cycle] != 0) |
10 | {
|
11 | OCR1B = ptr_timing_isr[pwm_cycle]; |
12 | }
|
13 | else if(pwm_change) // <-- Syncronisation! |
14 | {
|
15 | pwm_change = 0; |
16 | |
17 | [Zeiger tauschen] |
18 | }
|
19 | }
|
Übrigens rührt die Einfachheit meines Codes daher, dass meine Soft-PWM im Prinzip einfacher funktioniert. Die Soft-PWM aus dem µC.net Artikel verwendet beim Timer einen niedrigen Prescaler aber nutzt die 16-Bit Compare Register besser aus, um eine exakt bestimmbare PWM-Frequenz zuzulassen. Meine hat ihre festen 122Hz wobei ich das Prinzip aus dem Soft-PWM Artikel besser finde. Werde ich mich auch mal mit beschäftigen. lg PoWl
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.