16bit Timer1 - Inerrupt beim Schreiben von TCNTx deaktivieren?

OP #3048750
Lesenswert?
• ▲
▼
Hallo,

ich habe eine Frage zum 16bit Timer1. Im Datenblatt wird man darauf 
hingewiesen, dass man beim Zugriff auf das 16bit Register (2 x 8 Bit 
Register) Interrupts vor dem Zugriff deaktivieren und nachher wieder 
aktivieren soll, damit ein eventuell auftretender Interrupt beim 
Schreiben oder Lesen zwischen den beiden 8 Bit Operationen nicht rein 
pfuscht.

Muss ich das in C auch machen oder erledigt das der Compiler für mich?
OP #3048830
Lesenswert?
• ▲
▼
Ok, d.h. wenn ich zum Timer Interrupt einen weiteren Interrupt im 
Programm verwende, muss ich einen möglichen weiteren Interrupt in dem 
Moment verhindern, wenn auf die 16bit Register des Timers zugegriffen 
wird.

z.B. so?

TCNTx lesen:
1
unsigned int TIM16_ReadTCNTn( void )
2
{
3
  unsigned char sreg;
4
  unsigned int i;
5

6
  sreg = SREG;  /* Save global interrupt flag */
7
  cli();        /* Disable interrupts */
8
  i = TCNTn;    /* Read TCNTn into i */
9
  sei();        /* Enable interrupts */
10
  SREG = sreg;  /* Restore global interrupt flag */
11
  return i;
12
}
Gast #3048845
Lesenswert?
• ▲
▼
m. g. schrieb:
> ich habe eine Frage zum 16bit Timer1. Im Datenblatt wird man darauf
> hingewiesen, dass man beim Zugriff auf das 16bit Register (2 x 8 Bit
> Register) Interrupts vor dem Zugriff deaktivieren und nachher wieder
> aktivieren soll, damit ein eventuell auftretender Interrupt beim
> Schreiben oder Lesen zwischen den beiden 8 Bit Operationen nicht rein
> pfuscht.

Steht in meinem Datenblatt so aber nicht bzw noch mehr.
OP #3048893
Lesenswert?
• ▲
▼
Magnus M. schrieb:
> m. g. schrieb:
>>   sreg = SREG;  /* Save global interrupt flag */
>>   cli();        /* Disable interrupts */
>>   i = TCNTn;    /* Read TCNTn into i */
>>   sei();        /* Enable interrupts */
>>   SREG = sreg;  /* Restore global interrupt flag */
>
> Das "sei()" kannst - oder besser gesagt SOLLTEST du weglassen.

Original steht das auch so nicht im Datenblatt. Wie du sagst, ohne 
sei();
Aber ist es nicht logisch, wenn ich die Interrupts gleich nach dem Lesen 
des TCNTn wieder einschalte? Wann würden sie denn sonst wieder 
eingeschaltet?
Persönliche Seite #3048900
Lesenswert?
• ▲
▼
> Original steht das auch so nicht im Datenblatt. Wie du sagst, ohne
> sei();

Eben.

> Aber ist es nicht logisch, wenn ich die Interrupts gleich nach dem Lesen
> des TCNTn wieder einschalte?

Nein.

> Wann würden sie denn sonst wieder eingeschaltet?

Ganz einfach durch die Zeile

SREG = sreg;  /* Restore global interrupt flag */

Das Global Interrupt Enable Flag ist Bestandteil des SREG. War dieses 
vorher gesetzt, so wird es nach dieser Zeile auch wieder gesetzt sein. 
War es vorher gelöscht, so wird es auch nach dieser Zeile gelöscht sein.
OP #3048908
Lesenswert?
• ▲
▼
kaplic schrieb:
> Da im Datenblatt steht, was du tun sollst, musst du das auch in C tun!
> Der Compiler ist keine Glaskugel, welche weiß, was du vor hast!!!

Hier ein Auszug aus dem Datenblatt (AT90PWM316 Seite 105): (Habs erst 
jetzt gesehen)

The following code examples show how to access the 16-bit Timer 
Registers assuming that no interrupts updates the temporary register. 
The same principle can be used directly for accessing the OCRnx and ICRn 
Registers.

Note that when using “C”, the compiler handles the 16-bit access.

Wie es aussieht, erledigt der Compiler doch den 16-bit Zugriff und 
übernimmt das Deaktivieren und Aktivieren der Interrupts!
Persönliche Seite #3048915
Lesenswert?
• ▲
▼
m. g. schrieb:
> Note that when using “C”, the compiler handles the 16-bit access.
>
> Wie es aussieht, erledigt der Compiler doch den 16-bit Zugriff und
> übernimmt das Deaktivieren und Aktivieren der Interrupts!

NEIN! Der Compiler kümmert sich nur um die korrekte Reihenfolge des 
Registerzugriffs.

> The following code examples show how to access the 16-bit Timer
> Registers assuming that no interrupts updates the temporary register.

Beachte die Aussage "assuming that no interrupts updates the temporary 
register"!
#3048922
Lesenswert?
• ▲
▼
m. g. schrieb:
> Wann würden sie denn sonst wieder eingeschaltet?

Wie es im Kommentar steht, durch das SREG = sreg. Ein bestimmtes Bit im 
Statusregister kodiert, ob die Interrupts an oder aus sind. Durch cli() 
kann man es löschen (Interrupts aus), und mit sei() setzen (Interrupts 
an).

Der Code stellt also den Zustand wieder her, den das Bit vorher hatte:
1
sreg = SREG;  /* Save global interrupt flag */
2
cli();        /* Disable interrupts */
3
i = TCNTn;    /* Read TCNTn into i */
4
SREG = sreg;  /* Restore global interrupt flag */
Wenn die Interrupts am Anfang aus waren, bleiben sie aus. Wenn sie an 
waren, werden sie wieder eingeschaltet.

Mit sei() würdest Du sie dagegen immer einschalten, egal ob sie vorher 
an oder aus waren. Wenn Du also sicher weißt, dass sie vorher an waren, 
kannst Du Dir das Sichern des Statusregisters sparen:
1
cli();        /* Disable interrupts */
2
i = TCNTn;    /* Read TCNTn into i */
3
sei();        /* Enable interrupts */

Beides Kombinieren macht aber keinen Sinn. In util/atomic.h gibt es 
übrigens Makros für diese beiden Sequenzen:
1
#include <util/atomic.h>
2

3
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
4
  i = TCNTn;
5
}

bzw.
1
ATOMIC_BLOCK(ATOMIC_FORCEON) {
2
  i = TCNTn;
3
}
OP #3048952
Lesenswert?
• ▲
▼
Magnus M. schrieb:

> Beachte die Aussage "assuming that no interrupts updates the temporary
> register"!

Ok, jetzt wird mir die Sache schon klarer. Wenn ich das jetzt richtig 
verstanden habe, muss ich nur darauf achten, welches Ereignis mir das 
temporäre 8-bit Register im entscheidenten Moment überschreiben kann!

Und das kann denke ich jetzt nur das TCNTn, OCRnx oder das ICRn sein? 
Also ein 16-bit Register, dass ebenso das temporäre 8-bit Register 
verwendet.

Wenn ich also nur einen 16-bit Timer im CTC-Mode laufen habe und z.B. 
einen ext. Int0, dann brauche ich mir keine Gedanken darüber machen?

Sehe ich das richtig?
#3050137
Lesenswert?
• ▲
▼
m. g. schrieb:

> Wenn ich also nur einen 16-bit Timer im CTC-Mode laufen habe und z.B.
> einen ext. Int0, dann brauche ich mir keine Gedanken darüber machen?
>
> Sehe ich das richtig?

Nein, das siehst du falsch.

Wenn es möglich ist, egal wie, dass dir beim Auslesen eines 16 Bit 
Registers ein Interrupt reinkommt, wenn das eine Byte schon gelesen 
wurde und das andere noch nicht, dann kannst du in ein Problem laufen, 
weil die beiden Bytes nicht aus demselben Zählvorgang stammen können. 
Punkt.

Wozu willst du das überhaupt auslesen?
#3050216
Lesenswert?
• ▲
▼
m. g. schrieb:
> Wenn ich also nur einen 16-bit Timer im CTC-Mode laufen habe und z.B.
> einen ext. Int0, dann brauche ich mir keine Gedanken darüber machen?

???

Der Knackpunt ist nicht der Interrupt, sondern was Du darin machst.

Wenn irgendein Interrupt auf TCNTn, OCRnx oder das ICRn zugreift, muß 
das Main solche Zugriffe atomar kapseln.
Z.B. der INT0 liest TCNT1 und das Main schreibt OCR1B.

Alternativ kann aber auch der Interrupt das temporäre Register vor dem 
Zugriff sichern.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren