Forum: Compiler & IDEs AVR: Konstante 0 ist nicht 0 in ISR


von Jantronics (Gast)


Lesenswert?

Hallo, ich habe folgendes Problem: Ich verwende einen ATmega 32 und habe 
eine ISR für den EEPROM ready interrupt geschrieben. Darin gibt es eine 
Zuweisung:
1
ucBufferState = EEPROM_BUFFER_READY;

Dabei ist ucBufferState eine globale Variable vom Typ volatile unsigned 
char und EEPROM_BUFFER_READY ein Makro:
1
#define  EEPROM_BUFFER_READY  0

Es soll also ucBufferState schlicht der konstante Wert 0 zugewiesen 
werden. Dies gelingt aber nicht, ucBufferState bekommt irgendeinen 
anderen Wert. Dieses Problem tritt nur beim Wert 0 auf, verwende ich z. 
B. als Konstante eine 1 funktioniert das Ganze wie gewünscht. Das taugt 
zwar durchaus als work around, dennoch würde ich das Problem gerne 
verstehen, denn sonst könnte ich mich nicht mehr auf Vergleiche oder 
Zuweisungen mit einer konstanten 0 verlassen.

von Karl H. (kbuchegg)


Lesenswert?

Such mal dein Programm nach Arrayüberläufen ab.
Meistens ist es irgendsowas, wenn Variablen anscheinend
ohne Grund ihren Wert ändern.

von Εrnst B. (ernst)


Lesenswert?

Auch ne Möglichkeit:
Hast du irgendwo ASM-Code dazugelinkt (oder inline-ASM), der das 
GCC-Zero-Register überschreibt, üblicherweise "r1" ?

das muss auf jeden Fall wieder auf 0 zurückgesetzt werden, und 
interrupts sperren während r1 != 0... Am besten garnicht erst anfassen.

von Werner B. (Gast)


Lesenswert?

Ist "ucBufferState" auch als "volatile" Variable definiert?

von Jantronics (Gast)


Lesenswert?

Beim r1 Register liegt der Hund wohl tatsächlich begraben, ein Blick in 
das Assemblerlisting zeigt seine ursächliche Beteiligung an dem 
Shringsel. Es scheint tatsächlich != 0 zu sein. Nur mache ich das 
nirgendwo wissentlich. Da muss ich nochmal genauer nachforschen. Danke 
schon mal für den Hinweis!

von Jantronics (Gast)


Lesenswert?

Nachtrag: Es hat sich herausgestellt, dass mein Problem ein gänzlich 
anderes wahr. Der Annahme, dass das r1-Register in der ISR nicht den 
Wert 0 hat, widersprach die GCC-Doku, die besagt, dass r1 beim ISR 
Aufruf gerettet und anschließend zwangsweise auf 0 gesetzt wird. Ein 
weiterer Blick in das Listing bestätigte dies auch.

Der Fehler bestand vielmehr darin, dass es dem Compiler gefiel, zwei 
globale Variablen, die sich in unterschiedlichen Modulen befanden, 
jedoch den gleichen Namen trugen, als ein und dasselbe anzusehen, 
selbstverständlich ohne Warnung geschweige denn einer Fehlermeldung. 
Nunja, unterschiedlich genannt - und alles wird gut...

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Jantronics wrote:

> Der Fehler bestand vielmehr darin, dass es dem Compiler gefiel, zwei
> globale Variablen, die sich in unterschiedlichen Modulen befanden,
> jedoch den gleichen Namen trugen, als ein und dasselbe anzusehen,
> selbstverständlich ohne Warnung geschweige denn einer Fehlermeldung.

Dafür sind es doch globale Variablen.  Die sind per definitionem
identisch.  Warum sollte es dafür eine Warnung geben?  Der Linker
würde dich warnen, wenn beide Module versuchen, das gleiche Symbol
mit einer unterschiedlichen Größe zu benutzen, aber in allen anderen
Fällen geht er davon aus, dass das so gewollt war.  Das ist im
C-Standard ausdrücklich zulässig (und im C99 Rationale als eine der
möglichen Belegungstrategien für Variablen erklärt).

Wenn du das abschalten willst (dann schaltest du auf eine andere
Belegungsstrategie um, die ebenfalls im Rationale als eine Möglichkeit
erläutert ist), dann geht das mit der Compileroption -fno-common.

Ansonsten ist es halt einfach guter und sinnvoller Programmierstil,
nur solche Objekte und Funktionen global zu deklarieren, für die das
notwendig ist.  (Deren Deklaration sollte dann auch in ein von allen
Modulen gemeinsam genutztes Headerfile gehen.)  Alles andere wird
`static', dann passieren derartige Unfälle auch nicht.  Es ist ein
Versäumnis, dass `static' nicht der Default ist, sondern `global'.

von Jantronics (Gast)


Lesenswert?

Danke für die Info mit der Compiler-Option. Ich war es allerdings bisher 
gewohnt, dass ich eine über mehrere Module globale Variable in einem 
Modul definiere und in den anderen als "extern" deklariere, oder, wie 
schon gesagt, in einem gemeinsamen Header definiere. Naja, was soll's, 
der eine Compiler macht's so, der andere anders, muss man halt wissen.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Jantronics wrote:

> Ich war es allerdings bisher
> gewohnt, dass ich eine über mehrere Module globale Variable in einem
> Modul definiere und in den anderen als "extern" deklariere, ...

Ist ja auch der vernünftige Weg.

Ich vermute, GCCs Verhalten (das dem des klassischen Unix-C-Compilers
entsprechen dürfte) rührt einfach aus einer Zeit her, da C das
Schlüsselwort "extern" noch nicht kannte.  Damit konnte nicht zwischen
Definition und Deklaration einer globalen Variablen unterschieden
werden.  Später hat man das möglicherweise aus Kompatibilitätsgründen
im Compiler beibehalten, damit sich der bereits existierende Code
noch genau so verhält wie früher.

Wie geschrieben, das ist aber reine Spekulation.  Man sollten in
Erinnerung behalten, dass in den 1970er Jahren einfach manche Dinge
bezüglich Programmierstil anders gesehen worden sind.

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.