Forum: Mikrocontroller und Digitale Elektronik Problem mit PWM-Signal


von Andy (Gast)


Lesenswert?

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
void clockInit();
10
void portInit();
11
void pwmInit();
12
13
/***************************
14
**      Hauptprogramm     **
15
****************************/
16
int main()
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
void clockInit()
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
void portInit()
55
{
56
  PORTE.DIR |= (1<<PIN0)|(1<<PIN1)|(1<<PIN2);     //PWM
57
}
58
59
60
61
/****************************
62
**      PWM einstellen     **
63
*****************************/
64
void pwmInit()
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

von holger (Gast)


Lesenswert?

>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;)

von Andy (Gast)


Lesenswert?

Das musst du mir bitte genauer erklären...

von holger (Gast)


Lesenswert?

>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.

von Andy (Gast)


Lesenswert?

Hallo,
Hab jetzt folgendes in die main-Schleife gesetzt:
1
    for(;;)
2
    {
3
        TCE0.CCA -= 50;
4
        _delay_ms(3);
5
    }

einmal mit 1ms und einmal mit 3ms.
Flackern tritt bei beiden auf - mir kommt aber vor, dass es bei 3ms 
nicht mehr so oft auftritt.

Was kann das sein??

von Andy (Gast)


Lesenswert?

Nachtrag: Auch bei 10ms flackert es.

von Andy (Gast)


Lesenswert?

Nochmal Nachtrag: wenn ich die Dimmrichtung umdrehe, flackert es auch 
nicht...
Was geht da ab??

von Karl H. (kbuchegg)


Lesenswert?

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?

von holger (Gast)


Lesenswert?

>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.

von Andy (Gast)


Lesenswert?

@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...

von Andy (Gast)


Lesenswert?

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

von Andy (Gast)


Angehängte Dateien:

Lesenswert?

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??

von Michael R. (mexman) Benutzerseite


Lesenswert?

> Woher kann der kommen??

Vielleicht schlaegt da der Watchdog oder ein anderer Interrupt zu!?


Gruss

Michael

von Andy (Gast)


Lesenswert?

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...

von Karl H. (kbuchegg)


Lesenswert?

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.

von Andy (Gast)


Lesenswert?

@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

von Andy (Gast)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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)

von Andy (Gast)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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.

von Andy (Gast)


Lesenswert?

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??
Wäre echt dringend...

lg

von Stefan W. (wswbln)


Lesenswert?

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).

von Andy (Gast)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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)

von Andy (Gast)


Lesenswert?

Ja, der Ruckler ist weg - es war genau der Effekt, den du vermutet 
hast... :)
Besten Dank!

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
Noch kein Account? Hier anmelden.