Hallo,
Ich verwende einen xMega32A4 um RGB-LEDs zu betreiben. Unter anderem
gibt es einen Modus, der es erlaubt, von Helligkeit A zu Helligkeit B zu
faden. Nun ist mir aufgefallen, dass es während des Fade-Vorganges einen
kleinen "Ruckler" gibt. Da mich dieser stört, bin ich auf Fehlersuche
gegangen - ohne Erfolg. Danach kam mir die Idee, diese Funktionen in
einem eigenen Programm zu probieren. Also hab ich ein kleines
Testprogramm geschrieben, dass nur die PWM initialisiert und im
Hauptprogramm das entsprechende Register erhöht - und siehe da, auch
dort ruckelt es.
Hier ist der Code aus dem Testprogramm:
1
#define F_CPU 32000000UL
2
#include<util/delay.h>
3
4
#include<stdint.h>
5
#include<avr/io.h>
6
#include<avr/interrupt.h>
7
#include<stdlib.h>
8
9
voidclockInit();
10
voidportInit();
11
voidpwmInit();
12
13
/***************************
14
** Hauptprogramm **
15
****************************/
16
intmain()
17
{
18
clockInit();
19
// timerInit();
20
pwmInit();
21
portInit();
22
23
sei();
24
PMIC.CTRL|=(1<<PIN0)|(1<<PIN1)|(1<<PIN2);
25
26
for(;;)
27
{
28
TCE0.CCA--;
29
_delay_us(100);
30
}
31
}
32
33
34
/*********************************
35
** Frequenz einstellen **
36
**********************************/
37
voidclockInit()
38
{
39
//Intern
40
//Oscillator auf 32Mhz einstellen
41
OSC.CTRL|=0x02;
42
//Wenn Oscillator stabil wird das Flag RC32MRDY gesetzt und 32Mhz können benutzt werden
43
while(!(OSC.STATUS&OSC_RC32MRDY_bm));
44
//I/O Protection
45
CCP=0xD8;
46
//Clock auf 32Mhz einstellen
47
CLK.CTRL=0x01;
48
}
49
50
51
/******************************
52
** Ports einstellen **
53
*******************************/
54
voidportInit()
55
{
56
PORTE.DIR|=(1<<PIN0)|(1<<PIN1)|(1<<PIN2);//PWM
57
}
58
59
60
61
/****************************
62
** PWM einstellen **
63
*****************************/
64
voidpwmInit()
65
{
66
TCE0.CTRLB=0xF3;
67
TCE0.PER=65535;
68
TCE0.CTRLA=0x01;
69
70
//Anfangs alles auf 0 stellen
71
TCE0.CCA=65535;
72
TCE0.CCB=65535;
73
TCE0.CCC=65535;
74
}
Ich betreibe den uC mit 32MHz (intern) und verwende eine PWM-Frequenz
von ca. 500Hz. Die PWM hat eine Auflösung von 16bit.
Ist da irgendetwas falsch?
Vielen Dank für eure Hilfe!
mfg
Andy
>Ich betreibe den uC mit 32MHz (intern) und verwende eine PWM-Frequenz>von ca. 500Hz.> TCE0.CCA--;> _delay_us(100);
Und du schreibst mit 10kHz den PWM Wert neu.
Wird wohl ein Schwebungseffekt sein;)
>Das musst du mir bitte genauer erklären...
Wenn du deinen PWM Wert schneller änderst als
die PWM Frequenz ist, was erwartest du dann?
Setz dein delay mal auf 2ms.
Bei deiner PWM, findet da eine Synchronisierung des Neusetzens statt?
Normalerweise wird der neue PWM Wert erst dann übernommen, wenn der
Zähler seinen Maximalen oder Minimalen Wert erreicht hat und nicht
mittendrinn.
Macht das deine PWM Einheit?
>Nachtrag: Auch bei 10ms flackert es.
Könnte es damit zusammenhängen das die nächste Zeile
einen Überlauf verursacht den du nicht abfragst?
>TCE0.CCA -= 50;
Was ist wenn TCE0.CCA = 5 ist und du 50 abziehst?
Was passiert dann? Richtig, du bekommst einen ziemlich
grossen Wert. Das wird wohl dein flackern sein.
@Karl Heinz: Danke für den Tipp - muss ich überprüfen. Aber
programmtechnisch wird nur das gemacht, was du oben siehst.
@Holger: wenn ich z.b. von 5 die 50 abziehe, kommen 65490 raus. Ist aber
für eine 16bit-PWM kein Problem...
So, ich habe jetzt auch sicherheitshalber eine Variable eingebaut und
einen Überlauf verhindert, d.h. ich setze die Werte bei 0 und bei 65535
manuell zurück - ohne Ergebnis, es flackert immer noch.
@Karl Heinz: Wenn der Fehler bei der Synchronisierung liegen würde, dann
müsste es doch beim Dimmen in die andere Richtung auch flackern, oder??
lg
Zur Info:
Habe es soeben geschafft, ein Oszibild aufzunehmen. Hier sieht man, dass
im PWM-Signal einmal ein Aussetzer drinnen ist, der das Flackern
verursacht. Woher kann der kommen??
Nur beim Dimmen in eine Richtung? Der müsste dann doch immer Störungen
verursachen, oder? Und ansonsten hab ich nichts aktiviert, außer dem
Timer für die PWM...
Andy schrieb:> @Karl Heinz: Wenn der Fehler bei der Synchronisierung liegen würde, dann> müsste es doch beim Dimmen in die andere Richtung auch flackern, oder??
Nein.
Sieh im Handbuch nach, wie bei deinem benutzen PWM Modus ganz konkret
der Update des Vergleichsregister gemacht wird. Wenn die Hardware das
nicht erledigt, dann musst du dich um eine Synchronisierung kümmern.
Wie funktioniert denn PWM?
Wenn der Zähler den Überlauf nach 0 macht, wird der Pin eingeschaltet;
wenn der Zählerwert dann irgendwann den Wert in TCE0.CCA erreicht hat,
wird der Pin wieder ausgeschaltet.
Jetzt kann es aber zu folgender Situation kommen:
TCE0.CCA habe den Wert 8
Der Zähler zählt dahin
0 Pin wird eingeschaltet
1
2
3
4
5
6
7
und genau jetzt, in diesem Moment, änderst du TCE0.CCA um auf 7.
der Zähler zählt weiter
8
vorher würde jetzt der Pin ausgeschaltet worden sein, weil ja diese 8
mit dem vorhergehenden Wert von TCE0.CCA (der 8) übereingestimmt hätte.
Aber TCE0.CCA ist ja jetzt 7!
Als folge davon wird der Pin jetzt nicht mehr ausgeschaltet. Der Zähler
muss weiterlaufen, bis 65535, wieder bei 0 anfangen, bis er dann endlich
wieder die 7 erreicht um den Pin abzuschalten.
Folge: -> du hast nicht die PWM-Länge von 8 auf 7 verkürzt, sondern du
hast einen extrem langen Puls erzeugt.
Und damit ist auch klar, dass dieses Problem nur dann auftritt, wenn du
den PWM Wertin TCE0.CCA verkürzt. Verlängern geht immer ohne Probleme.
Wie gesagt: sieh nach, wie der Update dieses Registers gemacht wird, ob
da hardwaremässig etwas vorgesehen ist. Bei den Megas ist es so, dass
ein Update des Vergleichsregister zwar registriert wird, der eigentliche
Update aber erst von der Hardware gemacht wird, wenn der Zähler im
Überlauf zu 0 ist. Damit kann dieses Problem dann nicht mehr auftreten.
@Karl Heinz: Wow, jetzt sage ich nichts mehr. :) Das wirds gewesen sein
- ich weiß zwar noch nicht, wie dieser Update beim XMega funktioniert,
aber das sind genau die Symptome, die ich habe - das Oszi-Bild spricht
auch dafür! Vielen Dank für deine Erläuterung - wenns das war, hast du
mir sehr weitergeholfen...
mfg
Andy
Noch schnell eine Frage: Wenn ich sicher gehen will, dass es nicht
flackert, schreibe ich die Änderung von TCE in den Timer-Interrupt vom
PWM-Timer. Somit wird nur "upgedatet", wenn der PWM-Timer überläuft,
oder??
lg
Andy schrieb:> Noch schnell eine Frage: Wenn ich sicher gehen will, dass es nicht> flackert, schreibe ich die Änderung von TCE in den Timer-Interrupt vom> PWM-Timer. Somit wird nur "upgedatet", wenn der PWM-Timer überläuft,> oder??
Wäre eine Möglichkeit.
Eine andere wäre es, nach dem Setzen des neuen Wertes den aktuellen
Zählerstand zu prüfen und wenn der größer als der neue Wert ist, den Pin
"händisch" abzuschalten.
Das müsste auch umgekehrt gehen: die Prüfung vor dem Setzen machen.
(Ich denke sogar, dass die Prüfung vorher besser wäre, müsste das aber
noch im Detail durchdenken, welche Sonderfälle da auftreten können)
Danke für die Tipps, nur stellt sich mir die Frage, wie ich im
PWM-Betrieb einen Output-Pin setzen kann, ohne über das PWM-Register zu
gehen. Timer kurzzeitig deaktivieren - Output-Pin setzen und Timer
gleich wieder aktivieren geht nicht. Wie könnte ich das noch lösen?
Hinzu kommt noch, dass ich in der wahren Anwendung dann ja drei
PWM-Signale mit dem Timer generiere.
Was mich noch interessieren würde, ist, warum das beim xMega32A4 nicht
so funktioniert, wie beim Mega328p. Bei diesem hatte ich diese Probleme
nicht...
lg
Andy schrieb:> Danke für die Tipps, nur stellt sich mir die Frage, wie ich im> PWM-Betrieb einen Output-Pin setzen kann, ohne über das PWM-Register zu> gehen. Timer kurzzeitig deaktivieren - Output-Pin setzen und Timer> gleich wieder aktivieren geht nicht. Wie könnte ich das noch lösen?
Kann ich dir nicht sagen.
> Was mich noch interessieren würde, ist, warum das beim xMega32A4 nicht> so funktioniert, wie beim Mega328p. Bei diesem hatte ich diese Probleme> nicht...
Von den XMega versteh ich nichts.
Aber bei den normalen Megas wird das wie gesagt insofern synchronisiert,
als ein neuer Wert nicht sofort ins Vergleichsregister übernommen wird,
sondern nur dann, wenn es garantiert sicher ist das zu tun: Wenn der
Zähler gerade in der Overflow Behandlung ist.
Andy schrieb:> Weiß sonst jemand, wie ich das lösen könnte, bzw. ob man da was bei den> xmega-Einstellungen für den Timer machen kann??
Hast Du denn kein Datenblatt des Prozessors? Da sollten doch derlei
Randbedingungen erläutert sein. Oft gibt es auch Application Notes mit
wertvollen Tipps (AVR1306 und AVR1311 fallen da vom Titel her ins Auge).
OK, ich habs: mit CCx wird der neue Wert sofort übernommen, mit CCxBUF
wird der Wert erst bei einem Overflow übernommen. Vielen Dank für eure
Hilfe! Ohne euch wär ich nie draufgekommen...
bis zum nächsten mal!
mfg
Andy
Andy schrieb:> OK, ich habs: mit CCx wird der neue Wert sofort übernommen, mit CCxBUF> wird der Wert erst bei einem Overflow übernommen. Vielen Dank für eure> Hilfe! Ohne euch wär ich nie draufgekommen...
D.h. du bist deine Ruckler los?
(Bis jetzt war das ja von meiner Seite nur Spekulation. Begründete
Spekulation aber eben doch nur Spekulation)