Hallo zusammen,
ich habe eine Frage zu dem Beispiel Software PWM aus dem Forum :
http://www.mikrocontroller.net/articles/Soft-PWM
Meine erste Frage ist eine Verständnis Frage zu der ISR Compare.
Im Datenblatt steht das der Interrupt Vector aufgerufen wird wenn das
TOV1 Flag gesetzt wird also in Normal Mode bei erreichen von MAX Value
des Timer Counters. Hab ich das so richtig verstanden ?
Ich habe nun versucht den intelligenten Lösungsansatz auf einen ATxMega
256A3 zu portieren. Atmel schreibt für ein Output Compare muss der Timer
in normal mode laufen und der Compare Output Enable muss aktiviert
werden.
1
TCC0.CTRLA=TC_CLKSEL_DIV8_gc;// Presacler 8
2
TCC0.CTRLB=0b00010000;// select Modus: Normal; Enable Compare Output A
müsste also so passen oder ?
Hab das ganze dann mal debuggt und das Problem ist nun das die Interrupt
Routine nicht aufgerufen wird.
Hat damit jemand schon Erfahrungen gemacht und kann mir helfen ?
Hab den auf Xmega abgeänderten Code angehängt.
Vielen Dank schonmal
Gruß Stefan
Stefan Friedrich schrieb:> Ich habe nun versucht den intelligenten Lösungsansatz auf einen ATxMega> 256A3 zu portieren.
Das ist dann aber nicht der intelligenteste Lösungsansatz für den
ATXMega der machbar ist.
Wenn du einen DMA Kanal frei hast dann kannst du mit diesem für einen
Timer gleich 4 Output Compare Kanäle eines Timers füttern. Damit läuft
alles in Hardware im Hintergrund ab bis auf den Punkt der Aktualisierung
der Dutycycles per Software. Diese Werte liegen in einem SRAM Array mit
4 Elementen und müssen nur dann überschrieben werden wenn du die
Dutycycles ändern möchtest.
Wenn du statt einem Timer einen 8Bit Port benutzt dann kannst du diesen
ebenfalls per DMA Kanal permanent füttern und jedes beliebige PWM
Bitmuster an diesen 8 Bit Port aus einem SRAM Array ausgeben lassen.
Dann wären dies schon 8 PWMs die mit bis zu 32MHz Frequenz aktualisiert
werden können.
Also: für eine PWM mit 256 Schritten legst du im SRAM ein Array mit 256
Elementen an. Dieses Array wird per DMA + Timer als Taktbasis permanent
in einen Port kopiert. Das geht alles in Hardware ohne Software
Eingriffe. Also ohne CPU Last. Die Bitmuster der Elemente im SRAM Array
definieren deine PWM auf jedem der 8 Pins dieses Ports.
Für die Variante mit Timer + 4 Output Compare Register legst du im SRAM
ein Array auf 4 Elementen an. Der Timer Overflow taktet den DMA per
Event und der DMA kopiert diese 4 Werte in die 4 OC-Register des
gleichen Timers.
Das geht also, bis auf das einmalige Einrichten und Aktualisieren der
Werte, bei diesen Varianten ohne Softwareeingriffe. Die damit
erreichbare CPU Last ist ungleich geringer als die im Artikel
beschriebene Sofft-PWM.
Beide Varianten habe ich schon selbst programmiert und funktionieren
perfekt.
Gruß Hagen
Hagen Re schrieb:> Beide Varianten habe ich schon selbst programmiert und funktionieren> perfekt.
wirklich?
da sich CPU und DMA einen Bus zum Speicher Teilen kann ich mir nicht
vorstellen, dass man da nicht einen ziemlich großen Jitter hat, wenn die
CPU grad viele Speicheruzugriffe hat und die DMA warten muss.
Korrekt, aber bei 32MHz Taktbasis hat man für 256 Schritte genügend
Zeit. Die Timer Variante blockiert den Bus nur 1/(256/4)'tel der Zeit
wie die Port Variante. Das hängt dann von den Anforderungen des OTs ab.
Die wie üblich nicht klar spezifiziert wurden.
Auf alle Fälle ist das Soft-PWM Beispiel nicht die cleverste Wahl für
den XMega. Denn ob nun der DMA transparent im Hintergrund auf das SRAM
zugreift oder es letzendlich über ISRs und Software erfolgt ist egal da
die Datenmengen gleich sein werden.
Gruß hagen
Vlad Tepesch schrieb:> Hagen Re schrieb:>> Beide Varianten habe ich schon selbst programmiert und funktionieren>> perfekt.> wirklich?> da sich CPU und DMA einen Bus zum Speicher Teilen kann ich mir nicht> vorstellen, dass man da nicht einen ziemlich großen Jitter hat, wenn die> CPU grad viele Speicheruzugriffe hat und die DMA warten muss.
Davon abgesehen greift die CPU beim Programablauf viel häufiger auf den
FLASH statt SRAM zu. Und der Bus zum FLASH ist unabhängig vom Datenbus
zum SRAM, eg. hat keinen Einfluß auf das DMA.
Bassti schrieb:> Find die Idee trotzdem gut... man muss ja nicht gleich mit 125 kHz> anfangen...> Paar LEDs Dimmen usw. ...ist ne nette Idee mit dem Port und dem DMA! :)
Wobei man dann im Vergleich zur Timervariante sogar mit der
Maximalfrequenz runter gehen kann. Denn statt mit einer linearen PWM,
wie bei Timern möglich, zu arbeiten kann man bei der Portvariante mit
dem sogenannten Scrambling-PWM arbeiten. Dabei werden die On-Phasen der
LEDs gleichmäßig als Pulse über den kompletten PWM Zyklus verteilt.
Somit kann man die Gesamtfrequenz der PWM reduzieren da sich erst später
ein sichtbares Flackern der LEDs einstellt. Im Vergleich zur normalen
PWM bei der sich nur eine variable On/Off Zeit einstellen lässt.
Nimmt man 2 Ports und 2 DMA Kanäle als Matrix so kann man 256 LEDs
ansteuern.
Unter Umständen könnte man sogar die 4 virtuellen Ports benutzten und
per einem DMA Kanal deren 4*4 Bytes an Konfiguration aus dem SRAM
kopieren. Davon werden zwar nur die 4 OUT register real benötigt aber
man hat so mit einem DMA Kanal gleich 4*8 Bits an PWM.
Gruß hagen
Danke für die Antworten.
Also Anwendung soll PWM auf 8 Kanälen sein, später vielleicht mal 16.
Die PWM Signale sollten an einem (bzw dann zwei) Ports anliegen und
erstmal sollten 8 Bit PWM reichen. (Wobei die 16 Bit ja mit diesem
Ansatz auch schnell nachzurüsten wären)
Der Grund warum ich die Software PWM version weiter verwenden wollte
ist, dass ich das Programm das ich derzeit noch auf einem Atmega 32 am
laufen hatte gerne auf diesem Prozessor weiter verwenden wollte. (Also
die ganzen Funktionsaufrufe und Parameterübergabe nicht großartig
verändern wollt)
Sollte es mit dieser Variante auf dem Xmega nicht funktionieren bleibt
mir wohl nichts anderes übrig aber ich wollte es wenigstens versuchen.
Bis jetzt scheitert es allerdings noch daran das die ISR nicht
aufgerufen wird.
Hagen Re schrieb:> Wenn du statt einem Timer einen 8Bit Port benutzt dann kannst du diesen> ebenfalls per DMA Kanal permanent füttern und jedes beliebige PWM> Bitmuster an diesen 8 Bit Port aus einem SRAM Array ausgeben lassen.> Dann wären dies schon 8 PWMs die mit bis zu 32MHz Frequenz aktualisiert> werden können.>> Also: für eine PWM mit 256 Schritten legst du im SRAM ein Array mit 256> Elementen an. Dieses Array wird per DMA + Timer als Taktbasis permanent> in einen Port kopiert. Das geht alles in Hardware ohne Software> Eingriffe. Also ohne CPU Last. Die Bitmuster der Elemente im SRAM Array> definieren deine PWM auf jedem der 8 Pins dieses Ports.
Ansonsten hört sich diese Lösung sehr interessant an, alledings ist mir
nach lesen des Datenblattes nicht ganz klar wie das zu bewerkstelligen
ist. Mit der Hardware PWM kann man die Signale ja immer nur an maximal 6
von 8 pins pro Port ausgeben.
Und wieso muss das Array 256 Elemente haben ? Angenommen ich wollte nur
eine Sequenz ausgeben von 20% 50% 100% Helligkeit müssten doch 3
Arrayelemte reichen à 8 Bit, oder habe ich das komplett falsch
verstanden ?
Grüße Stefan
Stefan Friedrich schrieb:> Ansonsten hört sich diese Lösung sehr interessant an, alledings ist mir> nach lesen des Datenblattes nicht ganz klar wie das zu bewerkstelligen> ist. Mit der Hardware PWM kann man die Signale ja immer nur an maximal 6> von 8 pins pro Port ausgeben.> Und wieso muss das Array 256 Elemente haben ? Angenommen ich wollte nur> eine Sequenz ausgeben von 20% 50% 100% Helligkeit müssten doch 3> Arrayelemte reichen à 8 Bit, oder habe ich das komplett falsch> verstanden ?
Eine 8 Bit PWM hat 256 verschiedene DutyCycles die einstellbar sind. Das
Array hat also 256 Elemente in denen du für jeden Pin des Ports die
Zustände abspeicherst. Der DMA kopiert dieses Array permanent in den
Port und das mit der gleichen Frequenz mit der normalerweise dein Timer
läuft. Wenn du nun auf Pin 0 vom Port einen DutyCycle von 20% einstellen
möchtest dann muß das unterste Bit aller 256 Bytes im Array zu 20% auf 1
und zu 80% auf 0 gesetzt sein. Man macht also das was der PWM-Timer
autom. macht von Hand.
Wenn du die ATXMegaA?U Serie einsetzen würdest dann gibt es dort den
Timer Modus 2. Damit werden die 4x 16Bit Timer0 eines Ports auf 8x 8Bit
Timer umprogrammiert. Du hast dann auf 8 Pins des Ports 8 PWMs mit 8Bit
Auflösung. Dieses neue Feature ist mir auch erst in den letzten Tagen
aufgefallen und dürfte für dich am passensten sein ;)
Gruß hagen
Hagen Re schrieb:> Eine 8 Bit PWM hat 256 verschiedene DutyCycles die einstellbar sind. Das> Array hat also 256 Elemente in denen du für jeden Pin des Ports die> Zustände abspeicherst. Der DMA kopiert dieses Array permanent in den> Port und das mit der gleichen Frequenz mit der normalerweise dein Timer> läuft. Wenn du nun auf Pin 0 vom Port einen DutyCycle von 20% einstellen> möchtest dann muß das unterste Bit aller 256 Bytes im Array zu 20% auf 1> und zu 80% auf 0 gesetzt sein. Man macht also das was der PWM-Timer> autom. macht von Hand.
Ah ok, jetzt hab ichs verstanden. Dann ist diese Methode für meine
Zwecke wohl doch eher ungeeignet, da ich die duty cycles doch recht oft
ändere bzw in den unterschiedlichen Modi viele verschiedene
Einstellungen verwende.
Da für jeden Schritt/Einstellung 256 Byte zu reservieren wäre wohl zu
viel am Ende.
Da es nicht wirklich so auf die Prozessorauslastung ankommt und ich mit
1-2% Auslastung für die PWM durchaus leben kann werde ich weiter
versuchen die Routine aus dem Forum zu portieren.
Danke trotzdem für die Antworten :)
Gruß Stefan
Hello again...
hab nun nochmal die Beispiele von Atmel angeschaut und das Xmega Manual
mehrmals durchgelesen, also die Abschnitte Timer Counter und Interrupts,
aber bin immernoch ratlos.
Ich habe es zwar geschafft das er mitlerweile einmal den CCA Interrupt
aufruft, jedoch nur einmal. Obwohl in der ISR der Compare Wert ja immer
upgedatet wird.
Hab ich den Timer falsch konfiguriert? Oder geht das mit dem
Outputcompare anders ?
Kann mir jemand einen Tipp geben ?
Grüße Stefan
EDIT: Was die Fehlersuche bzw das debuggen so schwer macht ist das
einige Variablen wegoptimiert werden beim Kompilieren, zumindest sagt
das AVR Studio.
Hallo Hagen,
könntest du deine DMA PWM Lösung posten?
... bzw wie muss ich den Timer beim Xmega einstellen, dass ich die
Lösung aus dem Forum verwenden kann.
(http://www.mikrocontroller.net/articles/Soft-PWM)
Ich habe es soeben schon versucht, aber irgendwie funktioniert es nicht.
Guten Morgen,
probiere es mal mit dieser Timerkonfiguration:
1
voidtimer_init(void){
2
// Compare Interrupts A,B,C,D aktivieren High
3
TCC1.INTCTRLB=TC_CCAINTLVL_HI_gc;
4
TCC1.CTRLA=TC_CLKSEL_DIV8_gc;
5
TCC1.PER=65535;
6
}
Hatte zumindest mit einem ähnlichen Code schon mal eine funktionierende
Variante....
Hatte den intelligenten Ansatz vom Forum schon mal verwendet. Welchen
Controller verwendest du?
Gruß Flo