Forum: Mikrocontroller und Digitale Elektronik [wiki] AVR Flag verodern wirklich falsch?


von Tom (Gast)


Lesenswert?

Hi,

http://www.mikrocontroller.net/articles/AVR_Checkliste#Flag_richtig_gel.C3.B6scht.3F

> Zusätzlich ist zu beachten, dass in C die Interrupt-Flags nicht mit einer
> Veroderung des Registers (z. B. TIFR |= (1 << TOV0)) gelöscht werden
> sollten, da bei dieser Operation alle anderen evtl. gesetzten Flags im
> betreffenden Register ebenfalls gelöscht werden. Es ist die Schreibweise
> von oben zu benutzen (also TIFR = (1 << TOV0))!


??? !!! Stimmt das wirklich?

Wenn ich wirklich nur zu doof bin, löscht dieses Posting bitte.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Tom schrieb:
> ??? !!! Stimmt das wirklich?
Die Interruptflagregister verhalten sich anders als "normale" Register. 
Dort wird ein gesetztes Flag gelöscht, indem eine '1' hieneingeschrieben 
wird (siehe Datenblatt " TOV0 is cleared by writing a logic one to the 
flag.").
Wenn jetzt aber sowas dasteht:
1
TIFR |= (1 << TOV0))
Dann heißt das ja, dass zuerst das Register gelesen wird, dann ein Bit 
dazuverodert, und dann alles wieder zurückgeschrieben wird (ein 
Read-Modify-Write eben). Das könnte ausführlich auch so geschrieben 
werden:
1
h = TIFR;
2
h = h|(1 << TOV0));
3
TIFR = h;
Wenn jetzt blöderweise andere Interruptbits auch gesetzt sind, dann 
werden die als Kollateralschaden mit gelöscht.
Wenn z.B. TIFR == 0010 0001 ist und dann das alles abgearbeitet wird:
h = TIFR;            --->   h  == 0010 0001
h = h|(1 << TOV0));  --->   h  == 0010 0001
Und wenn das zurückgeschrieben wird, dann werden beide Interrupt-Flags 
gelöscht:
TIFR = h;            ---> TIFR == 0000 0000   :-o

Besser wäre also noch sowas:
TIFR &= (1 << TOV0));

Und am einfachsten geht es tatsächlich so:
TIFR = (1 << TOV0));

von Tom (Gast)


Lesenswert?

Alles klar, danke!

Ich glaube, ich brauche doch erstmal nen Kaffee.

von Tom (Gast)


Lesenswert?

OK, mein Denkfehler war der, dass ich das für eine einfache Zuweisung, 
nur halt mit invertierter Wirkung, hielt.

Bei einer direkten Zuweisung des ganzen Registerinhaltes würden dann 
durch das Schreiben der Nullen in die Flagpositionen, die nicht 
ge/löscht/ werden, die Flags dort ge/setzt/ werden werden.

Aber das scheint die Hardware zu verhindern.

von Karl H. (kbuchegg)


Lesenswert?

Tom schrieb:

> Bei einer direkten Zuweisung des ganzen Registerinhaltes würden dann
> durch das Schreiben der Nullen in die Flagpositionen, die nicht
> ge/löscht/ werden, die Flags dort ge/setzt/ werden werden.

Nein.
Du kannst diese Flags nur löschen. Gesetzt werden sie durch die 
Hardware.

Aber: Du willst immer nur dieses EINE Flag löschen, welches du löchen 
willst! Alle anderen sollen nicht beeinflusst werden.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Tom schrieb:
> OK, mein Denkfehler war der, dass ich das für eine einfache Zuweisung,
> nur halt mit invertierter Wirkung, hielt.
Richtig, das war der Denkfehler.

> Aber das scheint die Hardware zu verhindern.
Zum Glück...  ;-)
Dieses Verhalten findet man bei einigen anderen uC-Familien bei solch 
kritischen Registern, die auf Read-Modify-Write-Befehle allergisch 
reagieren (könnten).
Es gibt dann evtl. sogar getrennte Register zum Setzen von Flags und 
Löschen vom Flags. Wenn dann in also das "Setz-Register" eine '1' 
geschrieben wird, wird das Bit gesetzt, wenn in das "Lösch-Register" 
eine '1' geschrieben wird, wird das entsprechende Bit im Zielregister 
zurückgesetzt.
Beim AVR gibt es von dieser "Vollausstattung" quasi nur das 
Lösch-Register.

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.