Hallo Forum,
ich habe ein Problem mit der PWM des ATSAMD20J18A auf dem Board von
Microchip (Atmel) SAMD20-XPRO. Das Programmbeispiel habe ich aus einer
Elektor-Zeitschrift entnommen. Das Programm macht erstmal was es soll,
dennoch zeigen sich regelmäßig Überlagerungen im PWM-Verlauf (siehe
Anhang). Leider übersteigt der Fehler meinen derzeitigen Kenntnisstand.
Kann jemand helfen? Die LEDs sind an PB02 und PB03
1
#include<asf.h>
2
3
volatileuint16_ti;//declarations of the variables
4
volatileuint16_tc0value=65535;
5
volatileuint16_tc1value=0;
6
7
voidconfigure_tc(void);//function prototype
8
9
structtc_moduletc_instance;//generate a instance-structure
Ohne jetzt die Timer des SAMD20 zu kennen, vermute ich, dass durch dein
wildes Rumgeballere auf das Compare-Register (mit 50kHz, 20µs) der Timer
ab und zu keinen Match macht (z.B. während der Timer hochzählt, setzt du
das Compare-Register auf eine kleineren Wert) und dann für diese Periode
der Ausgang nicht abgeschaltet wird.
Leider lag es nicht daran. Es sieht aus, als wenn ein Interrupt- oder
Event-Ereignis dazwischen funkt. Ist doch aber alles im Grundzustand
abgeschaltet ?!
Bernd E. schrieb:> Leider lag es nicht daran. Es sieht aus
Wir sehen Deinen Source Code nicht. Vermutlich schreibst Du immer nocht
eines der Capture Register zum falschen Zeitpunkt.
Übrigens mache ich sowas gerne mit DMA...
Jim M. schrieb:> Übrigens mache ich sowas gerne mit DMA...
Alternativ (so habe ich es in der avr-libc im einfachsten Beispiel
mal gemacht): man aktualisiert den PWM-Wert immer nur dann, wenn
gerade ein Timerinterrupt durch ist, d.h. der aktuelle Zyklus eben
begonnen hat.
Jim M. schrieb:> Bernd E. schrieb:>> Leider lag es nicht daran. Es sieht aus>> Wir sehen Deinen Source Code nicht. Vermutlich schreibst Du immer nocht> eines der Capture Register zum falschen Zeitpunkt.>> Übrigens mache ich sowas gerne mit DMA...
Leider nicht ganz weg. LED an PB3 sieht gut aus, oder Fehler ist
verdeckt.
LED an PB2 hat immer noch den beschriebenen Fehler.
1
#include<asf.h>
2
3
volatileuint16_ti;//declarations of the variables
4
volatileuint16_tc0value=65535;
5
volatileuint16_tc1value=0;
6
7
voidconfigure_tc(void);//function prototype
8
9
structtc_moduletc_instance;//generate a instance-structure
Wenn bisheriger PWM-Wert gleich 0, dann direkt setzen, ansonsten Wert
merken und den Match or Capture Channel Interrupt setzen (INTENSET->MC1
oder MC0, je nach verwendetem Kanal). Im richtigen Interrupt (INTFLAG
abfragen nach Kanal) dann den Interrupt löschen und wieder abschalten,
zum Schluss den gemerkten Wert setzen. Register-Synchronisierung nicht
vergessen (STATUS->SYNCBUSY), falls nötig.
Damit wird ein neuer Wert immer nur gesetzt, wenn der aktuelle gerade
erreicht wurde und der Zähler von vorne beginnt. Bei sehr hoher
PWM-Frequenz und niedrigem Wert könnte es zum gleichen Effekt kommen,
wenn der Code im Interrupt den neuen Wert nicht rechtzeitig setzen kann
(PWM läuft ja weiter), von daher den Wert möglichst früh setzen.
Danke für die Antworten. Ich merke schon, da fehlt mir noch einiges an
Hintergrundwissen über die Timer der SAMs. Ich dachte, dass es auch ohne
Interrupts geht. Nun fehlen mir die passenden Beispiele zum Timer.
Bernd E. schrieb:> Ich dachte, dass es auch ohne Interrupts geht.
Interrupts sind etwas sehr Essenzielles bei einem Mikrocontroller. Mit
ihnen musst du dich so oder so vertraut machen.