Lesezugriff in ISR - atomar notwendig oder nicht

Hallo,

bin mir aktuell nicht sicher ob die Zuweisung des Rechenergebnis an wert in loop atomar erfolgen muss?
Es könnte ja sein das während der Zuweisung ein Interrupt auftritt und nur ein Byte statt zwei in wert "übergeben" wurde. Ich war bisher der Meinung das atomarer Zugriff nur notwendig ist wenn wert in einer ISR verändert wird

Ist atomar immer notwendig sobald sobald schreibend oder lesend in einer ISR eine variable benutzt wird oder nur schreibend? Für volatile ja. Für atomar ist die Frage?

volatile unsigned int wert;

void loop(void)
{
  // atomar ?
  wert = ... Berechungen ...
}

ISR(TIMER1_COMPA_vect)
{
  OCR1A = wert;
}

Doc_Arduino:
wert "übergeben" wurde. Ich war bisher der Meinung das atomarer Zugriff nur notwendig ist wenn wert in einer ISR verändert wird

Richtig. Innerhalb der ISR sind Interrupts (im Normalfall) gesperrt, so dass der Wert innerhalb der ISR problemlos gelesen werden kann. Wenn die ISR ihn nicht ändert, kann er im loop auch normal belegt werden.
Korrektur: Es kann die Änderung im loopü unterbrochen werden und damit nur 1 Byte gesetzt sein.
Richtig ist: das volatile ist trotzden notwendig.

Gruß Tommy

Atomar: Du änderst einen Wert, der in der ISR gelesen wird,
Volatile: Du liest einen Wert, der in der ISR geändert wird.

Da würde ich noch mal darüber nachdenken.

Gruß Tommy

Hallo,

ich meinte das etwas anders. Quasi der umgedrehte Fall.
Wenn in loop die Zuweisung des Rechenergebnisses an wert stattfindet und wert aus mehreren Bytes besteht, kann dann die ISR diese Zuweisung unterbrechen und sich einen verstümmelten wert holen? Weil die Zuweisung vielleicht? noch nicht abgeschlossen war. Oder wird eine Zuweisung niemals unterbrochen, auch von einer ISR nicht?

@ Microbahner. Mit der Aussage bin ich nicht einverstanden, weil komplett falsch,

Die ISR ändert den Wert von wert ja nicht. Also hat sie auf die Zuweisung keinen Einfluss.
Jetzt wo Du nochmal darauf hinweist: Es könnte aber passieren, dass sie nur einen Teil der Änderung mitbekommt, weil sie zwischendrin liest. Also doch atomar. Ich korrigiere damit meine 1. Aussage.

Gruß Tommy

Doc_Arduino:
Wenn in loop die Zuweisung des Rechenergebnisses an wert stattfindet und wert aus mehreren Bytes besteht, kann dann die ISR diese Zuweisung unterbrechen und sich einen verstümmelten wert holen?

Genau das kann die ISR. Und deshalb muss man das atomar machen - sprich den Interrupt während der Zuweisung unterbinden. Also wenn Du im 'normalen' Programmablauf einen Wert ( mit Size>1Byte ) änderst, den die ISR liest.

Und 'volatile' ist ein Hinweis an den Compiler, dass sich ein Wert auch ausserhalb seines 'sichtbaren Bereiches' ändern kann. Das betrifft dann den Optimieralgorithmus und ist wichtig für alle Werte, die die ISR ändert, und die im normalen Sketch verwendet werden.

Doc_Arduino:
@ Microbahner. Mit der Aussage bin ich nicht einverstanden, weil komplett falsch,

Dann würden meine MobaTools vorn und hinten nicht funktionieren.
Vielleicht solltet ihr nochmal drüber nachdenken :wink:

MicroBahner:
Volatile: Du liest einen Wert, der in der ISR geändert wird.

Er kann in der ISR auch nur gelesen werden und muss trotzdem volatile sein..

MicroBahner:
Atomar: Du änderst einen Wert, der in der ISR gelesen wird,

Du liest einen mehrbytigen Wert im loop und musst das trotzdem atomar tun

Gruß Tommy

Hallo,

genau die Frage ist, kann ein Interrupt eine Mehrbytezuweisung die außerhalb von ihm stattfindet unterbrechen oder nicht? Das wäre die Kurzform meines Anliegens. Ich hatte nochmal hier nachgelesen, wurde aber nicht schlau daraus wie das in meinem Fall ist.
https://www.mikrocontroller.net/articles/Interrupt#Interruptfeste_Programmierung

Praktisch kann ja ein Interrupt immer dazwischen funken sobald irgendein Befehl mehr als ein Takt dauert.
Gut, mach ich das atomar. Danke für die schnellen Antworten.

Ich fasse zusammen. volatile und atomar immer, egal ob im Interrupt lesend oder schreibend verwendet.
Kann man sich auch leichter merken ohne nochwas unterscheiden zu dürfen. :wink:

@ Microbahner.
Deine erste Antwort ist da leider missverständlich. Ich weiß nicht ob sie allgemeingültig sein sollte oder auf meine Frage direkt zugeschnitten. Wenn allgemeingültig dann wäre sie falsch.
Wenn eine Variable in einer ISR geändert wird (also schreibend), dann muss sie außerhalb der ISR auf jeden Fall atomar behandelt werden. Du sprachst nur vom lesen. Solche Fehler findet man verdammt schwer.

Wenn das in der ISR nur gelesen wird, ist volatile vollkommen überflüssig - es behindert nur den Optimieralgorithmus. Volatile heißt nur, dass sich der Compiler den Wert bei mehrfacher Verwendung immer aus dem RAM holen muss, und ihn nicht in Registern zwischenspeichern kann. Wenn die ISR den Wert nur liest, kann der Compiler den Wert zwischenspeichern, das stört die ISR nicht.

Tommy56:
Du liest einen mehrbytigen Wert im loop und musst das trotzdem atomar tun

Da hast Du allerdings recht, wobei das volatile auch bei 1-bytigen Werten wichtig ist. In meiner Aussage oben fehlte in der Tat also noch eine Zeile.

Hallo,

ich hab das bisher so verstanden:

Volatile: Wenn die Variable in beiden vorkommt.
Atomar: wenn die Variable grösser 1 byte ist , in der ISR geschrieben wird und ausserhalb gelesen wird.

Allerdings bei einem 8266 oder ESP32 erfogt da der Lesezugriff auch byteweise je Takt. Wenn nein dann wäre ja Atomar nicht notig ?

Heinz

Nachtrag:
https://www.arduino.cc/reference/de/language/variables/variable-scope--qualifiers/volatile/

Doc_Arduino:
@ Microbahner.
Deine erste Antwort ist da leider missverständlich. Ich weiß nicht ob sie allgemeingültig sein sollte oder auf meine Frage direkt zugeschnitten. Wenn allgemeingültig dann wäre sie falsch.

Zumindest unvollständig, und damit allgemein gesehen falsch. Also nochmal:

Atomar: Du verwendest einen (mehrbytigen) Wert, der auch in der ISR verwendet wird.
Werte die die ISR nur liest, kann man auch außerhalb der ISR nichtatomar lesen.

Volatile: Du liest einen Wert, der in der ISR geändert wird ( egal ob ein- oder mehrbytig ).

MicroBahner:
Dann würden meine MobaTools vorn und hinten nicht funktionieren.
Vielleicht solltet ihr nochmal drüber nachdenken :wink:

Ich habe da reichlich drüber nachgedacht!

Variablen, Strukturen, müssen als volatile deklariert werden, wenn auf sie von mehr als einem "Programmstrang" zugegriffen wird.
z.B. Hauptprogramm und ISR
Oder auch bei 2 Kern µC, wie dem ESP32 oder K210.
Egal, wer liest oder schreibt

"Atomic", muss sein, wenn der Zugriff auf die Daten mehr als 1 Asm Statment benötigt, also unterbrochen werden könnte.
Egal, wer liest oder schreibt, alle diese Zugriffe müssen verriegelt werden.
Da in AVR ISR die Interrupts sowieso erstmal gesperrt sind, meist nur im Hauptprogramm.
Anders siehts wieder bei Multicore aus.

Hallo,

atomar ist geklärt. :slight_smile:
Ich war bis heute leider immer nur bei Veränderung in einer ISR (oder außerhalb des Programmflusses) davon ausgegangen, eben dann atomar verwenden zu müssen. Ab jetzt auch bei Lesezugriffen in einer ISR (oder außerhalb des Programmflusses).

zu volatile las ich das schon immer so "lesend wie schreibend"
https://www.mikrocontroller.net/articles/FAQ#Was_hat_es_mit_volatile_auf_sich

Danke Euch.

Hab ich ja wieder was angerichtet ... :grin:

Hi

Wenn in der ISR nur gelesen wird - der Wert wird eh neu aus dem Speicher ausgelesen - da zuvor nicht bekannt ist, was in den Registern steht, müssen eh sämtliche Variablen neu geholt werden.
Da sehe ich nur Nachteile, hier volatile zu benutzen (wobei ich Das bis Jetzt wohl gemacht hätte) - der eigentliche Sketch 'kennt' ja Seinen Variablenwert und kann Diesen auch 'so lange, wie's halt dauert' in Registern halten - die ISR ändert Da ja Nichts dran.

Sobald die ISR was schreibt, muß der Wert im Sketch selber immer neu gelesen werden - kann sich ja IMMER geändert haben.
Da der Wert der Variable nicht in den Registern gehalten werden KANN, braucht eine volatile Variable deutlich länger (nur, wen nSie nicht eh neu gelesen wird, da Sie schon 'ewig' nicht mehr in Gebrauch war - 32 Register mit je einem Byte reichen auch nicht für Alles - auch haben einige der Register besondere Funktionalitäten - zumindest bei den AVR.

MfG

Wenn in der ISR nur gelesen wird - der Wert wird eh neu aus dem Speicher ausgelesen - da zuvor nicht bekannt ist, was in den Registern steht, müssen eh sämtliche Variablen neu geholt werden.
Da sehe ich nur Nachteile, hier volatile zu benutzen.....

Wenn das Hauptprogramm optimierend kompiliert wird, muss die Variable volatile sein, damit das Hauptprogramm sie "wirklich" in den Speicher schreibt.
Sonst steht alter Müll im Speicher, welcher dann von der ISR gelesen wird.

... verdammt ... in Der Richtung hast Du natürlich Recht.

Hallo,

Doc_Arduino:
genau die Frage ist, kann ein Interrupt eine Mehrbytezuweisung die außerhalb von ihm stattfindet unterbrechen oder nicht? Das wäre die Kurzform meines Anliegens. Ich hatte nochmal hier nachgelesen, wurde aber nicht schlau daraus wie das in meinem Fall ist.
Interrupt – Mikrocontroller.net

Praktisch kann ja ein Interrupt immer dazwischen funken sobald irgendein Befehl mehr als ein Takt dauert.
Gut, mach ich das atomar. Danke für die schnellen Antworten.

Ein Befehl wird üblicherweise nicht unterbrochen durch einen Interrupt. Der wird erst nach Ende des einen Befehls abgearbeitet.
Ein Befehl ist aber der ASM-Befehl des C. Wenn Du also z.B. auf einem AVR mit einen der 16Bit-Befehle einen 16Bit-Wert aus dem Ram holst, bleibt der ungestört. Wenn Du aber mit Byte-Befehlen die Teilwerte holst und zusammenbastelst, kannst er nach jeder ASM-Anweisung gestört werden.
Atomar sperrt letztlich nur die Interrupts bis zum Ende des Blocks.
Du kannst auch selbst das Statusregister zwischenspeichern, die Interrupts sperren , Deinen Kram machen und das Statusregister zurückschreiben. Das geht so aber nur bei AVR, das Problem ist, ein CLU() vor und SEI() nach dem Block alleine kann den gesetzten IRQ-Zustand ändern. Wenn der vorher gesperrte war, wäre er danach erlaubt... Deshlab die atomic-Geschichte, die kümmert sich um die Spezialitäten der jeweiligen Architektur.

Gruß aus Berlin
Michael

amithlon:
Wenn Du also z.B. auf einem AVR mit einen der 16Bit-Befehle einen 16Bit-Wert aus dem Ram holst, bleibt der ungestört.

Welche 16 Bit Befehle meinst du da?