www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Atomarer Zugriff von 16 Bit Variable in 8 Bit Controller


Autor: Sebastian B. (mircobolle)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

wir entwickeln software fuer kritische anwendungen.

Heute habe ich in der abteilung eine diskussion bei einem CodeReview 
mitbekommen.

Inhalt des Reviews:

globale 16 bit variable in modul A
u16 u16_A;

in der RTC ISR wird dieser wert nun gegen null verglichen und 
dekrementiert:
if (u16_A > 0 )
   u16_A -= 1;

mein kollege hat nun angemerkt, dass bei einem 8 bit controller 
zugrifffe auf 16 bit variablen intern ja nicht mit einem assembler 
befehl geschehen können. Dies könnte unter umständen dazu führen, dass 
u16_A verä.... und schwups RTC Interrupt (ausgelesen)... ndert wird... 
und das dabei was schief gehen kann.

1. ist es natürlich unschön, so mit dieser globalen variable umzugehen

aber ist es wirklich so ein Problem? oder regelt der compiler solche 
zugriffe intern über abschalten der interrupts während eines solchen 
zugriffs??

würde mich wirklich interessieren.

COntroller ist übrigens der HC(S)08
compiler ist der coderWarrior

MFG
 und gute nacht ;-)

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ Sebastian B. (mircobolle)

>wir entwickeln software fuer kritische anwendungen.

Klorollenabwickler? ;-)

SCNR

>1. ist es natürlich unschön, so mit dieser globalen variable umzugehen

Nö, das passt, WENN . . .

>aber ist es wirklich so ein Problem?

Ja.

> oder regelt der compiler solche
>zugriffe intern über abschalten der interrupts während eines solchen
>zugriffs??

Nöö, da ist Handarbeit gefragt, siehe Interrupt.

MFG
Falk

Autor: crazy horse (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
nein, musst du selbst machen.
Also vor Zugriff Interrupts abschalten - zumindest die, die die Variable 
verändern können.
Ist ein altes Problem, was oft übersehen wird, funktioniert ja 
normalerweise. Aber nur, weil die Wahrscheinlichkeit gering ist, dass 
genau zwischen den beiden Zugriffen was passiert (und dann ja noch ein 
Übertrag L->H stattfinden muss, ansonsten ist der Wert ja nur nicht ganz 
aktuell, aber nicht prinzipiell falsch). Irgendwann passiert es aber.
Dein Kollege hat absolut recht!

Autor: gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
globale 16 bit variable in modul A
u16 u16_A;

in der RTC ISR wird dieser wert nun gegen null verglichen und
dekrementiert:
if (u16_A > 0 )
   u16_A -= 1;

Dieser Code ist identisch mit

u16 u16_A;
if (u16_A)
   u16_A -= 1;

was an sich nicht schlimm ist, das schlimme daran ist,
daß u16_A nicht als volatile gekennzeichnet ist, denn wenn er als 
volatile
gekennzeichnet wäre, müsste der Compiler 2-Mal auf die Variable 
zugreifen,
und das Problem behebt sich von selbst, zumindest aus der Einsicht, die 
du uns gegeben hast.

Autor: Andreas W. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Da hab ich auch gleich mal eine Frage zu.

Gibt es auch ein Problem wenn ich 16/32/64.Bit variablen ausschließlich 
außerhalb von Interrups verwende.

@crazy horse (Gast)

Das Problem kann je nach interrupt selten oder auch SEHR oft auftreten. 
mir ist aufgefallen das solche "Zufälle" in einer CPU sehr 
wahrscheinlich sind.

Autor: Ralf (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Gibt es auch ein Problem wenn ich 16/32/64.Bit variablen ausschließlich
> außerhalb von Interrups verwende.
Nein, eigentlich nicht. Das einzige, was passieren kann, ist dass wenn 
du grad auf so ne Variable zugreifst, der Interrupt zwischen den 
Byte-Zugriffen auftritt. Aber das macht den Variablen im Normalfall nix.

Ralf

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>...der Interrupt zwischen den Byte-Zugriffen auftritt.
>Aber das macht den Variablen im Normalfall nix

Das passiert viel öfter als Du denkst.

Globale Variabeln die Du innerhalb und ausserhalb einer ISR verwendest 
müssen volatile sein, denn sonst wird der Optimiser die Werte mit 
grosser Warscheinlichkeit in Register halten, da er nicht wissen kann, 
dass diese von einer ISR benutzt werden!

Innerhalb einer ISR ist der Zugriff auf 16/32 Bit Variabeln sicher, da 
dann weitere Interupts gesperrt sind. (Es sei den Du lässt diese wieder 
explizit wieder zu)

Ausserhalb von ISRs führen solche Zugriffe zu Problemen, wenn die Werte 
solcher Variabeln innerhalb einer ISR verändert werden. Dann musst Du 
Interrupts unbedingt sperren, siehe folgendes Beispiel:
unsigend char sreg_cpy;
volatile unsigned long var32;
//------------------------------------
sreg_cpy=SREG;   // save SREG
cli();           // disable interrupts
var32 = var32+1; // save usaged of  var
SREG=sreg_cpy;   // restore SREG


MfG Peter

Autor: Ralph (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das beschriebene Problem tritt immer dann auf, wenn die Bitzahl einer 
Variablen größer als die Datenbusbreite des µC ist.

Achte hier auch auf Timerzugriffe  wenn 16Bit Timer verwendet werden.
Es ist durchaus möglich das ein Timerüberlauf zwischen den beiden 
Lesezugriffen erfolgt.

Eine Möglichkeit das zu umgehen ist folgenden:

1. Highbyte auslesen
2. Lowbyte auslesen
3. Highbyte nochmal lesen
4. Beide Highbytes vergleichen
5. Highbyte identisch ?
   a. Ja ==> fertig
   b. Nein ==> Sprung zu 1.

Nachteil: Benötigt mehr Laufzeit als Möglichkeit 2

2. Möglichkeit:

1. Timer stop
2. Highbyte und Lowbyte auslesen
3. Timer start

Nachteil: Timer steht für einige µsec


Auch hier gilt wie für alle anderen 16 Bit zugriffe auf einem 8 Bit µC:
Prüfen ob IRQ abgeschaltet werden müssen, in diesem Fall empfehlenswert.

Autor: Ralf (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Peter:
> Das passiert viel öfter als Du denkst.
Ja, das schon, aber er hatte danach gefragt, was passiert, wenn er die 
Variablen nur ausserhalb der ISRs verwendet.

Ralf

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ Ralph (Gast)

>Achte hier auch auf Timerzugriffe  wenn 16Bit Timer verwendet werden.
>Es ist durchaus möglich das ein Timerüberlauf zwischen den beiden
>Lesezugriffen erfolgt.

Schon, aber der AVR regelt das per Hardware Zwischenpuffer, siehe 
Datenblatt.
Andere uCs machen das ähnlich.

Die hier vorgeschlagenen Methoden sind nicht sinnvoll und notwendig.

MFg
Falk

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ralph wrote:
> Das beschriebene Problem tritt immer dann auf, wenn die Bitzahl einer
> Variablen größer als die Datenbusbreite des µC ist.

Nein!

Das Problem gibt es auch bei read/write-Zugriffen (++,--,|= usw.).
Oder wenn man eine Bitvariable zuweist.
Manche Architekturen (8051) können auch Bitvariablen atomar setzen.


Peter

Autor: jl (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Noch ne weitere Anmerkung:

auch bei 16bit Controllern bei denen eine 16bit Zahl vom Speicher 
gelesen wird kann es zu 2Lesezyklen und damit veränderung während des 
lesens kommen. Sobald im Speichermapping die 16bit Zahl auf einer 
ungeraden Adresse beginnt gibt es das gleiche Problem.

Wie kommst es dazu?
- einfach in einer Struktur Bytes definieren
    struct ( char x;
             int  y;
           )
- generell im mapping 8,16,32 bit variablen nicht getrennt verwalten




JL

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mal eine Frage...
wenn die ISR irgendwie an den Registern rumfummelt muss diese auch dafür 
sorgen das die auch wieder hergestellt werden, oder etwa nicht?

Autor: Sebastian B. (mircobolle)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Falk Brunner wrote:
> @ Sebastian B. (mircobolle)
>
>>wir entwickeln software fuer kritische anwendungen.
>
> Klorollenabwickler? ;-)
>
> SCNR
-> Kein Problem ;-)

kritischer wäre eine Regelung, die den Füllstand einer mobilen 
Camping-Toilette überwachen soll. Ein Grenzwert-Fehler könnte hier zu 
fatalen Folgen führen... ;-) so viel zum Theme Kritikalität

>Schon, aber der AVR regelt das per Hardware Zwischenpuffer, siehe
>Datenblatt.
>Andere uCs machen das ähnlich.

Ich dachte mir eben auch deshalb, dass evtl. 16 Bit variable in solche 
register zwischen gepuffert werden.

aber da lag ich wohl falsch.

Ich exerziere mal kurz einen Fehler-Fall durch:

Ich schreibe in main() auf die globale Variable

volatile u16 v_u16_A;


main(){

    while(1){
    /* ... */
    if (v_u16_B > 0)
       v_u16_A = 0;
    /* ... */

    }

}


in der RTC ISR wuerde nun sowas passieren wie:

rtc_isr (){
   if (v_u16_A > 0)
      v_u16_A -= 1;
}

die ISR laeuft nun mit einem Takt von 2 ms...

Startwert:
v_u16_A = 10;

zuerst:
main-Zugriff

zwischen HIGH und LOW Byte -> INTERRUPT
v_u16_A[HIGH] = 0x00;
...
v_u16_A[LOW]  = 0x0A;

ISR RTC:
...
v_u16_A -= 1; /* --> 9 */

zurueck zu main:
v_u16_A[LOW]  = 0x00;



In diesme Fallw wuerde der ISR Zugriff ja nicht "stoeren"...
ich mein klar ist es ein Fehler und natuerlich ist es unschoen, aber in 
diesem konkreten Fall, sehe ich jetzt keine weiteren Probleme, da main 
die Variable ja noch ueberbuegeln kann..

Wenn der Interrupt direkt vorher auftritt:
alles prima: dekrementieren... pruefen/auf null setzen

wenn der interrupt danach auftritt:
auch alles prima: wert auf null setzen... pruefen/...

MFG

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ Gast (Gast)

>wenn die ISR irgendwie an den Registern rumfummelt muss diese auch dafür
>sorgen das die auch wieder hergestellt werden, oder etwa nicht?

Ja, siehe Interrupt.

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Ralf
>@Peter:
>> Das passiert viel öfter als Du denkst.
>Ja, das schon, aber er hatte danach gefragt, was passiert, wenn er die
>Variablen nur ausserhalb der ISRs verwendet.

Hab ich ja geschrieben: Es ist nur ein Problem, wenn globale Variabeln 
innerhalb einer ISR modifiziert werden, sonst nicht!

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Peter (Gast)

>Hab ich ja geschrieben: Es ist nur ein Problem, wenn globale Variabeln
>innerhalb einer ISR modifiziert werden, sonst nicht!

Es ist auch ein Problem, wenn sie "nur" gelesen werden.
Man kann glaub ich sagen, dass sobald Variablen sowohl im Haputprogramm 
als auch ISRs benutzt werden, egal ob lesend oder schreibend, atomare 
Operatioenen und volatile Definitionen notwendig sind.

MFG
Falk

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.