Forum: Compiler & IDEs ATOMIC Blöcke verstehen.


von AVRli (Gast)


Lesenswert?

Hallo µC Bändiger,

ich lese gerade gerade so nebenbei in der GGC Wiki hier im Forum was von 
"ATOMIC Makros". Also wofür die da sind hab ich im Prinzip jetzt 
verstanden nur wo und wann man die genau einsetzt ist noch etwas "dunkel 
im Denkschacht". :-)

Damit kann man dafür sorgen das ein gleichzeitiger Zugriff auf ein 16 
Bit (oder breiteren) Wert im Interrupt und im Hauptprogramm möglich ist.

Doch wann nutzt man nun genau diese ATOMIC Funktion?
Bei jeden Zugriff auf eine Variable im Hauptprogramm die breiter als 8 
bit ist? Und nur dann?

Ich versuche es mal mit einer Wartefunktion, waitcnt wird im Timer 
Interrupt alle 1ms decrementiert.
1
...
2
volatile uint16_t waitcnt;
3
...
4
5
void wait(uint16_t time_ms) {
6
  uint16_t tmp;
7
8
  ATOMIC_BLOCK(ATOMIC_FORCEON) {
9
    waitcnt = time_ms;
10
  }
11
12
  tmp = time_ms;
13
14
  while (tmp>0) {
15
    ATOMIC_BLOCK(ATOMIC_FORCEON) {
16
      tmp = waitcnt;
17
      }
18
  }
19
}

Läuft so eine Sache dann mit einer UART Routine noch "synchron" oder 
verliert man da dann Daten?

Schöne Grüße, AVRli
(lange nix gemacht, doch nun wieder hier)

von Karl H. (kbuchegg)


Lesenswert?

AVRli schrieb:

> Damit kann man dafür sorgen das ein gleichzeitiger Zugriff auf ein 16
> Bit (oder breiteren) Wert im Interrupt und im Hauptprogramm möglich ist.

Nö.
Genau umgekehrt.
Damit erreicht man, dass ein 16-Bit Zugriff (du meinst das richtige) im 
Hauptprogramm nicht von einem Interrupt unterbrochen werden kann.

> Bei jeden Zugriff auf eine Variable im Hauptprogramm die breiter als 8
> bit ist? Und nur dann?

Immer dann, wenn die Gefahr besteht, dass einem ein Interrupt beim 
Auslesen des Wertes dazwischenfunken kann, so das sbeispielsweise die 
unteren 8 Bit schon gelesen wurden, die oberen 8 Bit (bei einem 16 Bit 
Wert) aber noch nicht.

> Ich versuche es mal mit einer Wartefunktion, waitcnt wird im Timer
> Interrupt alle 1ms decrementiert.
>
>
1
> ...
2
> volatile uint16_t waitcnt;
3
> ...
4
> 
5
> void wait(uint16_t time_ms) {
6
>   uint16_t tmp;
7
> 
8
>   ATOMIC_BLOCK(ATOMIC_FORCEON) {
9
>     waitcnt = time_ms;
10
>   }
11
> 
12
>   tmp = time_ms;
13
> 
14
>   while (tmp>0) {
15
>     ATOMIC_BLOCK(ATOMIC_FORCEON) {
16
>       tmp = waitcnt;
17
>       }
18
>   }
19
> }
20
>
>

passt

> Läuft so eine Sache dann mit einer UART Routine noch "synchron" oder
> verliert man da dann Daten?

UART hat damit nichts zu tun.


Es geht eher darum, dass du einen Aufsatz schreibst, zur Mittagspause 
gehst (der Interrupt kommt) und in der Zeit in der du auf Mittagspause 
bist dir deine Mutter das Papier vom Schreibtisch nimmt und ein anderes 
hinlegt. Wenn du von der Pause zurückkommst, schreibst du dann auf einem 
anderen Papier weiter, als das auf dem du eigentlich solltest. Beim 
Auswerten des Aufsatzes ist dann das Erstaunen groß, dass die erste 
Hälfte davon falsch ist.

von AVRli (Gast)


Lesenswert?

Karl heinz Buchegger schrieb:
> Es geht eher darum, dass du einen Aufsatz schreibst...
> ...beim Auswerten des Aufsatzes ist dann das Erstaunen
> groß, dass die erste Hälfte davon falsch ist.

:-D Besser kann man es wohl nicht erklären! top

Nun wäre für mich noch interessant ob ich den Rest auch richtig 
verstanden habe warum es eben verschiedene Atomic-Makros gibt.

ATOMIC_BLOCK(type) Den haben wir ja nun besprochen...

Nur wann nimmt man den type ATOMIC_FORCEON und wann ist dann 
ATOMIC_RESTORESTATE zu verwenden? RESTORESTATE wenn ich im ATOMIC_BLOCK 
vergleiche mache und rechne die ja Einfluss auf das SREG haben?

Und wozu braucht man nun noch den NONATOMIC_BLOCK(type)?

Ist nicht alles was kein ATOMIC_BLOCK ist, ein NONATOMIC_BLOCK ???


Danke im Voraus!
Schöne Grüße, AVRli

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Ein typischer Fall ist auch sowas:
1
volatile uint16_t waittime;
2
3
ISR(TIMER0_OVF_vect)
4
{
5
  waittime--;
6
}
7
8
int
9
main(void)
10
{
11
   /* ... */
12
   waittime = 42243;
13
   /* ... */
14
   while (waittime != 0)
15
      /* wait */;
16
17
}

Beobachteter Effekt: geht meistens, aber manchmal steht in waittime
hernach 0x00ff drin.

Ursache: wenn der Compiler die 16-bit-Variable waittime auf 0 testen
will, testet er zuerst das low-Byte.  Solange das nicht 0 ist, kann
er die Warteschleife sofort fortsetzen, andernfalls muss er noch das
high-Byte testen.  Nun steht irgendwann 0x100 da drin, der Test des
low-Bytes ist erfolgreich (gleich Null also), es soll das high-Byte
getestet werden.  Jetzt schlägt der Timer-Interrupt zu und dekre-
mentiert die 0x100 zu 0xff.  Danach Rückkehr ins Hauptprogramm,
Test des high-Bytes, aha, das ist auch Null :), also ist die Schleife
jetzt zu Ende.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

AVRli schrieb:

> Nur wann nimmt man den type ATOMIC_FORCEON und wann ist dann
> ATOMIC_RESTORESTATE zu verwenden?

FORCEON nimmst du, wenn du dir sicher bist, dass die Interrupts vor
Eintritt in den Block freigegeben waren und damit hinterher auch
wieder freigegeben werden sollen ("force on").

RESTORESTATE nimmst du für Routinen, die ggf. auch innerhalb einer
Zeit aufgerufen werden können, während Interrupts global gesperrt
sind.  Das kann innerhalb einer ISR sein, es kann aber auch an
einer anderen Stelle im Programm sein, bei dem sie aus irgendeinem
Grund gesperrt waren.  In diesem Falle wird der aktuelle Zustand
der Interruptfreigabe (in Form des kompletten SREG, die anderen
Bits interessieren hier einfach niemanden) beim Eintritt in den
Block gerettet und beim Austritt wieder hergestellt.

> Und wozu braucht man nun noch den NONATOMIC_BLOCK(type)?

Nur aus Schönheits- oder Symmetriegründen. ;-)

> Ist nicht alles was kein ATOMIC_BLOCK ist, ein NONATOMIC_BLOCK ?

Ja, ist er.  Ich wäre sicher auch nicht auf die Idee gekommen, sowas
extra aufzuschreiben, aber aus irgendeinem Grund fand Dean Camera
das wohl toll, das Pendant zum atomic block auch zu haben. ;-)

von Peter D. (peda)


Lesenswert?

AVRli schrieb:
> Nur wann nimmt man den type ATOMIC_FORCEON und wann ist dann
> ATOMIC_RESTORESTATE zu verwenden?

ATOMIC_RESTORESTATE ist was für die Überängstlichen, die meinen, in 
ihrem eigenen Code nicht mehr durchzusehen.

Oder die so ungünstig programmieren, daß extrem lange über mehrere 
Funktionsinstanzen reichende Interrupt-Disable Zeiten entstehen.

Oder die viele Funktionen gleichzeitig in Interrupts und Main verwenden. 
Unterfunktionsaufrufe in Interrupts sind aber sehr Stack-teuer und lange 
sollten sie auch nicht dauern.


Wenn man ATOMIC_RESTORESTATE braucht, hat man sich irgendwo durch 
unüberlegte Programmablaufplanung ins Bein geschossen.


Peter

von Werner B. (werner-b)


Lesenswert?

Jörg Wunsch schrieb:
>> Und wozu braucht man nun noch den NONATOMIC_BLOCK(type)?
>
> Nur aus Schönheits- oder Symmetriegründen. ;-)
>
>> Ist nicht alles was kein ATOMIC_BLOCK ist, ein NONATOMIC_BLOCK ?
>
> Ja, ist er.  Ich wäre sicher auch nicht auf die Idee gekommen, sowas
> extra aufzuschreiben, aber aus irgendeinem Grund fand Dean Camera
> das wohl toll, das Pendant zum atomic block auch zu haben. ;-)

Die Idee war glaube ich, dass man innerhalb eines längeren atomic 
Bereiches die Interrupts für einen bestimmten Codeabschnitt erlauben 
kann. Dadurch sieht dann der Quellcode wesentlich strukturierter aus aus 
wenn mehrere ATOMIC_BLOCK hintereinander "gefummelt" werden.

von markusj (Gast)


Lesenswert?

Peter Dannegger schrieb:
> Wenn man ATOMIC_RESTORESTATE braucht, hat man sich irgendwo durch
> unüberlegte Programmablaufplanung ins Bein geschossen.

... oder programmiert ein Modul/eine Bibliothek, die dem Benutzer 
möglichst viel Freiraum einräumen will ...

mfG
Markus

von Falk B. (falk)


Lesenswert?

@  Werner B. (werner-b)

>kann. Dadurch sieht dann der Quellcode wesentlich strukturierter aus aus
>wenn mehrere ATOMIC_BLOCK hintereinander "gefummelt" werden.

Ja, aber im allgemeinen sollten ATOMIC Blöcke eher kurz sein. Siehe 
Interrupt.

MFG
Falk

von AVRli (Gast)


Lesenswert?

Hallo an alle,

nun ist hier wirklich klar was man damit anstellt. Das ist aus meiner 
Sicht so was von elementar, dass ich mich stark wundere das mir das in 
noch keinem C Buch untergekommen ist. Ok ich habe nur 2 ... ;-)

1x die deutsche Übersetzung der C Beschreibung der beiden 
"Sprachentwickler" Gut, das das WinAVR nicht berücksichtigt wird ist 
schon klar und auch ok, in dem Buch geht's auch um die Sprache. :-)

Hier hingegen hätte ich es erwartet...

Mikrocomputertechnik mit Controllern der Atmel AVR-RISC-Familie: 
Programmierung in Assembler und C - Schaltungen und Anwendungen von 
Günter Schmitt

Tcha, aber noch hab ich da nichts in Richtung ATOMIC Blöcke gefunden. 
Naja egal, besser spät als nie erfahren warum manche Programme nicht 
ganz so funktionieren wie sie sollen... wenn ich zurück auf meinen ms 
Timer komme, wenn ich da 300ms eine LED blinken lassen will dann sind 
300ms manchmal sehr kurz gewesen. Das ist nun dank der ATOMIC Blöcke 
verschwunden.

Ich dachte ja bis gestern immer das es mit einer...

voilatile uint16_t zaeler;

...Deklaration getan ist. Wobei nun nach längerem Nachdenken ich der 
Meinung bin ob ein Wert > 8 Bit nun voilatile ist oder nicht, spielt 
durch die Nutzung von ATOMIC BLÖCKEN keine Rolle oder?

Schönen Abend, AVRli...

von Karl H. (kbuchegg)


Lesenswert?

AVRli schrieb:

> ...Deklaration getan ist. Wobei nun nach längerem Nachdenken ich der
> Meinung bin ob ein Wert > 8 Bit nun voilatile ist oder nicht, spielt
> durch die Nutzung von ATOMIC BLÖCKEN keine Rolle oder?

ATOMIC und volatile sind 2 verschiedene Bausteine

Bei ATOMIC geht es darum, den Zugriff unterbrechungsfrei zu kriegen.
Bei volatile geht es darum überhaupt einen Zugriff zu kriegen und dem 
Optimizer mitzuteilen: Ich meine das so wie ich es schreibe.

von Falk B. (falk)


Lesenswert?

@  AVRli (Gast)

>...Deklaration getan ist. Wobei nun nach längerem Nachdenken ich der
>Meinung bin ob ein Wert > 8 Bit nun voilatile ist oder nicht, spielt
>durch die Nutzung von ATOMIC BLÖCKEN keine Rolle oder?

Denkste! Volatile und Atomic sind verschiedene Dinge! Auch wenn sie oft 
zusammen benötigt werden. Siehe Artikel Interrupt.

MFG
Falk

von AVRli (Gast)


Lesenswert?

Ok, ;-)

nun alles gut im Gehirn abspeichern. Also mach ich alles wie gehabt mit 
voilatile bei INT/MAIN Nutzung und nun noch zusätzlich die ATOMIC 
Geschichte. Dann danke für Eure Hilfe!!

Gruß AVRli...

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.