Forum: Mikrocontroller und Digitale Elektronik Interrupt-Synchronisation


von Kevin (Gast)


Lesenswert?

Hallo zusammen,

angenommen man habe einen µC auf dem kein OS läuft. Es gibt ein 
Hauptprogramm welches Berechnungen vornimmt und in bestimmten Variablen 
abspeichert. Das Programm ist durch Interrupt unterbrechbar. Im 
Interrupt werden die Variablen gelesen. Auch der Interrupt kann 
Berechnungen vornehmen, die im Hauptprogramm gelesen werden. Weiterhin 
nehme man an es gibt keinerlei Synchronisation zwischen Hauptprogramm 
und Interrupt(Semaphore/Mutexe...) Was ist unter diesen Voraussetzungen 
das schlimmste was passieren kann?

Gruß
Kevin

von Patrick L. (Firma: S-C-I DATA GbR) (pali64)


Lesenswert?

Dazu setzt man sogenannte Flags die anzeigen ob Berechnungen im Gange 
sind oder abgeschlossen sind.

Sonnst :
Kevin schrieb:
> Was ist unter diesen Voraussetzungen
> das schlimmste was passieren kann?

Absolutes Chaos und undefinierte Ergebnisse ....;-)

: Bearbeitet durch User
von Teo D. (teoderix)


Lesenswert?

Patrick L. schrieb:
> undefinierte Ergebnisse ...

https://www.mikrocontroller.net/articles/Interrupt#Interruptfeste_Programmierung


Patrick L. schrieb:
> Dazu setzt man sogenannte Flags die anzeigen ob Berechnungen im Gange
> sind oder abgeschlossen sind.

Meist reicht es, die Unterbrechungen zu unterbinden.
Was in der ISR berechnet wird, braucht halt ein Volatile, um nicht 
versehentlich, veraltete Registerinhalte zu verarbeiten.

von Wilhelm M. (wimalopaan)


Lesenswert?

Kevin schrieb:
> Hallo zusammen,
>
> angenommen man habe einen µC auf dem kein OS läuft. Es gibt ein
> Hauptprogramm welches Berechnungen vornimmt und in bestimmten Variablen
> abspeichert. Das Programm ist durch Interrupt unterbrechbar. Im
> Interrupt werden die Variablen gelesen. Auch der Interrupt kann
> Berechnungen vornehmen, die im Hauptprogramm gelesen werden. Weiterhin
> nehme man an es gibt keinerlei Synchronisation zwischen Hauptprogramm
> und Interrupt(Semaphore/Mutexe...) Was ist unter diesen Voraussetzungen
> das schlimmste was passieren kann?

Bei Assemblerprogrammierung einfach inkonsistente Daten.
Bei C/C++ bekommst Du UB noch dazu (was in diesem Fall aber mehr ein 
weiterer formaler Aspekt ist).

Da Du ja scheinbar schon etwas von der Thematik verstanden hast, ist mir 
der Hintergrund der Frage nicht ganz klar ...

von Kevin (Gast)


Lesenswert?

Patrick L. schrieb:
> Absolutes Chaos und undefinierte Ergebnisse ....;-)

Chaos klingt gut. Was ist mit undefiniert gemeint? Was wenn nur jeweils 
lesend der Zugriff erfolgt? Also nicht auf die gelesene Variable 
zurückgeschrieben wird. Was wäre hier der Worst Case?

von Oliver S. (oliverso)


Lesenswert?

Kevin schrieb:
> Was ist unter diesen Voraussetzungen
> das schlimmste was passieren kann?

Nichts. Außer, das Programm ist fehlerhaft, dann gibts Chaos. Das gilt 
aber für alle fehlerhaften Programme.

Du musst halt selber dafür sorgen, daß sich ISR und Hauptprogramm nicht 
gegenseitig verheddern. Die Stichworte dazu lauten volatile und atomic.

Oliver

von Kevin (Gast)


Lesenswert?

Wilhelm M. schrieb:
> Da Du ja scheinbar schon etwas von der Thematik verstanden hast, ist mir
> der Hintergrund der Frage nicht ganz klar ...

Ich möchte verstehen unter welchen Bedingungen man eine Synchronisation 
braucht und wann nicht, ohne jetzt ins Detail zu gehen wie z.b. so eine 
Synchronisation aussehen muss.

von Wilhelm M. (wimalopaan)


Lesenswert?

Kevin schrieb:
> Wilhelm M. schrieb:
>> Da Du ja scheinbar schon etwas von der Thematik verstanden hast, ist mir
>> der Hintergrund der Frage nicht ganz klar ...
>
> Ich möchte verstehen unter welchen Bedingungen man eine Synchronisation
> braucht und wann nicht, ohne jetzt ins Detail zu gehen wie z.b. so eine
> Synchronisation aussehen muss.

Eine Synchronisation brauchst Du immer bei nebenläufigem Zugriff, wenn 
mindestens ein Schreiber dabei ist.
Je nach eingesetzter Sprache kann das dann unterschiedlich aussehen. Bei 
C/C++ wurde schon volatile als "Optimierungssperre" genannt. Das hat 
aber nichts mit Synchronisation zu tun. Weiterhin wird noch 
wechselseitiger Ausschluss benötigt. Das kannst Du durch atomics oder 
expliziter Syncho durch bspw. Mutexe erreichen.

von Kevin (Gast)


Lesenswert?

Wilhelm M. schrieb:
> wechselseitiger Ausschluss

benötigt man bei mehr als einen Schreiber, richtig?

von Wilhelm M. (wimalopaan)


Lesenswert?

Kevin schrieb:
> Wilhelm M. schrieb:
>> wechselseitiger Ausschluss
>
> benötigt man bei mehr als einen Schreiber, richtig?

Steht doch oben: mindestens einem Schreiber

von Teo D. (teoderix)


Lesenswert?

Kevin schrieb:
> Ich möchte verstehen unter welchen Bedingungen man eine Synchronisation
> braucht und wann nicht,

Immer wenn auf die Daten, aus dem Hautprogramm und einer ISR zugegriffen 
wird.
Das mag sich in einigen (seltenen) Fällen, von ganz alleine ergeben, 
aber deine Aufmerksamkeit wird hier immer benötigt. Das ganze also mal 
in ruhe, im Kopf durchspielen.

von Monk (roehrmond)


Lesenswert?

Kevin schrieb:
> Was ist unter diesen Voraussetzungen
> das schlimmste was passieren kann?

Dass du kaputte Zahlen verarbeitest.

Denn bei einem 32 Bit Integer würde ein (8 Bit) Mikrocontroller ganze 4 
Scheibzugriffe nacheinander im RAM machen. Wenn du dazwischen liest, 
bekommst du ein paar alte mit ein paar neuen Bits vermischt.

: Bearbeitet durch User
von Peter D. (peda)


Lesenswert?

Der Interrupt kann über ein Flag signalisieren, daß neue Daten verfügbar 
sind. Das Main muß sie dann atomar lesen, damit sie konsistent bleiben.
Sinnvoll legt man dazu ein Struct an.

von der_eine (Gast)


Lesenswert?

Servus,

kritisch sind stets Schreib- und Lesezugriffe, welche mehr als einen 
Assemblerbefehl benötigen.

Folgendes Szenario kann das vielleicht beschreiben:

Im Hauptprogramm wird eine 16-Bit Variable beschrieben (angenommen das 
teilt sich 2 Assemblerbefehle auf, High- und Low-Byte schreiben) und 
diese wird im Interrupt ausgelesen und "verarbeitet".

Es könnte folgendes passieren:
1. High-Byte wird geschrieben (Hauptprogramm)

2. Interrupt kommt
2.a. High-Byte (neu) wird im Interrupt gelesen
2.b. Low-Byte (alt) wird im Interrupt gelesen
2.c. Eine Mischung aus alt und neu wird verarbeitet - Möglicherweise 
Unfug
2.d. Interrupt beendet

3. Low-Byte wird geschrieben (Hauptprogramm)


Das gemeine ist, daß dieser Fehler wahrscheinlich nur ab und zu auftritt 
und dann auch nicht immer zu einem Fehler führt.

Die Lösung ist, sich das ganze sehr genau durchdenken. Allgemeine 
Lösungen wie "immer volatile davorschreiben" helfen da nur sehr bedingt. 
Es kommt immer auf den konkreten Fall und Architektur an.

Viel Erfolg

von Monk (roehrmond)


Lesenswert?

In dem Zusammenhang haben wir das oben genannte Volatile. Es verhindert 
aber nicht Konflikte bei gleichzeitigen Zugriff auf Mehr-byte Variablen. 
Da geht es um was anderes:

Man (auch der C Compiler) benutzt CPU Register so oft wie möglich, um 
langsamere RAM-Zugriffe zu vermeiden. Beispiel:
1
int zaehler;
2
3
void machwas_hundert_mal() 
4
{
5
    for (i:=0; i<100; i++)
6
    {
7
       mach_was();
8
       zaehler=zaehler+1;
9
    }
10
}

Hier wird die Variable "zaehler" im RAM nicht hundert mal geändert, 
sondern nur einmal nach dem Ende der Schleife. Sie wird auch nicht 
hundert mal gelesen.

Wenn du jetzt den "zaehler" in einem anderen Thread (Interrupt) ausliest 
während die for-Schleife läuft, bekommst du einen veralteten Wert. Wenn 
du den Zähler im anderen Thread änderst, geht diese Änderung am Ende der 
for-Schleife verloren, sie wird einfach überschrieben!

Volatile verhindert das.
1
volatile int zaehler;

Nun wird die Variable innerhalb der for-Schleife tatsächlich immer 
wieder aus dem RAM gelesen, erhöht und wieder zurück ins RAM 
geschrieben. Die Schleife läuft nun deutlich langsamer.

Dein "Problem" aus der Eingangsfrage ist übrigens weder Mikrocontroller 
spezifisch noch hängt es von der Programmiersprache ab. Jedes PC 
Programm ist ebenso betroffen.

: Bearbeitet durch User
von Kevin (Gast)


Lesenswert?

Steve schrieb:
> Kevin schrieb:
>> Was ist unter diesen Voraussetzungen
>> das schlimmste was passieren kann?
>
> Dass du kaputte Zahlen verarbeitest.
>
> Denn bei einem 32 Bit Integer würde ein (8 Bit) Mikrocontroller ganze 4
> Scheibzugriffe nacheinander im RAM machen. Wenn du dazwischen liest,
> bekommst du ein paar alte mit ein paar neuen Bits vermischt.

Das ist interessant. Daran hatte ich nicht gedacht. Kann man annehmen, 
das auf einem 32Bit Controller der Schreibzugriff auf eine (8/16/32 Bit) 
Variablen immer atomar erfolgt. Oder kann der Interrupt auch genau im 
Schreiben erfolgen?

von Kevin (Gast)


Lesenswert?

der_eine schrieb:
> kritisch sind stets Schreib- und Lesezugriffe, welche mehr als einen
> Assemblerbefehl benötigen.

Danke, beantwortet meine Frage siehe oben, schon ziemlich gut.

von Peter D. (peda)


Lesenswert?

Benutzt man das ATOMIC_BLOCK Macro wird der Zugriff auch nicht 
wegoptimiert, d.h. volatile mit seinen Nachteilen ist unnötig.

von Monk (roehrmond)


Lesenswert?

Kevin schrieb:
> Kann man annehmen, das auf einem 32Bit Controller der Schreibzugriff
> auf eine (8/16/32 Bit) Variablen immer atomar erfolgt.

Meistens, aber nicht immer. Denn die meisten 32 Bit CPUs können auch in 
kleineren Einheiten auf das RAM zugreifen. Ich bin nicht sicher, ob man 
sich darauf verlassen kann, dass 32 Bit Variablen immer am Stück gelesen 
und geschrieben werden. Hängt sicher auch vom Compiler und dessen 
Optionen ab, nicht nur von der CPU.

von Wilhelm M. (wimalopaan)


Lesenswert?

Peter D. schrieb:
> Benutzt man das ATOMIC_BLOCK Macro wird der Zugriff auch nicht
> wegoptimiert, d.h. volatile mit seinen Nachteilen ist unnötig.

Schaltet nur die Interrupts bei AVR ab. Trotzdem brauchst Du volatile.

von Εrnst B. (ernst)


Lesenswert?

Wilhelm M. schrieb:
> Schaltet nur die Interrupts bei AVR ab.

nicht nur. ATOMIC_BLOCK enthält auch ein
 _asm_ volatile ("" ::: "memory");

also eine memory barrier. d.H. alle Variablen, die im ATOMIC_BLOCK 
geändert werden, sind vor dem Re-Aktivieren der ISRs auch wirklich 
geschrieben.

von (prx) A. K. (prx)


Lesenswert?

Steve schrieb:
> Kevin schrieb:
>> Kann man annehmen, das auf einem 32Bit Controller der Schreibzugriff
>> auf eine (8/16/32 Bit) Variablen immer atomar erfolgt.
>
> Meistens, aber nicht immer. Denn die meisten 32 Bit CPUs können auch in
> kleineren Einheiten auf das RAM zugreifen. Ich bin nicht sicher, ob man
> sich darauf verlassen kann, dass 32 Bit Variablen immer am Stück gelesen
> und geschrieben werden. Hängt sicher auch vom Compiler und dessen
> Optionen ab, nicht nur von der CPU.

Probleme kann es bei Misaligmment geben, in gepackten Strukturen und in 
Bitfeldern.

von Kevin (Gast)


Lesenswert?

Danke schonmal an alle.

Ich habe mal nachgelesen.FreeRtos z.b., nutzt zur Synchronisation 
zwischen 2 Tasks Mutexe, jedoch zwischen Task und Interrupt Semaphore. 
Vielleicht kann man sich da was abgucken, wenn es nicht zu komplex 
implementiert ist.

von Kevin (Gast)


Lesenswert?

(prx) A. K. schrieb:
> Probleme kann es bei Misaligmment geben, in gepackten Strukturen und in
> Bitfeldern.

Was meinst du mit Misalignment?

von Teo D. (teoderix)


Lesenswert?

Oje, nu kloppen sich die Spezis die Köppe ein. Dabei will der TO doch 
nur Fahrradfahren lernen und nicht gleich mit nem Euro-Fighter, auf 
seine Spatzen losgehen....

von (prx) A. K. (prx)


Lesenswert?

Kevin schrieb:
> (prx) A. K. schrieb:
>> Probleme kann es bei Misaligmment geben, in gepackten Strukturen und in
>> Bitfeldern.
>
> Was meinst du mit Misalignment?

Wenn die 4 Bytes nicht an einer Adresse %4==0 liegen, die Maschine einen 
solchen Zugriff nicht zulässt und der Compiler deshalb daraus mehrere 
Zugriffe machen muss.

von Wilhelm M. (wimalopaan)


Lesenswert?

Kevin schrieb:
> Danke schonmal an alle.
>
> Ich habe mal nachgelesen.FreeRtos z.b., nutzt zur Synchronisation
> zwischen 2 Tasks Mutexe, jedoch zwischen Task und Interrupt Semaphore.
> Vielleicht kann man sich da was abgucken, wenn es nicht zu komplex
> implementiert ist.

Jetzt doch mit OS?

Wenn Du nicht in Assembler programmierst (also etwa C/C++), dann weißt 
Du nicht, wie ein Objektzugriff gemacht wird. Du musst also vom 
Schlimmsten ausgehen, und das ist dann eine RMW-Folge. Also etwas 
nicht-atomares.

Daher hast Du zwei Aufgaben:

1) Du musst Atomarität herstellen durch
1a) atomics (s.a. C/C++-Bibliothek), oder
1b) explizite kritische Bereiche mit wechselseitigem Ausschluss

und

2) Du musst den Compiler für die gemeinsam genutzten Datenstrukten am 
Optimieren hindern. Das macht man bei C/C++ durch volatile-Deklaration.

Bei den kritichen Bereichen musst Du noch zwischen bedingten und 
unbedingten KB unterscheiden. Für bedingte KB brauchst Du dann noch 
Bedingungsvariablen (ich meiner hier das Konzept, keine einfachen Flags 
oder so).

von (prx) A. K. (prx)


Lesenswert?

Teo D. schrieb:
> Oje, nu kloppen sich die Spezis die Köppe ein. Dabei will der TO doch
> nur Fahrradfahren lernen und nicht gleich mit nem Euro-Fighter, auf
> seine Spatzen losgehen....

Seine Fragen sind qualifiziert genug um ihn nicht als Spielkind zu 
behandeln.

: Bearbeitet durch User
von Kevin (Gast)


Lesenswert?

Wilhelm M. schrieb:
> Jetzt doch mit OS?

Jetzt doch mit OS?
Nein,  FreeRtos war in meiner Internetsuche nur recht weit oben ;-). Und 
es ist recht interessant implementiert.

Wilhelm M. schrieb:
> Bei den kritichen Bereichen musst Du noch zwischen bedingten und
> unbedingten KB unterscheiden.

Was ist KB?

von Wilhelm M. (wimalopaan)


Lesenswert?

Εrnst B. schrieb:
> Wilhelm M. schrieb:
>> Schaltet nur die Interrupts bei AVR ab.
>
> nicht nur. ATOMIC_BLOCK enthält auch ein
>  _asm_ volatile ("" ::: "memory");
>
> also eine memory barrier. d.H. alle Variablen, die im ATOMIC_BLOCK
> geändert werden, sind vor dem Re-Aktivieren der ISRs auch wirklich
> geschrieben.

Nö.
1
static __inline__ uint8_t __iCliRetVal(void)
2
{
3
    cli();
4
    return 1;
5
}
6
7
#define ATOMIC_BLOCK(type) for ( type, __ToDo = __iCliRetVal(); \
8
                         __ToDo ; __ToDo = 0 )

von Wilhelm M. (wimalopaan)


Lesenswert?

Kevin schrieb:
> Wilhelm M. schrieb:
>> Jetzt doch mit OS?
>
> Jetzt doch mit OS?
> Nein,  FreeRtos war in meiner Internetsuche nur recht weit oben ;-). Und
> es ist recht interessant implementiert.
>
> Wilhelm M. schrieb:
>> Bei den kritichen Bereichen musst Du noch zwischen bedingten und
>> unbedingten KB unterscheiden.
>
> Was ist KB?

Kritischer Bereich: ein Code-Abschnitt, in dem wechselseitiger 
Ausschluss herrschen soll

von Εrnst B. (ernst)


Lesenswert?

Wilhelm M. schrieb:
> Nö.

Nö.
1
static __inline__ void __iSeiParam(const uint8_t *__s)
2
{
3
  __asm__ __volatile__ ("sei" ::: "memory");
4
  __asm__ volatile ("" ::: "memory");
5
  (void)__s;
6
}

der Trick liegt im "type", da wird für die sreg-zwischenspeichervariable 
ein
1
  __attribute__((__cleanup__(__iSeiParam)))
gesetzt.

: Bearbeitet durch User
von Kevin (Gast)


Lesenswert?

(prx) A. K. schrieb:
> Wenn die 4 Bytes nicht an einer Adresse %4==0 liegen, die Maschine einen
> solchen Zugriff nicht zulässt und der Compiler deshalb daraus mehrere
> Zugriffe machen muss.

Danke. Misalignment war mir schon klar, jetzt habe ich auch die 
Verbindung warum es in meinem betrachteten Fall zum Problem werden kann.

von Wilhelm M. (wimalopaan)


Lesenswert?

Εrnst B. schrieb:

>
> der Trick liegt im "type", da wird für die sreg-zwischenspeichervariable
> ein
>
1
>   __attribute__((__cleanup__(__iSeiParam)))
2
>
> gesetzt.

Ja, aber nur dafür.

von Εrnst B. (ernst)


Lesenswert?

Wilhelm M. schrieb:
> Ja, aber nur dafür.

Das ist eine "destruktor"-Funktion, die immer ausgeführt wird, wenn die 
Variable den scope verlässt.

Hat den Sinn, dass auch bei einem
1
ATOMIC_BLOCK(ATOMIC_FORCEON) {
2
  ...
3
  if(x) return; // oder break
4
  ...
5
}
das "return" ein "sei" auslöst. Sonst wären vorzeitigen Verlassen des 
Blocks die Interrupts immer noch gesperrt.

Die darin deklarierte barrier gilt für den gesamten RAM, nicht nur die 
eine Variable.

das cli beim Betreten hat keine solche optimization barrier.

d.H. der Compiler könnte zwar Berechnungen vor dem Atomic-Block in 
diesen hineinziehen, aber nichts aus dem Block herausnehmen.

Nach Verlassen des Atomic Blocks ist jedenfalls sichergestellt, dass 
alle Variablen sauber in den RAM zurückgespeichert wurden.

von Wilhelm M. (wimalopaan)


Lesenswert?

Εrnst B. schrieb:
> Nach Verlassen des Atomic Blocks ist jedenfalls sichergestellt, dass
> alle Variablen sauber in den RAM zurückgespeichert wurden.

Nö.
1
#include <stdint.h>
2
#include <util/atomic.h>
3
    
4
static /*volatile */ uint8_t x;
5
6
int main() {
7
    ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
8
        x = 0;
9
    }
10
}

ergibt
1
main:
2
in r24,__SREG__  ;  _1, MEM[(volatile uint8_t *)63B]
3
cli
4
out __SREG__,r24         ;  MEM[(volatile uint8_t *)63B], _1
5
ldi r24,0                ;
6
ldi r25,0                ;
7
ret

von Εrnst B. (ernst)


Lesenswert?

Wilhelm M. schrieb:
> Nö.

Warum Nö? Dein Beispiel bestätigt doch 1:1 was ich geschrieben habe.
Nur dass der Compiler "x" eben ganz wegoptimiert hat. Darf er, wird ja 
nie wieder gelesen.

Pack in dein Beispiel ans Ende noch ein "return x", dann siehst du 
exakt, dass es zuerst in den RAM geschrieben wird, und für's return auch 
wieder aus dem RAM gelesen wird.
1
main:
2
        in r24,__SREG__
3
        cli
4
        sts x,__zero_reg__
5
        out __SREG__,r24
6
        lds r24,x
7
        ldi r25,0
8
ret

Selben Effekt hast du auch, wenn "x" nicht static ist.

: Bearbeitet durch User
von Wilhelm M. (wimalopaan)


Lesenswert?

Εrnst B. schrieb:
> Warum Nö? Dein Beispiel bestätigt doch 1:1 was ich geschrieben habe.
> Nur dass der Compiler "x" eben ganz wegoptimiert hat. Darf er, wird ja
> nie wieder gelesen.

Du sagst, dass im ATOMIC_BLOCK alle(!) dort zugegriffenen Variablen 
automatich volatile wären. Wie Du siehst, stimmt diese Aussage nicht!

Wenn es volatile wäre, dürfte er den Zugriff auf x nicht wegoptimieren. 
Du kannst Dich davon leicht überzeugen, indem Du in meinem Beispiel 
einfach mal die volatile Deklaration einkommentierst.

von Εrnst B. (ernst)


Lesenswert?

Wilhelm M. schrieb:
> Du sagst, dass im ATOMIC_BLOCK alle(!) dort zugegriffenen Variablen
> automatich volatile wären. Wie Du siehst, stimmt diese Aussage nicht!

Das habe ich NIE behauptet. Es geht ja gerade darum, dass die 
Variablen NICHT Volatile werden müssen, weil der Atomic-Block das 
Rückschreiben erzwingt. Damit ist das übliche Problem von "Variable wird 
in ISR und main verwendet" in den üblichen Fällen erschlagen, OHNE 
dass man sich die anderen Nachteile von volatile einfängt.

von Wilhelm M. (wimalopaan)


Lesenswert?

Εrnst B. schrieb:
> Wilhelm M. schrieb:
>> Du sagst, dass im ATOMIC_BLOCK alle(!) dort zugegriffenen Variablen
>> automatich volatile wären. Wie Du siehst, stimmt diese Aussage nicht!
>
> Das habe ich NIE behauptet. Es geht ja gerade darum, dass die
> Variablen NICHT Volatile werden müssen, weil der Atomic-Block das
> Rückschreiben erzwingt. Damit ist das übliche Problem von "Variable wird
> in ISR und main verwendet" in den üblichen Fällen erschlagen, *OHNE*
> dass man sich die anderen Nachteile von volatile einfängt.

Schau Dir folgendes an
1
#include <stdint.h>
2
#include <util/atomic.h>
3
    
4
static /*volatile */ uint8_t x;
5
6
ISR( TIMER2_OVF_vect ) {
7
    uint8_t y = x;
8
}
9
10
int main() {
11
    ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
12
        x = 0;
13
    }
14
}

Ergibt:
1
__RAMPZ__ = 0x3b
2
__CCP__ = 0x34
3
.text
4
.type   TIMER2_OVF_vect, @function
5
TIMER2_OVF_vect:
6
__gcc_isr 1      ;
7
__gcc_isr 2      ;
8
reti
9
__gcc_isr 0,r0
10
.size   TIMER2_OVF_vect, .-TIMER2_OVF_vect
11
.section        .text.startup,"ax",@progbits
12
.type   main, @function
13
main:
14
in r24,__SREG__  ;  _1, MEM[(volatile uint8_t *)63B]
15
cli
16
out __SREG__,r24         ;  MEM[(volatile uint8_t *)63B], _1
17
.L3:
18
rjmp .L3                 ;
19
.size   main, .-main

Atomarität und Optimierungssperre (ggf. durch volatile) sind zwei 
unterschiedliche Dinge.

: Bearbeitet durch User
von Peter D. (peda)


Lesenswert?

Wilhelm M. schrieb:
> Wenn es volatile wäre, dürfte er den Zugriff auf x nicht wegoptimieren.

Dein Beispiel ist allerdings sehr speziell, da es keine Loop enthält. 
Typisch wird bei MC-Anwendungen das Main nie verlassen. Ich wüßte 
jedenfalls nicht, wie dann eine sinnvolle Anwendung zustande kommen 
soll.
Außerdem sagst Du mit dem static, daß die Variable nirgends anders 
zugegriffen werden kann.

Mach ne Loop ins Main, nimm das static weg, dann erfolgt auch die 
Zuweisung.

von Εrnst B. (ernst)


Lesenswert?

Wilhelm M. schrieb:
> Schau Dir folgendes an

Wieder ein Beispiel, was meine Aussagen belegt bzw. zumindest nicht 
widerlegt.
In dem ASM-Code, den du zeigt, findet keinerlei nicht-synchronisierter 
Zugriff auf "uint8_t x" statt. Exakt das, was der Atomic_block erreichen 
soll.
QED.

: Bearbeitet durch User
von Teo D. (teoderix)


Lesenswert?

Teo D. schrieb:
> Oje, nu kloppen sich die Spezis die Köppe ein.

:DDD

von Peter D. (peda)


Lesenswert?

Man kann aber auch im Main auf volatile casten. Dann wird im Main der 
Zugriff erzwungen und im Interrupt kann die Variable weiterhin optimiert 
werden.
1
#define IVAR(x)         (*(volatile typeof(x)*)&(x))

von Gerald K. (geku)


Lesenswert?

Ich würde in der Interruptroutine keine Berechnungen oder andere 
komplexe Aufgaben durchführen. Die Interruptfunktionen nur füe 
IO-Operationen verwenden. Z.B. Wert von einem Port abholen und in ein 
FIFO schreiben und dem Hintergrund mittels Flag signalisieren das etwas 
im FIFO abholbar ist. Interrupt nur verwenden wenn die Gefahr besteht 
etwas im Hintergrund zu verpassen.

Ist der Hintergrund fertig, dann kann er zum Energiesparen, den 
Sleepmodus aktivieren. Dieser kann in einer Interruptroutine wieder 
deaktiviert werden.

Kurz eine Bemerkung zum FIFO:

Die Interruptroutine hat alleinigen Zugriff zum Schreibzeiger, der 
Hintergrund alleinigen Zugriff zum Lesezeiger. So kommen sich Interrupt 
und Hintergrund nicht in die Quere.

: Bearbeitet durch User
von Peter D. (peda)


Lesenswert?

Gerald K. schrieb:
> Die Interruptroutine hat alleinigen Zugriff zum Schreibzeiger, der
> Hintergrund alleinigen Zugriff zum Lesezeiger.

Beim Sende-FIFO dann umgekehrt.

von c-hater (Gast)


Lesenswert?

Kevin schrieb:

> Kann man annehmen,
> das auf einem 32Bit Controller der Schreibzugriff auf eine (8/16/32 Bit)
> Variablen immer atomar erfolgt.

Nein, das kann man nicht.

Es ist zwar der Regelfall, aber, wie bei jeder Regel: es gibt auch viele 
Ausnahmen. Diese Ausnahmen sind sehr architekturspezifisch. Wobei hier 
"Architektur" mehr umfasst, als das, was man üblicherweise darunter 
versteht. Neben der CPU/MCU selber nämlich auch noch die konkrete 
Schaltung, in der sie steckt.

von (prx) A. K. (prx)


Lesenswert?

c-hater schrieb:
> Neben der CPU/MCU selber nämlich auch noch die konkrete Schaltung, in
> der sie steckt.

Wobei eine Aufteilung auf mehrere Zugriffe im Businterface für 
Interrupts innerhalb eines Cores atomar bleibt.

: Bearbeitet durch User
von c-hater (Gast)


Lesenswert?

(prx) A. K. schrieb:

> Wobei eine Aufteilung auf mehrere Zugriffe im Businterface für
> Interrupts innerhalb eines Cores atomar bleibt.

Das kannst du für jede Architektur garantieren?

von (prx) A. K. (prx)


Lesenswert?

c-hater schrieb:
> Das kannst du für jede Architektur garantieren?

Bei Mikrocontrollern mit einem Core bin ich mir da ziemlicher sicher.

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.