Wenn mit einer Variable in einem Interrupt gearbeitet wird, sprich die
Variable inkrementiert wird, muss diese dann auch volatile sein oder
nur, wenn wirklich die Variable auch irgendwo anders im main verwendet
wird?
Ich denke, dass erstere macht keinen Sinn, die Variable im Interrupt
alleine als volatile zu setzen.
Sorry, nochmals konkret
b ist die Variable, die im Interrupt inkrementiert wird.
im main passiert Folgendes:
a = b;
Sie wird zwar nicht verändert aber gelesen. Muss b immer noch nicht
volatile sein?
Jonas schrieb:> Dann ist b ja irgendwo im Main deklariert und muss meiner Meinung nach> volatile sein.
Muss es.
Andernfalls ginge der Compiler davon aus, dass die Variable nicht
verändert werden kann und würde evtl. die beabsichtigte Funktionalität
wegoptimieren.
Jens schrieb:> Sie wird zwar nicht verändert aber gelesen. Muss b immer noch nicht> volatile sein?
Besser, du deklarierst b als volatile, denn sonst könnte es sein, dass
im main() die Variable nur 1x eingelesen und dann mit der lokalen Kopie
weitergearbeitet wird.
Du sagst dem Compiler mit volatile, dass die Variable sich ausserhalb
der Routine ändern kann (wie z.B. ein Hardwarezähler oder ein
Statusflag). Und genau das passiert mit deiner Variablen ja auch.
foobar schrieb:> Warning: bei AVR sind Zugriffe auf uint16 nicht atomar
Bei einem STM32 dagegen schon... ;-)
Man kann das i.A. auf alle Architekturen ausdehnen, in denen die
Prozessorwortbreite (oder ggfs. auch nur die Busbreite) nicht zur Breite
der Variablen passt.
Und ich hatte letzthin auch den Fall, da meinte sogar auf einem
32-Bit-System mit 32 Bit Bus der Compiler, es wäre schlauer, die 4
nötigen Bytes des Integers nacheinander einzeln einzulesen. Und sich
dabei vom Interrupt unterbrechen zu lassen... :-O
Lothar M. schrieb:> es wäre schlauer, die 4> nötigen Bytes des Integers nacheinander einzeln einzulesen.
Naja....
Bei einem Misalignment kann das schon sein, aber sonst eher unüblich.
Arduino Fanboy D. schrieb:> Lothar M. schrieb:>> es wäre schlauer, die 4>> nötigen Bytes des Integers nacheinander einzeln einzulesen.>> Naja....> Bei einem Misalignment kann das schon sein, aber sonst eher unüblich.
-Wie meinst du das mit Misalignment? Kannst du ein Beispiel geben?
Vielen Dank
Lothar M. schrieb:> da meinte sogar auf einem> 32-Bit-System mit 32 Bit Bus der Compiler, es wäre schlauer, die 4> nötigen Bytes des Integers nacheinander einzeln einzulesen.
Lass mich raten: Der Integer war in einem struct, welcher mit "packed"
markiert war, und du hast -mno-unaligned-access angegeben :-)
Niklas G. schrieb:> Lass mich raten: Der Integer war in einem struct, welcher mit "packed"> markiert war, und du hast -mno-unaligned-access angegeben :-)
Nein, es war komplizierter und hing auch noch vom Optimierungsgrad ab.
Bei der Debug-Version trat der Fehler "zum Glück" nicht auf :-/
OK, es war eigentlich ein Compilerfehler vereinfacht nur in dem Sinn,
dass er auf ein nicht-cachefähiges Statuswort wie auf eine
RAM-Speicherzelle zugriff. Und dann natürlich 4 Zugriffe statt nur 1 auf
das Statusregister machte.
Lothar M. schrieb:> Bei der Debug-Version trat der Fehler "zum Glück" nicht auf :-/
Ja, diese Fehler machen am meisten Spaß!
Lothar M. schrieb:> Und dann natürlich 4 Zugriffe statt nur 1 auf> das Statusregister machte.
Aber wieso? Klingt komisch, eigentlich sollten Compiler so etwas nur tun
um unaligned Speicherzugriffe zu vermeiden.
1. Der Sinn von volatile ist es, den Compiler darüber zu informieren,
dass sich der Inhalt einer Speicherstelle ändern kann, ohne dass es für
den Compiler aus dem Programmablauf ersichtlich ist. Ansonsten darf der
Compiler Deinen Code nach Belieben so optimieren, solange der für ihn
ersichtliche Programmablauf gewahrt bleibt.
Mit volatile sagst Du dem Compiler: "Pass auf, das Ding kann sich
jederzeit ohne Dein Zutun verändern."
2. Atomarer Zugriff bedeutet, dass der Inhalt einer Variable während des
Zugriffs nicht verändert wird. Das ist dann relevant, wenn ein Zugriff
mehr als einen Maschinenbefehl benötigt und sich der Inhalt der Variable
zwischen den Maschinenbefehlen ändern kann (z.B. weil es ein
HW-Rergister ist oder weil ein Interrupt dazwischen kommt).
Atomarer Zugriff wird erreicht, indem bestimmt Zugriffsprotokolle
vorhanden sein müssen, die eingehalten werden.
Z.B. HW-Register in einer bestimmten Reihenfolge lesen, oder z.B.
Variablen aus Interrupt-Service-Routinen nur unter Interruptsperre lesen
etc.