Forum: Mikrocontroller und Digitale Elektronik AVR WGM Modus 11


von Benjamin K. (exs)


Lesenswert?

Hi,

ich sitze gerade an einem Projekt bei dem ich einen Schrittmotortreiber 
mittels PWM ansteuern möchte.

Dazu habe ich verschiedene Modi des Timer 1 eines AT90USB162 
ausprobiert. Bisher ist es mir allerdings nur gelungen den Modus 15 
(fast PWM) zum Laufen zu bekommen. Nach dem ich das Datenblatt nochmal 
genau gelesen habe, erscheint mit der Modus 11 für meine Zwecke 
sinnvoller.

Folgende Einstellungen habe ich vorgenommen
1
/**
2
 * setup TOP value
3
 */
4
ldi    r16,0x01
5
sts    OCR1AH,r16
6
ldi    r16,0x00
7
8
/**
9
 * WGM-mode 11, phase correct PWM
10
 * set PIN C6 on upcounting, clear on downcounting
11
 *
12
 * TCCR1A  = COM1A1 | COM1A0 | COM1B1 | COM1B0 | COM1C1 | COM1C0 | WGM11 | WGM10
13
 * 0x83    =    1   |    0   |    0   |    0   |    0   |    0   |   1   |   1
14
 */
15
ldi    r16,((1 << COM1A1) | (1 << WGM11) | (1 << WGM10))
16
sts    
17
18
/**
19
 * enable interrupt on compare match A
20
 *
21
 * TIMSK1  = - | - | ICIE1 | - | OCIE1C | OCIE1B | OCIE1A | TOIE1
22
 * 0x03    = 0 | 0 |   0   | 0 |    0   |    0   |    1   |   1
23
 */
24
ldi    r16,((1 << OCIE1A) | (1 << TOIE1))
25
sts    TIMSK1,r16,r16
26
27
/**
28
 * OC1A as output (PIN C6, output) 
29
 *
30
 * DDRC    = DDC7 | DDC6 | DDC5 | DDC4 | DDC3 | DDC2 | DDC1 | DDC0
31
 * 0x??    =   -  |   1  |   -  |   -  |   -  |   -  |   -  |   -
32
 */
33
in    r16,DDRC
34
ori    r16,(1 << DDC6)
35
out    DDRC,r16
36
37
/**
38
 * WGM-mode 11, phase correct PWM
39
 * start PWM right now
40
 *
41
 * TCCR1B   = ICNC1 | ICES1 | - | WGM13 | WGM12 | CS12 | CS11 | CS10
42
 * 0x11    =   0   |   0   | 0 |   1   |   0   |   0  |   0  |   1
43
 */
44
ldi    r16,((1 << WGM13) | (1 << CS10))
45
sts    TCCR1B,r16

Wenn ich das richtig verstanden habe, dann sollte der Timer1 von 0x0000 
(BOTTOM) bis zu dem von OCR1A gegebenen Wert zählen. Dabei sollte PIN C6 
HIGH sein. Wird OCR1A (TOP) erreicht, dann sollte PIN C6 LOW werden und 
der Timer sollte rückwärts auf 0x0000 zählen.

Bei erreichen des TOP-Wertes kann der Compare Match A Interrupt 
ausgelöst werden. Bei erreichen des BOTTOM-Wertes kann der Timer1 
Overflow ausgelöst werden. Beide Interrupts bräuchte ich für mein 
Programm.

Ich habe ein Oszi an den Pin angeschlossen und festgestellt, dass der 
PIN C6 lediglich HIGH-Pegel hat. Ändere ich
1
/**
2
 * WGM-mode 11, phase correct PWM
3
 * set PIN C6 on upcounting, clear on downcounting
4
 *
5
 * TCCR1A  = COM1A1 | COM1A0 | COM1B1 | COM1B0 | COM1C1 | COM1C0 | WGM11 | WGM10
6
 * 0x83    =    1   |    0   |    0   |    0   |    0   |    0   |   1   |   1
7
 */
8
ldi    r16,((1 << COM1A1) | (1 << WGM11) | (1 << WGM10))
9
sts

zu
1
/**
2
 * WGM-mode 11, phase correct PWM
3
 * toggle PIN C6
4
 *
5
 * TCCR1A  = COM1A1 | COM1A0 | COM1B1 | COM1B0 | COM1C1 | COM1C0 | WGM11 | WGM10
6
 * 0x43    =    0   |    1   |    0   |    0   |    0   |    0   |   1   |   1
7
 */
8
ldi    r16,((1 << COM1A0) | (1 << WGM11) | (1 << WGM10))
9
sts

dann funktioniert die PWM. Allerdings nicht mit der angedachten 
Frequenz, aber immerhin mit einem Tastverhältnis von 1:1.

Habe ich da etwas falsch verstanden? Wie sollte der WGM Modus 11 denn 
sonst funktionieren?

Hat jemand schonmal diesen Modus genutzt?

von spess53 (Gast)


Lesenswert?

Hi

OCR1A ist dein Top-Register (Wert, bis zu dem der Timer zählt). Damit 
bleiben für PWM nur die Kanäle B und C.

MfG Spess

von Benjamin K. (Gast)


Lesenswert?

Wozu gibt es dann die Optionen aus Tabelle 15-3 auf Seite 130 des 
Handbuchs?

"Clear OCnA/OCnB/OCnC on compare match up-counting. Set OCnA/OCnB/OCnC 
on compare match when downcounting"

bzw. invers, also setzen bei compare match beim hochzählen (sprich 
BOTTOM matched -> Timer Overflow Interrupt wird ausgelöst -> Pin wird 
gesetzt) und rücksetzen bei compare match (sprich TOP matched -> Compare 
Match A Interrupt wird ausgelöst -> Pin wird zurückgesetzt) beim 
runterzählen.

Hast du das mal ausprobiert?

Ich habe beide Interrupt, also Timer Overflow und Compare Match A 
aktiviert. Habe Breakpoints in beiden Interruptroutinen gesetzt und weiß 
daher, dass Timer Overflow direkt beim starten ausgelöst wird, was ja 
Sinn macht, da TCNT1 am Anfang 0 enthält und somit BOTTOM matched.

Leider scheint das Debugging beim AVR Studio 5 noch nicht richtig 
ausgereift zu sein. Setze ich in beiden InterruptHandlern einen 
Breakpoint, dann wird immer nur einer angesprungen. Lösche einen 
beliebigen, wird der noch vorhandene angesprungen ...

Also nochmal für mich zum richtigen Verständnis:

Phase-correct PWM im Modus 11 bedeutet laut Datenblatt, dass der Timer 
von 0x0000 bis zum Wert in OCR1A hochzählt. Der Wert in OCR1A muss 
mindestens 0x0003 betragen. Hat er den Wert erreicht, dann wird der 
Compare Match A Interrupt ausgelöst und der Timer zählt rückwärts bis 
0x0000. Dort angekommen wird der Timer Overflow Interrupt ausgelöst und 
das Spiel beginnt von vorne.

Über COM1A1 und COM1A0 kann ich wählen ob der PIN C6 bei jedem Match 
toggeln soll, oder ob er beim hochählen gesetzt und beim runterzählen 
rückgesetzt werden soll bzw. eine dazu inverse Einstellung.

Soweit OK oder Einwände? Falls dies nicht richtig ist, dann wäre es nett 
wenn mich jemand erleuchten könnte. Ich würde gerne beim Höchzählen 
setzen und beim runterzählen rücksetzen. Wenn das wirklich so nicht 
funktionieren sollte, dann werde ich versuchen mit der normalen Port 
operation zu arbeiten und den PIN händisch in den entsprechenden 
Interruptroutinen setzen.

Schonmal Danke im  vorraus.

Gruß
Benny

von Karl H. (kbuchegg)


Lesenswert?

Benjamin K. schrieb:
> Hi,
>
> ich sitze gerade an einem Projekt bei dem ich einen Schrittmotortreiber
> mittels PWM ansteuern möchte.

Wozu brauchst du da einen PWM Modus?

CTC Modus mit Pin toggeln und die Sache ist gegessen. Alles was du 
willst ist eine variable Frequenz.

von spess53 (Gast)


Lesenswert?

Hi

>Wozu gibt es dann die Optionen aus Tabelle 15-3 auf Seite 130 des
>Handbuchs?

Es gibt ja noch andere PWM-Modes, bei denen OCR0A nicht als Top 
fungiert. OCR0A kann nur eine Funktion übernehmen, entweder als 
Compare-Register oder als TOP-Register. Bei Mode 10 kannst du auch OCR0A 
als Compare-Register verwenden.

>Leider scheint das Debugging beim AVR Studio 5 noch nicht richtig
>ausgereift zu sein. Setze ich in beiden InterruptHandlern einen
>Breakpoint, dann wird immer nur einer angesprungen. Lösche einen
>beliebigen, wird der noch vorhandene angesprungen ...

Ist bekannt. Der Simulator funktioniert bei PWM-Modes mit variablen Top 
nicht. Steht auch, wenn ich mich nicht irre, in den 'Known Issues' vom 
Simulator.

>Über COM1A1 und COM1A0 kann ich wählen ob der PIN C6 bei jedem Match
>toggeln soll, oder ob er beim hochählen gesetzt und beim runterzählen
>rückgesetzt werden soll bzw. eine dazu inverse Einstellung.

Beim togglen bekommst du im Mode 11 eine CTC und beim Rest entweder L 
oder H. Aber in keinem Fall eine PWM.

MfG Spess

von Benjamin K. (Gast)


Lesenswert?

Moin,

ich nutze den Simulator nicht, sondern bin mit einem JTAG MK2 auf dem 
Controller via DebugWire unterwegs. Im übrigen, kann der Simulator 
anscheinend einen AT90USB162 nicht simulieren.

Wieso OCR0A? Ich möchte Timer1 nutzen, wenn dann ist das OCR1A.

OK ich blick es nicht. Das mit Mode 11 und CTC steht in Handbuch anders 
...

CTC ist da in Tabelle 15-4 auf Seite 131 entweder Mode 4 oder Mode 12. 
In letzterem ist ICR1 dann TOP. Klar dass ich dann OCR1A als Compare 
nutzen kann. Der Timer läuft dann von BOTTOM bis zum Wert in ICR1 und 
wenn er unterwegs OCR1A matched wird der Pin geschaltet. Anschließend 
beim runterzählen und erneutem matchen von OCR1A wird der Pin wieder 
geschaltet. Tastverhältnis ist dann nur 1:1 wenn die Werte in ICR1 und 
OCR1A geschickt gewählt werden ...

Also meine Frage lautet: Wie funktioniert der Phase Correct PWM Mode? 
Wie kann dieser eingeschaltet werden und was macht OC1A dabei?

Ich weiß dass es andere Modi gibt, die für meine Anwendung auch 
missbraucht werden können. Ich könnte mir auch eine Karte kaufen die 
bereits alles mit einem Schrittmotor macht was ich will ... Dann weiß 
ich aber immer noch nicht wieso der Phase Correct PWM Modus bei meinem 
AVR nicht funktioniert, bzw. wo mein Fehler liegt ...

von spess53 (Gast)


Lesenswert?

Hi

>Ich weiß dass es andere Modi gibt, die für meine Anwendung auch
>missbraucht werden können. Ich könnte mir auch eine Karte kaufen die
>bereits alles mit einem Schrittmotor macht was ich will ...

Wieso kommt jetzt ein Schrittmotor ins Spiel?

MfG Spess

von Karl H. (kbuchegg)


Lesenswert?

spess53 schrieb:
> Hi
>
>>Ich weiß dass es andere Modi gibt, die für meine Anwendung auch
>>missbraucht werden können. Ich könnte mir auch eine Karte kaufen die
>>bereits alles mit einem Schrittmotor macht was ich will ...
>
> Wieso kommt jetzt ein Schrittmotor ins Spiel?

War es schon immer. :-)

und genau darum ist mir unklar, was da ein PWM Modus überhaupt soll.

Im speziellen bin ich der Meinung, dass der phase-correct Modus sowieso 
überbewertet wird. Sinn macht der IMHO nur dann, wenn bestimmte 
Phasenbeziehungen zwischen mehreren Timern eingehalten werden müssen. 
Ein Fall, den man eher selten hat.

Eine PWM dazu zu benutzen um eine variable Frequenz mit einem PP von 1:1 
zu erzugen ist meiner Meinung nach pervers. Dazu war PWM nie gedacht und 
man muss höllisch aufpassen, was denn nun genau passiert, wenn der 
Compare Wert  identisch mit dem Top-Wert ist.


> sts    TIMSK1,r16,r16

Was macht der Assembler hiermit?

und hiermit?

> ldi    r16,((1 << COM1A1) | (1 << WGM11) | (1 << WGM10))
> sts

von Benjamin K. (Gast)


Lesenswert?

Sorry muss beim kopieren schiefgegangen sein. Ist mir garnicht 
aufgefallen ...

Hier die korrigierte Version:
1
/**
2
 * setup TOP value
3
 */
4
ldi    r16,0x01
5
sts    OCR1AH,r16
6
ldi    r16,0x00
7
8
/**
9
 * WGM-mode 11, phase correct PWM
10
 * set PIN C6 on upcounting, clear on downcounting
11
 *
12
 * TCCR1A  = COM1A1 | COM1A0 | COM1B1 | COM1B0 | COM1C1 | COM1C0 | WGM11 | WGM10
13
 * 0x83    =    1   |    0   |    0   |    0   |    0   |    0   |   1   |   1
14
 */
15
ldi    r16,((1 << COM1A1) | (1 << WGM11) | (1 << WGM10))
16
sts    TCCR1A,r16
17
18
/**
19
 * enable interrupt on compare match A
20
 * enable timer overflow interrupt
21
 *
22
 * TIMSK1  = - | - | ICIE1 | - | OCIE1C | OCIE1B | OCIE1A | TOIE1
23
 * 0x03    = 0 | 0 |   0   | 0 |    0   |    0   |    1   |   1
24
 */
25
ldi    r16,((1 << OCIE1A) | (1 << TOIE1))
26
sts    TIMSK1,r16
27
28
/**
29
 * OC1A as output (PIN C6, output) 
30
 *
31
 * DDRC    = DDC7 | DDC6 | DDC5 | DDC4 | DDC3 | DDC2 | DDC1 | DDC0
32
 * 0x??    =   -  |   1  |   -  |   -  |   -  |   -  |   -  |   -
33
 */
34
in     r16,DDRC
35
ori    r16,(1 << DDC6)
36
out    DDRC,r16
37
38
/**
39
 * WGM-mode 11, phase correct PWM
40
 * start PWM right now
41
 *
42
 * TCCR1B   = ICNC1 | ICES1 | - | WGM13 | WGM12 | CS12 | CS11 | CS10
43
 * 0x11    =   0   |   0   | 0 |   1   |   0   |   0  |   0  |   1
44
 */
45
ldi    r16,((1 << WGM13) | (1 << CS10))
46
sts    TCCR1B,r16

bzw.
1
/**
2
 * WGM-mode 11, phase correct PWM
3
 * toggle PIN C6
4
 *
5
 * TCCR1A  = COM1A1 | COM1A0 | COM1B1 | COM1B0 | COM1C1 | COM1C0 | WGM11 | WGM10
6
 * 0x43    =    0   |    1   |    0   |    0   |    0   |    0   |   1   |   1
7
 */
8
ldi    r16,((1 << COM1A0) | (1 << WGM11) | (1 << WGM10))
9
sts    TCCR1A,r16


Was die Wahl des Modus angeht, war die Idee dass die Frequenz sehr 
einfach geändert werden kann, nämlich nur durch Ändern eines Registers 
OCR1A. Das Tastverhältnis bleibt automatisch erhalten und muss nicht 
weiter beachtet werden und die beiden Interrupts gestatten mir das 
drumherum einfach zu behandeln. Da der Treiber (Trinamic TMC262) über 
eine STEP/DIRECTION Schnittstelle verfügt scheint mir eine PWM durchaus 
geeignet.

In den sehr einfachen Interruptroutinen will ich die Schritte bis zur 
Zielposition aktualisieren, bzw. prüfen, ob die Zielposition schon 
erreicht wurde bzw. ob ich noch beschleunigen oder bremsen muss (-> 
Frequenzänderung -> Änderung von OCR1A).

Im Falle der Nutzung des CTC Modus ist die eine Interruptroutine dann 
etwas komplizierter und ich muss mir auch noch merken ob eine volle 
Schrittperiode durchgeführt wurde bevor ich zum Beispiel die Frequenz 
ändere.

von Benjamin K. (Gast)


Lesenswert?

da hat sich noch ein Fehler eingeschlichen ...
1
/**
2
 * setup TOP value
3
 */
4
ldi    r16,0x01
5
sts    OCR1AH,r16
6
ldi    r16,0x00
7
sts    OCR1AL,r16

von Karl H. (kbuchegg)


Lesenswert?

Benjamin K. schrieb:

> Was die Wahl des Modus angeht, war die Idee dass die Frequenz sehr
> einfach geändert werden kann, nämlich nur durch Ändern eines Registers
> OCR1A.

Und?
Ist beim CTC mit toggeln auch nicht anders.

> Das Tastverhältnis bleibt automatisch erhalten und muss nicht
> weiter beachtet werden

auch das ist beim CTC nicht anders

> und die beiden Interrupts gestatten mir das
> drumherum einfach zu behandeln.

und wieder: ist beim CTC nicht anders

> Da der Treiber (Trinamic TMC262) über
> eine STEP/DIRECTION Schnittstelle verfügt scheint mir eine PWM durchaus
> geeignet.

Wozu?
eine PWM nimmst du, wenn die Pulse unterschiedliche 
Puls/Pausenverhältnisse haben müssen. Das ist bei dir nicht der Fall.


> Im Falle der Nutzung des CTC Modus ist die eine Interruptroutine dann
> etwas komplizierter

bis 2 zählen ist kompliziert?

Aber seis drum: Bei einer Frequenzänderung musst du 2 Register anpassen. 
Genausoviele wie zb im FastPWM Modus.
Den Top-Wert und den Compare Match.

Ausser in ganz seltenen Fällen, in denen zb 2 Timer eine bestimmte PWM 
Phasenbeziehung einhalten müssen oder es sonstige externe 
Symteriebeschränkungen gibt, braucht kein Mensch den phase correct Mode. 
Du bellst mit diesem Modus das falsche Pferd an.

von Benjamin K. (Gast)


Lesenswert?

Dann habe ich jetzt mal eine Frage:

Wenn der TOP-Wert bei Phase Correct PWM im Modus 11 durch OCR1A 
angegeben wird. Welches Register beinhaltet dann den Compare-Wert?

Gruß
Benny

von spess53 (Gast)


Lesenswert?

Hi

>Wenn der TOP-Wert bei Phase Correct PWM im Modus 11 durch OCR1A
>angegeben wird. Welches Register beinhaltet dann den Compare-Wert?

OCR1B und/oder OCR1C.

MfG Spess

von Benjamin K. (Gast)


Lesenswert?

Kannst du mir sagen wo das im Handbuch steht?

Ich habe es jetzt so gelöst, dass ich COM1A1 und COM1A0 auf 0:0 setze. 
Dadurch wird OC1A nicht von OCR1A beeinflusst. Ich setze den Pin jetzt 
einfach in den beiden Interruptroutinen.

Nochmal Danke für die Hilfe.

von spess53 (Gast)


Lesenswert?

Hi

>Kannst du mir sagen wo das im Handbuch steht?

Wenn du drei OC-Register hast und davon mutiert eins zum Top-Register. 
Wie viel bleiben dann noch übrig? Steht vielleicht auch irgendwo.

>Ich habe es jetzt so gelöst, dass ich COM1A1 und COM1A0 auf 0:0 setze.
>Dadurch wird OC1A nicht von OCR1A beeinflusst. Ich setze den Pin jetzt
>einfach in den beiden Interruptroutinen.

Blödsinn. Ich hatte deinen ersten Satz leider überlesen sonst hätte ich 
dir auch gleich, wie Karl-Heinz, zu CTC geraten. Also Mode 4. Damit 
kannst du eine von OCR1A abhängige Frequenz erzeugen. Ganz ohne 
Interrupts und händisches Pin setzten.

MfG Spess

von Benjamin K. (Gast)


Lesenswert?

Das ist schon richtig. Es steht aber auch nirgends das der Pin dann 
nicht mehr geschaltet werden kann. Es wird ja auch der Compare Match A 
Interrupt ausgelöst ...

Wie dem auch sei, zwei Befehle um einen Pin ein und auszuschalten und 1 
16-Bit-Register zu beschreiben scheint mir bequemer und weniger Aufwand 
zu sein als ständig 2 16-Bit-Register zu setzen zu berechnen wie jetzt 
das Compare Register beschrieben werden muss, damit ein Tastverhältnis 
von 1:1 erhalten bleibt und dann noch einen Vergleich durchzuführen 
damit ich weiß ob ich jetzt gerade mitten im Schritt bin oder doch schon 
am Ende, aber das ist nur meine Meinung ;-)

nochmal danke

von spess53 (Gast)


Lesenswert?

Hi

> damit ein Tastverhältnis
>von 1:1 erhalten bleibt und dann noch einen Vergleich durchzuführen

CTC hat ein Tastverhältnis von 1:1. Darum brauchst du dich nicht 
kümmern.

MfG Spess

von Karl H. (kbuchegg)


Lesenswert?

... und die 'Rechnerei' ist eine Multiplikation mit 2.
Die müsstest du bei deiner phase correct PWM Lösung im übrigen genauso 
machen.

Aber was solls. Des Menschen Wille ist sein Himmelreich.

von Benjamin K. (Gast)


Lesenswert?

Ich muss nichts rechnen, da ich nur das OCR1A-Register als TOP setze. 
Ich habs hier gerade Laufen ...

Ich war, wohl falsch, davon ausgegangen, dass man im Modus 11 einfach 
das OCR1A-Register als TOP setzen kann UND die Automatik des OC1A-Pin 
setzen nutzen kann. Auf diese Art würde man sich alle Rechnerei einfach 
sparen, weil der Pin beim zählen von 0x0000 zu TOP gesetzt und beim 
zählen von TOP zu 0x0000 rückgesetzt würde, oder falls benötigt 
umgekehrt.

Aufwand in diesem Fall:
1x 16 Bit-Register OCR1A setzen
1x Compare Match A Interrupt Routine mit Schritt zählen
1x Overflow Routine mit Frequenz ändern

Aufwand CTC-Modus:
1x 16 Bit-Register OCR1A setzen
1x Interrupt-Routine (Compare Match A)
1x Vergleich um entweder Frequenz zu ändern oder Schritt zu zählen
1x Register oder Variable um zu merken ob Schritt gezählt werden muss

Aufwand in meiner jetzigen Lösung:
1x 16 Bit-Register OCR1A setzen
1x Compare Match A Interrupt Routine mit Pin setzen (sbi) + Schritt 
zählen
1x Overflow Interrupt Routine mit Pin rücksetzen (cbi) + Frequenz ändern

Wenn ICR1 mit einbezogen wird, dann
1x 16 Bit-Register ICR1 setzen (nicht gepuffert!)
1x 16 Bit Division mit 2 (ok einfach, aber doch "Aufwand")
1x 16 Bit-Register OCR1A setzen für 1:1
1x Interrupt Routine (Compare Match A)
1x Vergleich um entweder Frequenz zu ändern oder Schritt zu zählen
1x Register oder Variable um zu merken ob Schritt gezählt werden muss

Wirklich vielen Dank für die Hilfe. Vielleicht ist mir auch einfach 
nicht gelungen klar auszudrücken was ich eigentlich wissen wollte...

Gruß
Benny

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.