Forum: Compiler & IDEs TXCx Flag löschen


von Avr (Gast)


Lesenswert?

Hi,

beim studieren des Datenblatt eines Atmega1281 bin ich über die Aussage 
"The TXCn Flag bit is automatically cleared when a transmit complete 
interrupt is executed, or it can be cleared by writing a one to its bit 
location"

Okay zum löschen also eine 1 an die entsprechende Stelle schreiben 
sprich UCSR0A |= (1 << TXC0);

Jetzt habe ich allerdings im GCC Tutorial hier im Forum folgende Aussage 
gefunden.

"Bei bestimmten AVR Registern mit Bits, die durch Beschreiben mit einer 
logischen 1 gelöscht werden, muss eine absolute Zuweisung benutzt 
werden. Ein ODER löscht in diesen Registern ALLE gesetzten Bits!"

TIFR2 = (1<<OCF2A); // Nur Bit OCF2A löschen

Nun habe ich obige Zuweisung sprich UCSR0A |= (1 << TXC0); schon in 
einigen Codes genau so gefunden.

Die Aussage aus dem Tutorial ist für mich auch schwer nachvollziehbar. 
Es handelt sich dabei doch um eine direkte Zuweisung an einen Port 
UCSR0A = (1 << TXC0); würde doch eigentlich dafür sorgen, dass im 
Register alle Bits auf 0 gesetzt werden nur das TXC0 bit halt erstmal 
auf eins und dann intern vom AVR wieder auf 0.

Was das ein DDRA = (1 << DD0) dazu führt das alles alten registerwerte 
auf 0 gesetzt werden bis auf Bit0 bei UCSR0A = (1 << TXC0); aber nur Bit 
TXC0 und alle anderen unberührt bleiben ?

von Falk B. (falk)


Lesenswert?

@Avr (Gast)

>"The TXCn Flag bit is automatically cleared when a transmit complete
>interrupt is executed, or it can be cleared by writing a one to its bit
>location"

Das ist auch so.

>Okay zum löschen also eine 1 an die entsprechende Stelle schreiben
>sprich UCSR0A |= (1 << TXC0);

FALSCH!
1
UCSR0A = (1 << TXC0);


Es darf NUR das ein Bit geschrieben werden! Diese Register regieren 
anders als die normalen Register!

>Nun habe ich obige Zuweisung sprich UCSR0A |= (1 << TXC0); schon in
>einigen Codes genau so gefunden.

Das macht sie nicht richtiger.

>Die Aussage aus dem Tutorial ist für mich auch schwer nachvollziehbar.
>Es handelt sich dabei doch um eine direkte Zuweisung an einen Port
>UCSR0A = (1 << TXC0); würde doch eigentlich dafür sorgen, dass im
>Register alle Bits auf 0 gesetzt werden nur das TXC0 bit halt erstmal
>auf eins und dann intern vom AVR wieder auf 0.

Nein, weil dieser Register intern einen Logikdekoder haben, der nicht 
einfach alle Bits speichert, die da geschrieben werden, sondern alle 
Bits löscht, die auf 1 stehen.

>Was das ein DDRA = (1 << DD0) dazu führt das alles alten registerwerte
>auf 0 gesetzt werden bis auf Bit0 bei UCSR0A = (1 << TXC0); aber nur Bit
>TXC0 und alle anderen unberührt bleiben ?

Anderes Register, anderde Wirkung.


OK, Nachtrag. Bei TXC ist es egal, weil es in dem Register nur ein 
einziges Flag (TXC) gibt, das diese Wirkung hat. Ausserdem sind dort 
noch zwei normale Bits drin, U2Xn und MPCMn, die man, wenn man sie 
braucht, nicht löschen darf. Also wäre der vollständig korrekte Weg
1
UCSR0A = (1 << TXC0) | (UCSR0A  & 3);

Im Normalfall, wenn U2Xn und MPCMn == 0 sind reicht eine einfache 
Zuweisung wie ganz oben gezeigt.

Anders ist es in Registern wie TIFR1. Dort sind NUR solche Spezialbits 
drin, dort MUSS man Einzelbits OHNE veroderung des alten Zustands 
schreiben, wenn man EINZELNE Bits löschen will.

von Ralf G. (ralg)


Lesenswert?

Vielleicht noch als Ergänzung:
Bei diesen speziellen Registern kannst du immer nur Bits löschen. Durch 
Schreiben einer 0 kannst du das Flag nicht setzen! Also: wenn du
1
UCSR0A |= (1 << TXC0);
schreibst, wird das Register gelesen, 'neu zusammengebaut' und wieder 
zurückgeschrieben. Wo jetzt eine 1 stand (Flag gesetzt) werden jetzt die 
Bits gelöscht.
Wie Falk schon schrieb, hier ist es (fast) egal. Aber: nicht erst 
angewöhnen ;-)

von Avr (Gast)


Lesenswert?

Vielen Dank für die schnelle und ausführliche Antwort.

Ein paar Fragen hätte ich dann aber immer noch nur um ganz sicher zu 
gehen. Wie wird UCSR0A = (1 << TXC0); vom Compiler in ASM umgesetzt ? In 
eine STS oder CBI bzw SBI Anweisung ?

Die Frage ist ja gerade die was passiert wenn in einem Register sowohl 
Interruptflags als auch "normale" Registerflags vorhanden sind. Wenn ich 
es aus dem Post von Falk richtig herauslese würde das einfache UCSR0A = 
(1 << TXC0); dazu führen das "normale" Registerbits gelöscht werden 
richtig ?

Sprich enthält ein Register Interruptflags dann bezieht sich dieser 
interne Logikmechanismus lediglich auf das jeweilige Bit und nicht auf 
das vollständige Register ?

Im Falle von TXC spielt es keine Rolle und es könnte mit |= verkünpft 
werden, da es eh nur dieses eine Interruptflag im Register gibt das R/W 
freige hat und die jeweils anderen Bits einfach "normal" auf den Befehl 
ansprechen.

Will man in einem solchen Mischregister die "normalen bits" 
konfigurieren würde USCR0A = (1 << PB0) | (1 << PB1) ebenfalls zu keinen 
Problemen führen, da die Interruptflags nicht auf das schreiben einer 0 
ansprechen.

Gäbe es mehr als ein Interruptflag im Register würde durch den |= Befehl 
eventuell ein Interruptflag das gerade gesetzt ist auf "1 eingelesen" 
und anschließend zurückgeschrieben was zum löschen aller gesetzten 
Interruptflags führen würde korrekt ?

von Ralf G. (ralg)


Lesenswert?

Falk Brunner schrieb:
> Also wäre der vollständig korrekte Weg
1
UCSR0A = (1 << TXC0) | (UCSR0A  & 3);


Hier ist alles drin, was man wissen muss!

von Karl H. (kbuchegg)


Lesenswert?

Avr schrieb:
> Vielen Dank für die schnelle und ausführliche Antwort.
>
> Ein paar Fragen hätte ich dann aber immer noch nur um ganz sicher zu
> gehen. Wie wird UCSR0A = (1 << TXC0); vom Compiler in ASM umgesetzt ? In
> eine STS oder CBI bzw SBI Anweisung ?
st
Das muss er als STS umsetzen.

Aber ich sehe, worauf du hinaus willst. Das Problem ist nämlich 
eigentlich nicht ein
  REG = (1 << Bit);
sondern ein
  REG |= (1<<Bit);

Und das eigentliche Problem an dieser Stelle ist es, dass sich hier die 
Hardware völlig an jeglichen KOnventionen vorbei verhält. Denn 
eigentlich dürfte ein Compiler ein
   REG |= (1<<Bit);
bei derartigen speziellen Registern keinesfalls mit einem SBI 
übersetzen, weil dieses ja nicht das geforderte Verhalten hat.

Schwierige Frage. Letzten Endes bleibt nur eines: ausprobieren ob die 
Compilerbauer diesen Spezialfall bedacht und abgefangen haben.

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.