Forum: Mikrocontroller und Digitale Elektronik ATmega1284P Timer2 startet nicht


von Christian R. (cmrudolph)


Lesenswert?

Hi,

ich bekomme bei meinem ATmega1284P den Timer2 einfach nicht gestartet. 
Der Code, mit dem ich versuche den Timer zu aktivieren:
1
ASSR |= (1 << EXCLK);
2
ASSR |= (1 << AS2);
3
TCNT2 = 0;
4
//enable in CTC mode, w/o prescaler
5
TCCR2A = (1 << WGM21);
6
TCCR2B = (1 << CS20);
7
OCR2A = 127;
8
//clear timer / counter interrupt flags
9
TIFR2 = (1 << OCF2B) | (1 << OCF2A) | (1 << TOV2);
10
TIMSK2 = (1 << OCIE2A);

Bei der Reihenfolge habe ich mich an die im Datenblatt beschriebene 
"sichere Prozedur" um in den asynchronen Modus zu wechseln gehalten 
(Kapitel 17.9).
"Wait for TCN2UB, OCR2xUB, and TCR2xUB" habe ich dabei wieder 
auskommentiert, weil das ansonsten eine Endlosschleife ist.

Beim Debuggen mit JTAG habe ich bemerkt, dass den µC gar nicht 
interessiert, ob ich irgendwelche Flags in den Registern gesetzt habe. 
Direkt nach Ausführung der letzten geposteten Zeile sind die Register 
TIFR2, GTCCR, TIMSK2, TCCR2A, TCCR2B, TCNT2, OCR2A, OCR2B und ASSR alle 
mit 0x00 belegt. Auch beim schrittweisen debuggen ändern sich die Werte 
nicht.
Das einzige Register, welches sich beschreiben ließ war GTCCR. Darin 
hatte ich testweise die Flags TSM und PSRASY gesetzt, bevor ich die 
anderen beschreiben wollte und nach dem "beschreiben" das TSM Flag 
gecleared. Beschreiben ließen sich die Register trotzdem nicht.

Am TOSC1 Pin liegt ein Rechtecksignal mit 1Hz an (von einer RTC), das 
Bit vom Inputpin togglet auch so wie es soll.

Die ISR für den TIMER2_COMPA_vect ist auch definiert.


Woran kann es liegen, dass sich die Register nicht beschreiben lassen? 
Alle anderen Timer des ATmega (Timer0, Timer1 und Timer3) funktionieren 
wie gewohnt.

Vielen Dank und Grüße
Christian



Der kompilierte ASM Code:
1
  ASSR |= (1 << EXCLK);
2
 172:  e6 eb         ldi  r30, 0xB6  ; 182
3
 174:  f0 e0         ldi  r31, 0x00  ; 0
4
 176:  80 81         ld  r24, Z
5
 178:  80 64         ori  r24, 0x40  ; 64
6
 17a:  80 83         st  Z, r24
7
  ASSR |= (1 << AS2);
8
 17c:  80 81         ld  r24, Z
9
 17e:  80 62         ori  r24, 0x20  ; 32
10
 180:  80 83         st  Z, r24
11
  TCNT2 = 0;
12
 182:  10 92 b2 00   sts  0x00B2, r1
13
  //enable in CTC mode, w/o prescaler
14
  TCCR2A = (1 << WGM21);
15
 186:  82 e0         ldi  r24, 0x02  ; 2
16
 188:  80 93 b0 00   sts  0x00B0, r24
17
  TCCR2B = (1 << CS20);
18
 18c:  91 e0         ldi  r25, 0x01  ; 1
19
 18e:  90 93 b1 00   sts  0x00B1, r25
20
  OCR2A = 127;
21
 192:  9f e7         ldi  r25, 0x7F  ; 127
22
 194:  90 93 b3 00   sts  0x00B3, r25
23
  //clear timer / counter interrupt flags
24
  TIFR2 = (1 << OCF2B) | (1 << OCF2A) | (1 << TOV2);
25
 198:  97 e0         ldi  r25, 0x07  ; 7
26
 19a:  97 bb         out  0x17, r25  ; 23
27
  //GTCCR &= ~(1 << TSM);
28
  
29
  TIMSK2 = (1 << OCIE2A);
30
 19c:  80 93 70 00   sts  0x0070, r24

von Thomas E. (thomase)


Lesenswert?

Christian Rudolph schrieb:

> Beim Debuggen mit JTAG habe ich bemerkt, dass den µC gar nicht
> interessiert, ob ich irgendwelche Flags in den Registern gesetzt habe.
> Direkt nach Ausführung der letzten geposteten Zeile sind die Register
> TIFR2, GTCCR, TIMSK2, TCCR2A, TCCR2B, TCNT2, OCR2A, OCR2B und ASSR alle
> mit 0x00 belegt. Auch beim schrittweisen debuggen ändern sich die Werte
> nicht.
> Das einzige Register, welches sich beschreiben ließ war GTCCR. Darin
> hatte ich testweise die Flags TSM und PSRASY gesetzt, bevor ich die
> anderen beschreiben wollte und nach dem "beschreiben" das TSM Flag
> gecleared. Beschreiben ließen sich die Register trotzdem nicht.
>
> Am TOSC1 Pin liegt ein Rechtecksignal mit 1Hz an (von einer RTC), das
> Bit vom Inputpin togglet auch so wie es soll.

Die Register des Timers werden mit dem asynchronen Takt getriggert. Das 
sind bei dir 1Hz. Das kannst du vergessen. Das kann schon mit 32KHz 
Probleme geben.
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/Die_Timer_und_Z%C3%A4hler_des_AVR#Wenn_er_die_Minute_in_20s_schafft

mfg.

von Christian R. (cmrudolph)


Lesenswert?

Nichtsdestotrotz sollten sich die Register anfangs doch schreiben 
lassen, oder nicht? Denn bevor ich EXTCLK und AS2 setze, bekommt der 
Timer ja die CPUclk (in meinem Fall 4MHz).

Und wenn ich den Artikel richtig verstanden hat, dann wirkt sich diese 
Problematik auf die Ausführung der ISR aus. Der Timer startet bei mir 
aber gar nicht - auch nicht im synchronen Modus.

Alternativ kann ich mit dem PCINT2 einen softwaretimer bauen, was 
natürlich nicht so schön wäre.

von Thomas E. (thomase)


Lesenswert?

Christian Rudolph schrieb:
> Nichtsdestotrotz sollten sich die Register anfangs doch schreiben
> lassen, oder nicht? Denn bevor ich EXTCLK und AS2 setze, bekommt der
> Timer ja die CPUclk (in meinem Fall 4MHz).
>
> Und wenn ich den Artikel richtig verstanden hat, dann wirkt sich diese
> Problematik auf die Ausführung der ISR aus. Der Timer startet bei mir
> aber gar nicht - auch nicht im synchronen Modus.
>
> Alternativ kann ich mit dem PCINT2 einen softwaretimer bauen, was
> natürlich nicht so schön wäre.

Der startet irgendwann. Nachdem das AS2-Bit gesetzt wurde, ist der 
Async-Takt der Takt für alle Register des Timers.
Dafür ist das da:

>"Wait for TCN2UB, OCR2xUB, and TCR2xUB" habe ich dabei wieder
>auskommentiert, weil das ansonsten eine Endlosschleife ist.

Damit wird gewartet bis die Register geschrieben sind. Aber mit 1Hz wird 
der Timer nicht nur zur Schlaftablette sondern zu einer zugedröhnten 
Schlaftablette.

Schalte den TOSC1-Pin als normalen Porteingang und benutze den 
Pinchange-Interrupt zum Sekunden zählen.

Die Async-Mimik ist dazu gedacht, daß sie mit 32KHz betrieben wird.

mfg.

: Bearbeitet durch User
von Christian R. (cmrudolph)


Lesenswert?

Thomas Eckmann schrieb:
> Schalte den TOSC1-Pin als normalen Porteingang und benutze den
> Pinchange-Interrupt zum Sekunden zählen.

Das eigentliche Ziel ist es, den µC schlafen zu lassen und dann nach 
mehreren Sekunden wieder aufzuwecken. Das geht natürlich auch mit einem 
Prescaler von 1024 und OCRA von einem Vielfachen von 32.

> Die Async-Mimik ist dazu gedacht, daß sie mit 32KHz betrieben wird.
Ich habe die RTC umgestellt, sodass sie jetzt ein 32kHz Rechtecksignal 
ausgibt. Auch nach mehreren Minuten sind die Register nicht gesetzt.

Was mich wie gehabt wundert, ist dass trotz ASSR auf 0x00 (also Timer2 
im synchronen Modus, kein externer Takt) die Register nicht beschrieben 
werden.

Das mit dem Warten auf die TCN2UB etc. Flags ist im Datenblatt etwas 
missverständlich ausgedrückt. Es liest sich so, als ob man darauf warten 
soll, dass die Flags gesetzt sind. Das macht aber eigentlich keinen Sinn 
(das OCR2B Register versuche ich z.B. gar nicht zu setzen, daher kann 
das OCR2BUB Flag niemals high werden) und deshalb hatte ich eine 
Endlosschleife.
Wenn ich sinnigerweise darauf warte, dass alle Flags low sind, dann ist 
das sofort der Fall, weil die Flags nicht gesetzt werden.

von Thomas E. (thomase)


Lesenswert?

Christian Rudolph schrieb:
> Das mit dem Warten auf die TCN2UB etc. Flags ist im Datenblatt etwas
> missverständlich ausgedrückt. Es liest sich so, als ob man darauf warten
> soll, dass die Flags gesetzt sind. Das macht aber eigentlich keinen Sinn
> (das OCR2B Register versuche ich z.B. gar nicht zu setzen, daher kann
> das OCR2BUB Flag niemals high werden) und deshalb hatte ich eine
> Endlosschleife.
> Wenn ich sinnigerweise darauf warte, dass alle Flags low sind, dann ist
> das sofort der Fall, weil die Flags nicht gesetzt werden.

Die Flags müssen OR und nicht AND verknüpft werden.

Wenn du den Async-Mode einschaltest, danach die Timerregister setzt und 
dann sofort mit dem Debugger zuschlägst, sind die Register noch leer. 
Hast du mal probiert, die Timerregister vorher zu setzen und dann auf 
Async zu schalten?

mfg.

von der alte Hanns (Gast)


Lesenswert?

bei mir läuft (in Assembler und ohne Interrupt):
1
  ldi    tmp0,(1<<EXCLK)+(1<<AS2)
2
  sts    ASSR,tmp0
3
  ldi    tmp0,(1<<WGM21)                ; CTC
4
  sts    TCCR2A,tmp0
5
  ldi    tmp0,5
6
  sts    OCR2A,tmp0
7
  ldi    tmp0,0
8
  sts    TCNT2,tmp0
9
  ldi    tmp0,(1<<CS20)                ; /1
10
  sts    TCCR2B,tmp0
11
update_loop:
12
   lds   tmp0,ASSR
13
   andi  tmp0,((1<<TCN2UB)+(1<<OCR2AUB)+(1<<TCR2AUB))
14
  brne  update_loop
15
main_loop:
16
   sbis  TIFR2,OCF2A
17
  rjmp   main_loop
18
  sbi    TIFR2,OCF2A
19
  rcall  Meldung
20
 rjmp    main_loop

von c-hater (Gast)


Lesenswert?

Christian Rudolph schrieb:

> Woran kann es liegen, dass sich die Register nicht beschreiben lassen?

Falsche Part-Definition included?

von Christian R. (cmrudolph)


Lesenswert?

Thomas Eckmann schrieb:
> Die Flags müssen OR und nicht AND verknüpft werden.

Folgende Schleife habe ich verwendet:
1
while (ASSR & ((1 << TCN2UB) | (1 << OCR2AUB) | (1 << TCR2AUB)));

Thomas Eckmann schrieb:
> Wenn du den Async-Mode einschaltest, danach die Timerregister setzt und
> dann sofort mit dem Debugger zuschlägst, sind die Register noch leer.
> Hast du mal probiert, die Timerregister vorher zu setzen und dann auf
> Async zu schalten?

Ich bin den Code schrittweise durchgegangen, habe den Code in einem 
Rutsch ausführen lassen und danach einen Breakpoint gesetzt, aber beides 
hat nicht funktioniert.

der alte Hanns schrieb:
> bei mir läuft (in Assembler und ohne Interrupt)

Das entspricht in C wohl
1
ASSR = (1 << EXCLK) | (1 << AS2);
2
TCCR2A = (1 << WGM21);
3
OCR2A = 5;
4
TCNT2 = 0;
5
TCCR2B = (1 << CS20);
6
while (ASSR & ((1 << TCN2UB) | (1 << OCR2AUB) | (1 << TCR2AUB)));
Ich habe den kompilierten ASM Code analysiert, bis zur update-loop ist 
der Code identisch (der Compiler hat statt ein Register in dem eine 0 
stand wiederverwendet, also ist es eine ldi Anweisung weniger).

Die update-loop prüft doch, ob eines der drei Flags TCN2UB, OCR2AUB oder 
TCR2AUB gesetzt ist, oder?

Für meinen Code habe ich folgendes bekommen:
1
  while (ASSR & ((1 << TCN2UB) | (1 << OCR2AUB) | (1 << TCR2AUB)));
2
 1ce:  e6 eb         ldi  r30, 0xB6  ; 182
3
 1d0:  f0 e0         ldi  r31, 0x00  ; 0
4
 1d2:  80 81         ld  r24, Z
5
 1d4:  8a 71         andi  r24, 0x1A  ; 26
6
 1d6:  e9 f7         brne  .-6        ; 0x1d2 <initialize_uc+0x5c>

Edit: 0xB6 ist die Adresse, an der das ASSR Register liegt.
Edit2: 0x1A ist die Bitmaske für TCN2UB, OCR2AUB und TCR2AUB. Edit-Ende

Mich macht dabei stutzig, dass er zu 0x1d2 springt. Ändert sich das 
Zeroflag denn überhaupt noch?

c-hater schrieb:
> Falsche Part-Definition included?

Definitiv nicht. Es funktionieren die anderen Timer, TWI ist auch 
erfolgreich in Benutzung und die angesprochenen Ausgänge sind auch 
korrekt. Selbst den Interrupt auf dem TOSC1 Pin kann ich auslösen 
lassen.

: Bearbeitet durch User
von der alte Hanns (Gast)


Lesenswert?

In dieser einfachen Konstellation kann man die update-loop komplett 
weglassen.
Es muss etwas anderes nicht in Ordnung sein.

von Christian R. (cmrudolph)


Lesenswert?

So, des Fehlers Ursache ist gefunden...

Ich schäme mich schon fast das hier zu schreiben. Als ich die 
Programmierung vor fast einem Jahr begonnen habe, habe ich alle zu dem 
Zeitpunkt nicht benötigten Module des µC deaktiviert:
1
void initialize_uc()
2
{
3
  //disable Timer/Counter 0, synchronous Timer/Counter 2, SPI and ADC
4
  PRR0 = (1 << PRTIM0) | (1 << PRTIM2) | (1 << PRSPI) | (1 << PRADC);

Deshalb ließen sich die Register nicht schreiben!

Dass es an dem Programmcode liegen muss habe ich bemerkt, als ich den µC 
nochmal nur mit dem Timercode geflasht habe und es dann funktionierte.


Danke an alle für die Hilfe!

Grüße
Christian

von der alte Hanns (Gast)


Lesenswert?

> 1ce:  e6 eb         ldi  r30, 0xB6  ; 182
> 1d0:  f0 e0         ldi  r31, 0x00  ; 0
> 1d2:  80 81         ld  r24, Z

Kann mir jemand erklären, warum der C-Compiler diese Konstruktion 
verwendet anstatt eines simplen  lds r24,ASSR  ?

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.