winavr volatile

Hallo,

ich habe vor einiger Zeit einen Fehler in einem Programm beseitigt und weiss aktuell nicht mehr genau, was die Fehlerursache war, weil ich zwei Dinge geändert habe:

  1. Ich habe eine globale Variable, die in einer INT-Routine verwendet wird als volatile deklariert

  1. Ich habe "if (!fehler) " in "if (fehler == 0) geändert.

Die if-Abfrage befindet sich in derselben INT-Routine, in der die Variable "fehler" verändert wird, wobei zwischen der Änderung und der Abfrage die INT-Routine eventuell verlassen und neu aufgerufen werden kann.

Ich hatte gedacht, dass ich volatile in dem Fall nicht brauche, bzw. bewirkt das bei winavr überhaupt etwas?

Ich Nachhinein überlege ich, ob es nicht besser gewesen wäre, die Variable "fehler" lokal in der INT-Routine als static zu deklarieren...

Der 2. Punkt kann es ja wohl nicht sein, oder?

Testen kann ich das momentan nicht, weil ich dazu erstmal einiges an Hardware aufbauen müsste. Mich würde aber trotzdem mal interessieren, woran es denn letztenendes lag.

gruß

Stefan DF9BI

Alte Version:

--------------------------------------------------- .... uint8_t fehler; // global deklariert, aber ohne volatile ....

// in einer Int-routine

... // fehler kann ein Wert zwischen 0 und 64 sein, 0=kein Fehler

if (!fehler) {... // das funktioniert nicht, d.h. der // Programmteil wird immer aufgerufen, auch wenn // Fehler > 0 }

------------------------------------------------------ Neue Version:

.... volatile uint8_t fehler; // global deklariert ....

// in einer Int-routine

... // fehler kann ein Wert zwischen 0 und 64 sein, 0=kein Fehler

if (fehler==0) {... // tut jetzt

}

------------------------------------------------------ Alternative: (nicht getestet)

// in der INT-Routine:

static uint8_t fehler; ...

if (!fehler) { //... }

Reply to
Stefan Brröring
Loading thread data ...

Am 21.06.2011 10:14, schrieb Stefan Brröring:

Ohne volatile schmeißt mir der AVRGCC auch immer die globalen Variablen raus.

Static in der Interrupt-Routine sollte aber auch gehen.

IMHO können bei AVRGCC Integer als "bool" behandelt werden, also alles außer "0" ist wahr.

Reply to
Heiko Lechner

Der Optimizer sieht vmtl. folgendes: Eine Variable fuer deren Wert sich nur eine Routine interessiert die nie aufgerufen wird (der Interrupt handler fuer den nirgends im Code ein expliziter Aufruf existiert). Die Variable und die Schreibzugriffe darauf werden deswegen wegoptimiert.

Die Variable "fehler" noch woanders lesend zu benutzen sorgt ggf. dafuer, dass sie nicht wegoptimiert wird. Das "volatile" ist aber die richtige Loesung. Das sorgt zusaetzlich dafuer, dass immer und sofort auf die Variable zugegriffen wird. Ansonsten kann es dir z.B. passieren, dass der Optimizer die Variable zeitweise in einem Register puffert und der Interrupthandler dadurch einen aktualisierten Wert verspaetet zu sehen bekommt.

Micha

Reply to
Michael Baeuerle

ei

Dieses. Abh=C3=A4ngig davon, wo der Schreibzugriff auf die Variable stat= tfinden soll, da=C3=9F ist aus Deinem Beispielcode nicht ersichtlich.

C99, 6.7.3 (6):

|An object that has volatile-qualified type may be modified in ways unkn= own |to the implementation or have other unknown side effects.

Ein Interrupt-Handler ist mit ziemlicher Sicherheit etwas, was als "unkn= own to the implementation" gelten kann.

Vinzent.

--

f u cn rd ths, u cn gt a gd jb n cmptr prgrmmng.
Reply to
Vinzent Hoefler

Am 21.06.2011 11:50, schrieb Heiko Lechner:

Das hat nichts mit dem AVRGCC zu tun, das garantiert der C-Std.

Gruß, Johannes

--

Ah, der neueste und bis heute genialste Streich unsere großen Kosmologen: Die Geheim-Vorhersage. - Karl Kaos über Rüdiger Thomas in dsa

Reply to
Johannes Bauer

Aber nur, wenn sie auch aus dem Hauptprogramm gelesen/geschrieben wird.

Ich hatte ihn so verstanden, daß er die Variable *nur* innerhalb des Interrupthandlers liest/schreibt.

In den Fall müßte der Compiler auch ohne "volatile" gültigen Code erzeugen.

Der Compiler wird allerdings vermutlich mit "volatile" *anderen* Code erzeugen als ohne (auch, wenn das niemand außerhalb des Interrupthandlers braucht), wodurch sich das Laufzeitverhalten ändert, so daß möglicherweise der echte Bug kaschiert wird.

cu Michael

Reply to
Michael Schwingen

Wie soll er das tun? Der Interrupthandler wird kompiliert, damit muß er die Zugriffe auf die Variable 'reinnehmen. Ob Volatile oder nicht, ist erstmal egal - ob die Funktion "Interrupthandler" jetzt per Interrupt oder von einer anderen Funktion aufgerufen wird, ist dem Compiler für das Übersetzen

*dieser Funktion* erstmal egal.

Ob eine nicht-static-Funktion aufgerufen wird oder nicht, kann erst der Linker entscheiden.

Nein. Er greift außerhalb des Interrupthandlers überhaupt nicht auf die Variable zu. Das "volatile" kaschiert also vermutlich nur den echten Fehler.

cu Michael

Reply to
Michael Schwingen

nknown

nknown

.

des

Ja, allerdings sind die Infos des OP etwas mangelhaft, wenn er schreibt

|Die if-Abfrage befindet sich in derselben INT-Routine, in der die Varia= ble |"fehler" ver=C3=A4ndert wird, wobei zwischen der =C3=84nderung und der = Abfrage die |INT-Routine eventuell verlassen und neu aufgerufen werden kann.

Mir ist n=C3=A4mlich nicht 100%ig klar, wie er das meint. Und die Code-S= chnipsel sind auch zu d=C3=BCrftig, um daraus mehr Informationen zu erhalten.

Ich bin nun optimistisch davon ausgegangen, da=C3=9F der Compiler schlic= ht und einfach feststellt, da=C3=9F die Variable innerhalb des Kontexts der ISR= =C3=BCberhaupt nicht ge=C3=A4ndert wird (aus welchen Gr=C3=BCnden er das auch immer mei= nt).

Ohne den kompletten Code gesehen zu haben, kommt das nat=C3=BCrlich eine= m Ratespiel gleich und Compilerbugs kann man selbstredend auch nicht ausschlie=C3=9Fen.

tigen Code erzeugen.

Das kommt darauf an.(tm)

Einerseits wollen die Entwickler immer hochoptimierende Compiler, weil s= ie's ja per handoptimiertem Assembler selbst viel besser k=C3=B6nnten und and= ererseits zicken sie dann rum, wenn ihnen der Compiler Variablen in Register schie= bt und nachher feststellt, da=C3=9F das danach kein Mensch mehr braucht und= der Optimierer das Gelumpe komplett wegschmei=C3=9Ft. ;)

handlers

m=C3=B6glicherweise

Denkbar. W=C3=A4re nicht das erste Mal.

Vinzent.

--

f u cn rd ths, u cn gt a gd jb n cmptr prgrmmng.
Reply to
Vinzent Hoefler

nie

er die

mal

einer

en

Ein Interrupt handler ist aber keine normale Funktion. Und der Compiler muss das wissen, ansonsten fliegt das Programm auf die Schnauze. Man muss hier also schon mit einer Sonderbehandlung rechnen.

die

Im OP steht, der Interrupt handler selbst beschreibt die Variable. Es koennten aber bestimmt auch 2 Interrupt handler die Variable gemeinsam benutzen, das Problem waere wohl das gleiche.

Micha

--

Das Lesen von *Sektoren* gehoert nicht zum "ueblichen" Gebrauch einer
Festplatte. Die *Dateien*, um die es sich hier handelt, [...]
                                        Hans-Peter Diettrich in dchlf
Reply to
Michael Baeuerle

Jein: je nach Plattform *ist* das eine normale Funktion (dann wird das von einem Assembler-Stub aufgerufen), oder aber der einzige Unterschied besteht darin, daß der Codegenerator anderen Prolog/Epilog erzeugt und ein paar Register mehr rettet. Der COmpiler kann aber so oder so nicht wissen, ob das Teil aufgerufen wird oder nicht - sobald es nicht "static" ist, muß er es erstmal ins .o-File übernehmen.

Das wäre dann eine komplett andere Situation. Wenn 2 getrennte Interrupthandler wechselweise auf die Variable zugreifen, ist volatile u.U. nötig - aber auch nur dann, wenn die sich gegenseitig unterbrechen können.

cu Michael

Reply to
Michael Schwingen

Am 26.06.2011 23:55, schrieb Michael Schwingen:

Also ich hätte hier folgendes fiktives Szenario:

uint8_t flag = 0;

ISR(TIMER0_COMPA_vect) {

if ( PINA == 12 ) flag = 42;

}

int main (void) {

init_stuff();

while(1) {

if ( flag == 42 ) {

do_something();

} }

return 0;

}

Da wird flag "wegoptimiert" und muss als volatile deklariert werden.

Reply to
Heiko Lechner

Wenn main() und Interrupt handler gemeinsam die Variable benutzen braucht man sowieso volatile. Selbst wenn sie nicht wegoptimiert wird funktioniert es sonst meistens nicht wie gewuenscht. Hier wird z.B. mit

-O3 fuer y eine Registerkopie angelegt und y in der Schleife gar nicht mehr angefasst:

---------------------------------------------------------------------- uint8_t y = 0;

ISR(INT6_vect) { if (y > 5) PORTB = 0xFF; }

int main(void) { uint8_t i;

for (i = 0; i < 10; ++i) { while (PINC & 0x01); y += 1; } }

---------------------------------------------------------------------- PORTB wird also nicht bei y==6 gesetzt sondern fruehestens wenn die Schleife endet:

----------------------------------------------------------------------

00000134 : 134: cf ef ldi r28, 0xFF ; 255 136: d1 e2 ldi r29, 0x21 ; 33 138: de bf out 0x3e, r29 ; 62 13a: cd bf out 0x3d, r28 ; 61 13c: 80 91 00 02 lds r24, 0x0200 140: 90 e0 ldi r25, 0x00 ; 0 142: 30 99 sbic 0x06, 0 ; 6 144: fe cf rjmp .-4 ; 0x142 146: 8f 5f subi r24, 0xFF ; 255 148: 9f 5f subi r25, 0xFF ; 255 14a: 9a 30 cpi r25, 0x0A ; 10 14c: d0 f3 brcs .-12 ; 0x142 14e: 80 93 00 02 sts 0x0200, r24 152: 80 e0 ldi r24, 0x00 ; 0 154: 90 e0 ldi r25, 0x00 ; 0 156: 0c 94 ad 00 jmp 0x15a ; 0x15a

----------------------------------------------------------------------

Auch problematisch ist es, wenn sich die Interrupt handler in einem eigenen File interrupt.o befinden und dieses wiederum Teil einer Library os.a ist. Das gegen os.a gelinkte Binary enthaelt dann ohne Workaround erstmal gar keine Interrupt handler.

Micha

Reply to
Michael Baeuerle

[...]

Das ist eine völlig andere Situation als hier bisher diskutiert - Du mischst Zugriffe aus main und Interrupt-Handler, dann ist volatile auf jeden Fall nötig.

Nochmal: im Originalposting ging es darum, daß er die Variable *nur*

*innerhalb* des Interrupthandlers benutzt!

cu Michael

Reply to
Michael Schwingen

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.