Forum: Mikrocontroller und Digitale Elektronik volatile Variablen


von Mark U. (residuum)


Lesenswert?

Guten Abend,

habe ich mal eine Verständnisfrage:

Wenn eine Variable im Interrupt geändert wird, deklariere ich sie 
volatile.

Wie ist es, wenn eine Variable im Interrupt nur gelesen wird, muss sie 
dann auch volatile sein? Eigentlich nicht, oder?

Danke schon mal.
-Markus

: Verschoben durch Moderator
von W.S. (Gast)


Lesenswert?

Ach, das 'volatile' dient NUR dazu, daß der Compiler die von dir 
geschriebenen Zugriffe auf diese so gekennzeichnete Variable nicht 
wegoptimiert, weil er z.B. den Wert von einem früheren Zugriff her noch 
in einem Register hat.

Das ist alles.

Manchmal braucht man sowas auch zum nur schreiben. Es gibt 
Peripherie-Cores, die erst dann weitermachen, wenn man z.B. ihr 
Statusregister ausgelesen hat. Wenn man jedoch sowas ausliest und in 
eine Variable packt, die man garnicht weiter benutzt, dann neigen manche 
Compiler dazu, die ganze Ausleserei wegzuoptimieren. Dagegen hlft dann 
auch das volatile bei der Dummy-Variablen.

W.S.

von Mark U. (residuum)


Lesenswert?

Danke mal für die Anwort.

Es ist also schon so, dass bei nur lesendem Zugriff auf das volatile 
verzichtet werden kann. Ich verwende hier übrigens den AVR-GCC für einen 
ATmega-Controller.

von holger (Gast)


Lesenswert?

>Es ist also schon so, dass bei nur lesendem Zugriff auf das volatile
>verzichtet werden kann.

Nö, bei lesendem Zugriff weiss der Compiler ja nicht
das die Variable in einem Interrupt verändert werden kann.
Wenn das so ist benötigt er das volatile zwingend.

von Toxic (Gast)


Angehängte Dateien:

Lesenswert?

Auszug aus einem "FAQ" - siehe Anhang

von Sebastian R. (basti72)


Lesenswert?

Markus E. schrieb:
> Es ist also schon so, dass bei nur lesendem Zugriff auf das volatile
> verzichtet werden kann. Ich verwende hier übrigens den AVR-GCC für einen
> ATmega-Controller.

Nein. Es ist genau wie W.S. schrieb:

"das 'volatile' dient NUR dazu, daß der Compiler die von dir
geschriebenen Zugriffe auf diese so gekennzeichnete Variable nicht
wegoptimiert, weil er z.B. den Wert von einem früheren Zugriff her noch
in einem Register hat."

Ob lesend oder schreibend ist dafür völlig egal.

Wenn du z.B. eine Stelle im Code hast wie diese:

while( bFlagWurdeGesetztInterrupt );

Dann optimiert der Compiler wahrscheinlich den lesenden Zugriff auf die 
Variable und liest ihren Wert nicht jedes mal erneut aus dem Speicher 
aus.

Durch die deklaration als "volatile" sagst du dem Compiler, dass er 
nicht optimieren soll und er wird Code erzeugen, der jedes mal erneut 
den Speicher der Variable einlesen und testen wird.

Und natürlich optimiert der Compiler auch nur, wenn die Optimierungen 
überhaupt aktiv sind. (Also z.B. nicht wenn im Atmel-Studio die 
"Debug"-Version aktiv ist.)


Mein Tipp: Wenn du unsicher bist, verwende einfach auf jeden Fall 
"volatile" in der Deklaration. Das kostet ein wenig mehr Speicher und 
Performance, aber ersparrt dir Probleme die du nur ganz schwer als 
"fehlendes volatile" erkennst.

Gruß
Basti

von Ingo (Gast)


Lesenswert?

Im Debug ist doch O1 standardmäßig eingeschaltet! Und es hinder dich 
doch niemand auf Os oder O2 zu gehen!

von Mark U. (residuum)


Lesenswert?

Aus Unsicherheit habe ich schon alle Variablen, die irgendwie in der ISR 
genutzt werden volatile deklariert.

Zum Verständnis habe ich diese Frage hier gestellt.

Wie ist es im umgekehrten Fall, wenn eine Variable in der ISR gelesen 
wird, die nur im Hauptprogramm geändert wird:

ISR(){
while( bFlagWurdeInMainGesetzt );
}

Dann ist für bFlagWurdeInMainGesetzt eigentlich kein volatile nötig, 
oder?

@Gast: Sorry, war mir nicht klar.
Werde für meine nächste Frage eine andere Kategorie wählen.

von Sebastian V. (sebi_s)


Lesenswert?

Markus E. schrieb:
> ISR(){
> while( bFlagWurdeInMainGesetzt );
> }

So macht das natürlich überhaupt keinen Sinn. Da hast du eine tolle 
Endlosschleife gebaut weil deine main Funktion nie wieder dran kommt und 
das Flag ändern könnte. Wenn du in der ISR eine Variable aber nur einmal 
ließt kann man meiner Meinung nach das volatile weglassen, da mir keine 
Möglichkeit einfällt wie der Compiler den Wert irgendwo sichern könnte. 
Also sowas wie:
1
ISR()
2
{
3
  if(someFlag)
4
    doX();
5
  else
6
    doY();
7
}

von Peter II (Gast)


Lesenswert?

Markus E. schrieb:
> Dann ist für bFlagWurdeInMainGesetzt eigentlich kein volatile nötig,
> oder?

doch, weil sei eventuell im Hauptprogramm gar nicht in dem Ram 
geschrieben wird sondern im Register bleibt.


das volatile ist auch nicht für den code in der ISR sondern für den code 
im Hauptprogramm. Der code in der ISR wird durch das volatile sogar 
schlechter.

von Sebastian V. (sebi_s)


Lesenswert?

Peter II schrieb:
> doch, weil sei eventuell im Hauptprogramm gar nicht in dem Ram
> geschrieben wird sondern im Register bleibt.

Gut das könnte natürlich sein. Außer bei konstruierten Beispielen aber 
vermutlich eher unwahrscheinlich, dass eine Variable nie aus dem 
Register in den RAM zurück geschrieben wird.

von Ralf D. (rad)


Lesenswert?

Immer und immer und immer wieder:

volatile hat nix mit atomar zu tun!

Für atomare Zugriffe gibts in C kein Schlüsselwort - da hilfts auch 
nichts, den Sourcecode mit x-fach redundantem volatile zuzupflastern.

: Bearbeitet durch User
von Peter II (Gast)


Lesenswert?

Ralf D. schrieb:
> volatile hat nix mit atomar zu tun!

schön und gut, aber wo kam denn in den thread atomar vor?

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Markus E. schrieb:
> wenn eine Variable in der ISR gelesen wird, die nur im
> Hauptprogramm geändert wird:
>
> ISR(){
> while( bFlagWurdeInMainGesetzt );
> }
>
> Dann ist für bFlagWurdeInMainGesetzt eigentlich kein volatile nötig,
> oder?

Doch.

Beispiel:
1
extern unsigned char x;
2
3
void f (void)
4
{
5
    while (1)
6
        x++;
7
}

Das übersetzt avr-gcc korrekt zu
1
f:
2
.L2:
3
  rjmp .L2
Wenn also in einer ISR auf x geprüft wird, wird sich der Wert nie 
ändern.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Sebastian V. O. schrieb:
> Peter II schrieb:
>> doch, weil sei eventuell im Hauptprogramm gar nicht in dem Ram
>> geschrieben wird sondern im Register bleibt.
>
> Gut das könnte natürlich sein. Außer bei konstruierten Beispielen
> aber vermutlich eher unwahrscheinlich, dass eine Variable nie aus
> dem Register in den RAM zurück geschrieben wird.

Selbst wenn sie zurückgeschrieben wird, bedeutet das nicht, dass das 
volatile überflüssig ist.

Beispiel:
1
#include <util/delay.h>
2
3
extern unsigned char count;
4
5
void wait_and_count (void)
6
{
7
    do
8
        _delay_loop_1 (100);
9
    while (++count);
10
}

Wenn nun eine ISR count liest, wird sie nie einen anderen Wert als 0 
erhalten, denn avr-gcc übersetzt das Beispiel zu:
1
wait_and_count:
2
  lds r24,count
3
.L2:
4
  ldi r25, 100
5
1:
6
  dec r25
7
  brne 1b
8
  subi r24, -1
9
  brne .L2
10
  sts count,__zero_reg__
11
  ret

von Rolf M. (rmagnus)


Lesenswert?

W.S. schrieb:
> Manchmal braucht man sowas auch zum nur schreiben. Es gibt
> Peripherie-Cores, die erst dann weitermachen, wenn man z.B. ihr
> Statusregister ausgelesen hat. Wenn man jedoch sowas ausliest und in
> eine Variable packt, die man garnicht weiter benutzt, dann neigen manche
> Compiler dazu, die ganze Ausleserei wegzuoptimieren. Dagegen hlft dann
> auch das volatile bei der Dummy-Variablen.

Das volatile muß zwingend zum Register. Bei der Dummy-Variablen hilft es 
nicht unbedingt. Eigentlich braucht man die nicht mal, wenn das Register 
volatile ist. Wenn du die Dummy-Variable volatile machst, sorgt das nur 
dafür, daß diese auf jeden Fall geschrieben wird, aber nicht zwingend, 
daß das Register auch an der Stelle gelesen wird. Wurde das Register 
vorher in der Funktion schon mal gelesen oder geschrieben, kann der 
Compiler auch den alten Wert nochmal hernehmen und in die Dummy-Variable 
schreiben, ohne das Register nochmal zu lesen.

Peter II schrieb:
> das volatile ist auch nicht für den code in der ISR sondern für den code
> im Hauptprogramm. Der code in der ISR wird durch das volatile sogar
> schlechter.

Das volatile ist für beides.

Sebastian V. O. schrieb:
> Peter II schrieb:
>> doch, weil sei eventuell im Hauptprogramm gar nicht in dem Ram
>> geschrieben wird sondern im Register bleibt.
>
> Gut das könnte natürlich sein. Außer bei konstruierten Beispielen aber
> vermutlich eher unwahrscheinlich, dass eine Variable nie aus dem
> Register in den RAM zurück geschrieben wird.

Kann aber je nach Code passieren.

Ralf D. schrieb:
> Für atomare Zugriffe gibts in C kein Schlüsselwort

Doch: http://en.cppreference.com/w/c/atomic

von Andreas R. (andreasr)


Lesenswert?

Nine ways to break your systems code using volatile:
http://blog.regehr.org/archives/28

von pavarotti (Gast)


Lesenswert?

Beim Lesen des threads kam mir diese Geschichte in den Sinn: 
http://www.ariva.de/forum/Ephraim-Kishon-Juedisches-Poker-250692

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.