www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Problem mit PWM-Signal


Autor: Andy (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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:
#define  F_CPU 32000000UL
#include <util/delay.h>

#include <stdint.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdlib.h>

void clockInit();
void portInit();
void pwmInit();

/***************************
**      Hauptprogramm     **
****************************/
int main()
{
    clockInit();
//    timerInit();
    pwmInit();
    portInit();

    sei();
    PMIC.CTRL |= (1<<PIN0) | (1<<PIN1)|(1<<PIN2);

    for(;;)
    {
        TCE0.CCA--;
        _delay_us(100);
    }
}


/*********************************
**      Frequenz einstellen     **
**********************************/
void clockInit()
{
    //Intern
  //Oscillator auf 32Mhz einstellen
    OSC.CTRL |= 0x02;
    //Wenn Oscillator stabil wird das Flag RC32MRDY gesetzt und 32Mhz können benutzt werden
    while(!(OSC.STATUS & OSC_RC32MRDY_bm));
    //I/O Protection
    CCP = 0xD8;
    //Clock auf 32Mhz einstellen
    CLK.CTRL = 0x01;
}


/******************************
**      Ports einstellen     **
*******************************/
void portInit()
{
  PORTE.DIR |= (1<<PIN0)|(1<<PIN1)|(1<<PIN2);     //PWM
}



/****************************
**      PWM einstellen     **
*****************************/
void pwmInit()
{
    TCE0.CTRLB = 0xF3;
    TCE0.PER = 65535;
    TCE0.CTRLA = 0x01;

    //Anfangs alles auf 0 stellen
    TCE0.CCA = 65535;
    TCE0.CCB = 65535;
    TCE0.CCC = 65535;
}

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

Autor: holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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;)

Autor: Andy (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das musst du mir bitte genauer erklären...

Autor: holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Andy (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
Hab jetzt folgendes in die main-Schleife gesetzt:
    for(;;)
    {
        TCE0.CCA -= 50;
        _delay_ms(3);
    }

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

Autor: Andy (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nachtrag: Auch bei 10ms flackert es.

Autor: Andy (Gast)
Datum:

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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Andy (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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...

Autor: Andy (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Andy (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht 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??

Autor: Michael Roek (mexman) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Woher kann der kommen??

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


Gruss

Michael

Autor: Andy (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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...

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Andy (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Andy (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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)

Autor: Andy (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Andy (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Stefan Wimmer (wswbln)
Datum:

Bewertung
0 lesenswert
nicht 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).

Autor: Andy (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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)

Autor: Andy (Gast)
Datum:

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

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.