Hallo alle zusammen, ich habe da mal eine, hoffentlich interessante, Frage. Nehmen wir an, ich habe zwei Interrupts mit unterschiedlichen Prioritaeten. ISR_A hat eine hoehere Prioritaet als ISR_B. ISR_A kann ISR_B unterbrechen. ISR_A greift schreibend auf eine globale Variable eines anderen Moduls zu (Ueber die Systemarchitektur bitte ich hinwegzusehen, darum geht es nicht). ISR_B greift nur lesend auf diese Variable zu. Es ist nicht schlimm, wenn ISR_B einen veralteten Wert der Variable bekommt. Sollte es aber irgendwann mal mitbekommen das ISR_A den Wert geaendert hat. Muss die Variable volatil sein? Die Variable ist eine Struktur, kann also wahrscheinlich nicht in den Registern behalten werden. Wohl aber eines ihrer Member. Wie macht der gcc das? ISR wird aufgerufen, variable wird in Register geholt, geschrieben, gelsen, was weiss ich und bevor die ISR verlassen wird wird dann zurueck in den Speicher geschrieben?! Ich vermute es kommt auf den Einzelfall an und im Zweifel wird ein Blick ins Assembler Listing noetig sein, oder pauschal als volatil deklarieren. Beste Gruesse Christopher
beim beenden wird sie auf jeden Fall zurückgeschrieben. Wenn wirklich nur 2 ISR beteiligt sind, braucht man kein Volatile. Aber das die 2. ISR sinnvolle Daten bekommt ist nur bei 8bit variablen sichergestellt. Bei größeren musst du davon ausgehen, das Operationen nicht Atomar sind.
Peter II schrieb: > beim beenden wird sie auf jeden Fall zurückgeschrieben. Danke dafuer schonmal, das war auch meine Vermutung. > Wenn wirklich nur 2 ISR beteiligt sind, braucht man kein Volatile. es sind noch ein Paar mehr, aber die interessieren sich nicht fuer die Variable > Aber > das die 2. ISR sinnvolle Daten bekommt ist nur bei 8bit variablen > sichergestellt. Vorausgesetzt man ist auf einer 8bit Maschine unterwegs, oder? Das bringt mich zu einer neuen Frage. Wenn man eine Maschine mit 32bit Datenbus hat und eine Variable auf 32bit aligned ist, dann ist der Zugriff darauf auch atomar, oder? > Bei größeren musst du davon ausgehen, das Operationen > nicht Atomar sind. Die Lesezugriffe aus ISR_B sind atomar gehalten. Aber danke fuer den hinweis. ISR_A hat keine Interruptsperre, da diese nicht von ISR_B unterbrochen werden kann. LG Christopher
Peter II schrieb: > Wenn wirklich nur 2 ISR beteiligt sind, braucht man kein Volatile. Volatile hat doch aber auch den Zweck, dass der Compiler nicht meint Code optimieren zu können weil sich der Inhalt der Variable nicht geändert haben kann. Insofern braucht man IMMER volatile wenn mindestens eine ISR im Spiel ist, hier vor allem weil der höher priorisierte Interrupt den niedrigeren unterbrechen und die Variable ändern kann. Korrigiert mich falls ich falsch liege. Creepy wird es wenn es multicore Rechner sind, die pro core einen eigenen Cache haben. Da muss sogar in Hochsprachen wie Java volatile benutzt werden, wenn die Variable in mehreren Threads geändert werden kann. Ansonsten kann es vorkommen, dass Thread 2 einen veralteten Wert der Variable in seinem Cache liegen hat und benutzt, den Thread x schon geändert hatte.
Christopher B. schrieb: >> Aber >> das die 2. ISR sinnvolle Daten bekommt ist nur bei 8bit variablen >> sichergestellt. > Vorausgesetzt man ist auf einer 8bit Maschine unterwegs, oder? Das > bringt mich zu einer neuen Frage. Wenn man eine Maschine mit 32bit > Datenbus hat und eine Variable auf 32bit aligned ist, dann ist der > Zugriff darauf auch atomar, oder? würde ich pauschal nicht sagen. Das ist dann wirklich abhängig von der Hardware. > Volatile hat doch aber auch den Zweck, dass der Compiler nicht meint > Code optimieren zu können weil sich der Inhalt der Variable nicht > geändert haben kann. > Insofern braucht man IMMER volatile wenn mindestens eine ISR im Spiel > ist, hier vor allem weil der höher priorisierte Interrupt den > niedrigeren unterbrechen und die Variable ändern kann. ihm ist aber egal, ob er den alten stand noch liest. Und nach dem eine ISR neu aufgerufen wird muss sie eh aus dem Speicher gelesen werden. Volatile würde also nur bewirken, das sich innerhalb der Ausführung der ISR die Variabel soft ändern kann - das braucht er aber nicht.
Peter II schrieb: > ihm ist aber egal, ob er den alten stand noch liest. Und nach dem eine > ISR neu aufgerufen wird muss sie eh aus dem Speicher gelesen werden Richtig, wobei das eine sehr zweifelhaftes Design ist nur um sich ein Volatile (und den geringen Overhead, der daraus resultiert) zu sparen. Das weiss 3 Monate nach dem Schreiben des Codes nicht mal der TO mehr. Sowas ergibt dann unwartbarer Code.
Der Andere schrieb: > Richtig, wobei das eine sehr zweifelhaftes Design ist nur um sich ein > Volatile (und den geringen Overhead, der daraus resultiert) zu sparen. sehe ich nicht so. Eine ISR sollte so schnell wie möglich sein, da kann ein volatile schon zu viel sein. Und das verhalten ist ja definiert, damit kann man sich auch darauf verlassen.
Peter II schrieb: > Volatile würde also nur bewirken, das sich innerhalb der Ausführung der > ISR die Variabel soft ändern kann - das braucht er aber nicht. Ich würde: 1. die Variable volatile machen 2. In der ISR die volatile Variable in eine lokale Variable kopieren 3. Mit der lokalen Variablen weiterarbeiten Dann sollte eine Änderung während der ISR durch eine zweite ISR egal sein.
Christopher B. schrieb: > Es ist nicht schlimm, wenn ISR_B einen veralteten Wert der Variable > bekommt. Sollte es aber irgendwann mal mitbekommen das ISR_A den Wert > geaendert hat. Was genau ist darunter zu verstehen? Insbesondere der Teil 'sollte es aber irgendwann mitbekommen' ist interessant. Was verstehst du darunter? Wartet die ISR B darauf, dass die ISR A den Wert ändert? > Muss die Variable volatil sein? Im Zweifelsfall: ja Denn dann laufen die Dinge genau so, wie du sie hingeschrieben hat und keine Optimierung kann dir da reinpfurzen.
:
Bearbeitet durch User
@Christopher B. (chrimbo) >ISR_A hat eine hoehere Prioritaet als ISR_B. ISR_A kann ISR_B >unterbrechen. >ISR_A greift schreibend auf eine globale Variable eines anderen Moduls >zu (Ueber die Systemarchitektur bitte ich hinwegzusehen, darum geht es >nicht). >ISR_B greift nur lesend auf diese Variable zu. Ob nur lesen/schreiben ist egal, man brauch IMMER volatile und IMMER einen ATOMAREN Zugriff, hier auch in ISR_B. In ISR_A muss er nicht atomar sein bzw. er ist es automatisch, da ISR_A durch nichts anderes unterbraochen werden kann. Siehe Interrupt. >geholt, geschrieben, gelsen, was weiss ich und bevor die ISR verlassen >wird wird dann zurueck in den Speicher geschrieben?! Sicher, weil es praktisch keinen Sinn macht, Teile einer Struktur lokal zu speichern. Absolut sicher ist es nur mit volatile. Der Zugriff erfolgt exakt dort, wo er im Programm steht, nicht erst am Ende der ISR. >Ich vermute es kommt auf den Einzelfall an und im Zweifel wird ein Blick >ins Assembler Listing noetig sein, Nein. >oder pauschal als volatil >deklarieren. Ja.
Falk B. schrieb: > Ob nur lesen/schreiben ist egal, man brauch IMMER volatile und IMMER > einen ATOMAREN Zugriff, hier auch in ISR_B. In ISR_A muss er nicht > atomar sein bzw. er ist es automatisch, da ISR_A durch nichts anderes > unterbraochen werden kann. Siehe Interrupt. warum volatile? E s gibt keinen Grund dafür wenn sie die Variabel innerhalb von einem ISR Aufruf nicht ändern muss! Bei Eintritt werden immer alle Variablen aus dem Ram geladen und beim Verlassen wieder zurückgeschrieben auch ohne Volatile.
Peter II schrieb: > Bei Eintritt werden immer alle Variablen aus dem Ram geladen und beim > Verlassen wieder zurückgeschrieben auch ohne Volatile. Ja, das schon. Aber wo ist garantiert, dass der in main() zugewiesene Wert tatsächlich schon in der globalen Variablen gespeichert ist? Grundsätzlich kann der Compiler die Variable unendlich lang in einem Register halten. Den Einsprung in die ISR() sieht er ja nicht.
:
Bearbeitet durch Moderator
@ Peter II (Gast) >warum volatile? Schrieb ich das nicht bereits? > E >s gibt keinen Grund dafür wenn sie die Variabel innerhalb von einem ISR >Aufruf nicht ändern muss! Wir reden von einer UNTERBRECHENBAREN ISR. Ausserdem geht es bei volatile darum, dass ABSOLUT sichergestellt ist, dass KEINERLEI Optimierung mit lokalen Speicherbereichen vorgenommen wird. Das kann aber passieren, wenn die ISRs in verschiedenen .c Dateien liegen, welche getrennt übersetzt werden. >Bei Eintritt werden immer alle Variablen aus dem Ram geladen und beim >Verlassen wieder zurückgeschrieben auch ohne Volatile. Nicht zwingend, auch wenn es zu 99,9% so ist! Ein agressiver Optimierer kann da Variablen lokal halten.
Frank M. schrieb: > Ja, das schon. Aber wo ist garantiert, dass der in main() zugewiesene > Wert tatsächlich schon in der globalen Variablen gespeichert ist? es gibt keinen zugriff in der main! > >Bei Eintritt werden immer alle Variablen aus dem Ram geladen und beim > >Verlassen wieder zurückgeschrieben auch ohne Volatile. > Nicht zwingend, auch wenn es zu 99,9% so ist! Ein agressiver Optimierer > kann da Variablen lokal halten. wo soll das lokal sein? Es gibt kein "Außerhalb" einer ISR.
Falk B. schrieb: > Wir reden von einer UNTERBRECHENBAREN ISR. Ausserdem geht es bei > volatile darum, dass ABSOLUT sichergestellt ist, dass KEINERLEI > Optimierung mit lokalen Speicherbereichen vorgenommen wird. Das kann > aber passieren, wenn die ISRs in verschiedenen .c Dateien liegen, welche > getrennt übersetzt werden. genau das ist auch gut so. Warum sollte man diese Optimierung auch mit volatile verhindern? Sie kann doch während der ISR im Register gehalten werden.
"ISR_A greift schreibend auf eine globale Variable eines anderen Moduls zu" Damit das bei getrennt compilierten ISRs SICHER funktioniert, braucht man volatile. Und explizit atomaren Zugiff in der niederpriorisierten ISR. Diese ist hier genauso zu betrachten wie ein Zugiff aus dem Nicht-ISR Programm in main().
:
Bearbeitet durch User
Falk B. schrieb: > "ISR_A greift schreibend auf eine globale Variable eines anderen Moduls > zu" > > Damit das bei getrennt compilierten ISRs SICHER funktioniert, braucht > man volatile. Und explizit atomaren Zugiff in der niederpriorisierten > ISR. Diese ist hier genauso zu betrachten wie ein Zugiff aus dem > Nicht-ISR Programm in main(). nein, braucht man nicht. Es spielt keine rolle, ob die ISR sich verschachtelt aufrufen. Wie schon geschrieben: >Bei Eintritt werden immer alle Variablen aus dem Ram geladen und beim >Verlassen wieder zurückgeschrieben auch ohne Volatile. nur das ist wichtig. Oder wenn die Änderung der Variable sofort in der anderen ISR ankommen soll, was hier aber nicht gefordert ist! Das Atomar Problem ist davon getrennt.
Peter II schrieb: >>Bei Eintritt werden immer alle Variablen aus dem Ram geladen und beim >>Verlassen wieder zurückgeschrieben auch ohne Volatile. > > nur das ist wichtig. Oder wenn die Änderung der Variable sofort in der > anderen ISR ankommen soll, was hier aber nicht gefordert ist! Nein, das ist Sch....lecht. Nach Deiner Logik misslingt das: Nennen wir die globale Variable foo. ISR_B liest nur die Variable, ISR_A beschreibt sie. 1) ISR_B wird aufgerufen und benutzt foo mit dem Wert 42. 2) ISR_A unterbricht ISR_B und schreibt in foo den Wert 22. 3) ISR_A beendet sich, die 22 wird im RAM gespeichert 4) ISR_B beendet sich, die noch-42 wird im RAM gespeichert. Folge: im RAM steht wieder der alte Wert 42 statt der neue Wert 22. Jedenfalls nach Deiner Logik. Nach meiner Logik findet glücklicherweise Schritt 4 in der Realität gar nicht statt. Aber nur, weil ISR_B die Variable nicht verändert. Glück gehabt! Ich halte Deinen Vorschlag trotzdem für unsauber, ich würde volatile nehmen. Da weiß ich wenigstens, was passiert.
:
Bearbeitet durch Moderator
Erstmal danke für die Antworten und ich erkenne an der Diskussion, dass es wohl wirklich nicht so klar ist und freue mich darueber zum Denken angeregt zu haben. Karl H. schrieb: > Was genau ist darunter zu verstehen? > Insbesondere der Teil 'sollte es aber irgendwann mitbekommen' ist > interessant. Was verstehst du darunter? > Wartet die ISR B darauf, dass die ISR A den Wert ändert? Nein, B wartet nicht auf A. Irgendwann ist natuerlich schwammig formuliert. Sagen wir im naechsten Aufruf von B. VG Christopher
@ Frank M. (ukw) Benutzerseite >Ich halte Deinen Vorschlag trotzdem für unsauber, ich würde volatile >nehmen. Da weiß ich wenigstens, was passiert. Eben. Wo liegt das Problem? Die volatile-Variable wird sicher nicht die Performance des Controllers in die Knie zwingen.
Frank M. schrieb: > 1) ISR_B wird aufgerufen und benutzt foo mit dem Wert 42. > 2) ISR_A unterbricht ISR_B und schreibt in foo den Wert 22. > 3) ISR_A beendet sich, die 22 wird im RAM gespeichert > 4) ISR_B beendet sich, die noch-42 wird im RAM gespeichert. > > Folge: im RAM steht wieder der alte Wert 42 statt der neue Wert 22. Aufgabe Lesen!!!! er schriebt nur ein einer ISR und in der anderen liest er. Übrigens, lößt Volatile das Problem nicht. Denn es gibt auch hier das loch, das die Variabel kurz im Register ist.
Frank M. schrieb: > Nennen wir die globale Variable foo. ISR_B liest nur die Variable, ISR_A > beschreibt sie. Peter II schrieb: > Aufgabe Lesen!!!! Siehe oben, das steht sogar in meiner Annahme: "ISR_B liest nur die Variable". Wer kann da nicht lesen? > er schriebt nur ein einer ISR und in der anderen liest er. Jepp, und genau deshalb hast Du Glück, dass es so funktioniert. Deshalb wird Schritt 4 nicht ausgeführt! Deine pauschale Aussage: "Bei Eintritt werden immer alle Variablen aus dem Ram geladen und beim Verlassen wieder zurückgeschrieben auch ohne Volatile." stimmt nämlich nicht für ISR_B. Da wird nämlich nix zurückgeschrieben.
:
Bearbeitet durch Moderator
Frank M. schrieb: > Jepp, und genau deshalb hast Du Glück, dass es so funktioniert. was hat das mit Glück zu tun, genau das will Christopher B. und dafür ist kein Volatile notwendig.
Peter II schrieb: > was hat das mit Glück zu tun, [...] Du hast deshalb Glück, weil der avr-gcc so klug ist, unveränderte Variablen am Ende der ISR nicht wieder zurückzuschreiben. Es kann natürlich sein, dass man auf der Welt keinen so dummen C-Compiler findet, der das tatsächlich täte. Falsch wäre es aber nicht. Und deshalb nutzt Du hier eine Vermutung zum Verhalten des C-Compilers aus. Deshalb: volatile und gut ist. Innerhalb der ISR (auch ISR_B wegen Unveränderbarkeit) kann man ja den Wert der volatile-Variablen in eine lokale Variable kopieren und am Ende wieder zurück (was man in ISR_B natürlich tunlichst unterlässt). Damit macht man das dann selber und weiß dann auch, was da passiert.
:
Bearbeitet durch Moderator
Peter II schrieb: > Falk B. schrieb: >> "ISR_A greift schreibend auf eine globale Variable eines anderen Moduls >> zu" >> >> Damit das bei getrennt compilierten ISRs SICHER funktioniert, braucht >> man volatile. Und explizit atomaren Zugiff in der niederpriorisierten >> ISR. Diese ist hier genauso zu betrachten wie ein Zugiff aus dem >> Nicht-ISR Programm in main(). > > nein, braucht man nicht. So, so. Du bist also in der Lage dem Compiler vorschreiben zu können, welche Register er wie verwenden wird? Dir ist schon bewusst, dass ein Compiler einen Schreibzugriff auf eine Variable auch komplett unter den Tisch fallen lassen kann, wenn er keinen Sinn darin sieht? Ohne volatile ist noch nicht einmal garantiert, dass die ISR_A überhaupt die Variable beschreibt! Compiler sind ziemlich gut darin, Code der (aus seiner Sicht) keinen Effekt hat zu identifizeren und hinauszuwerfen.
:
Bearbeitet durch User
Karl H. schrieb: > So, so. > Du bist also in der Lage dem Compiler vorschreiben zu können, welche > Register er wie verwenden wird? ja, denn am ende der ISR muss er sie in dem Ram schreiben ob er will oder nicht. > Dir ist schon bewusst, dass ein Compiler einen Schreibzugriff auf eine > Variable auch komplett unter den Tisch fallen lassen kann, wenn er > keinen Sinn darin sieht? kann er in diesem fall nicht. Sobald sie an einer anderen stelle im Quellcode verwendet wird.
@ Karl Heinz (kbuchegg) (Moderator) >Ohne volatile ist noch nicht einmal garantiert, dass die ISR_A überhaupt >die Variable beschreibt! Meine Rede. Aber einem kleinen E-Techniker glaub ja keiner ;-)
Peter II schrieb: > ja, denn am ende der ISR muss er sie in dem Ram schreiben ob er will > oder nicht. Wenn sie nicht geändert wurde, dann muss er sie nicht ins RAM schreiben. Und genau das rettet Dir den Arsch.
@ Peter II (Gast) >> So, so. >> Du bist also in der Lage dem Compiler vorschreiben zu können, welche >> Register er wie verwenden wird? >ja, denn am ende der ISR muss er sie in dem Ram schreiben ob er will >oder nicht. Soso, du kennst also gute, optimierende Compiler in und auswendig? Und die können auf keinen Fall Variablen in ISRs dauerhaft in Registern halten? Zumal reine Schreibzugriffe ohne Lesezugriff in der gleichen ISR bzw. gleiche Datei (= Übersetzungseinheit) einem WOM gleichkommen und ganz fix rausfliegen! int a; main() { a=1; } Ja das mal durch deinen Compiler mit aktiver Optimierung und staune ;-)
Falk B. schrieb: > Soso, du kennst also gute, optimierende Compiler in und auswendig? Und > die können auf keinen Fall Variablen in ISRs dauerhaft in Registern > halten? können sie nicht, wenn sie woanders verwendet werden. Dann die ISR wird beendet und es gibt keine "außerhalb" Kontext. du scheinst es mit Threads zu verwechseln, die einen eigenen Threadkontext haben. > Wenn sie nicht geändert wurde, dann muss er sie nicht ins RAM > schreiben. Und genau das rettet Dir den Arsch. nur löst volatile diesem Problem überhaupt nicht. Dafür muss man mit locks arbeiten. selbst mit volatile geht variabel+++ in 2 ISR schief.
Frank M. schrieb: > unveränderte > Variablen am Ende der ISR nicht wieder zurückzuschreiben. Es kann > natürlich sein, dass man auf der Welt keinen so dummen C-Compiler > findet, der das tatsächlich täte. Falsch wäre es aber nicht. nun ja, wenn er einen Schreibzugriff macht obwohl die Variable nur gelesen wird, dann waere das wohl falsch. Wie dem auch sei. Danke an alle. Es wird jetzt als volatile deklariert um ganz sicher zu gehen ;-) LG Christopher
Falk B. schrieb: > int a; > > main() > { > > a=1; > > } > > Ja das mal durch deinen Compiler mit aktiver Optimierung und staune ;-) Sorry, Falk, auch wenn es Dir (und mir) nicht gefällt:
1 | 00000090 <main>: |
2 | 90: 81 e0 ldi r24, 0x01 ; 1 |
3 | 92: 90 e0 ldi r25, 0x00 ; 0 |
4 | 94: 90 93 01 01 sts 0x0101, r25 |
5 | 98: 80 93 00 01 sts 0x0100, r24 |
6 | 9c: 80 e0 ldi r24, 0x00 ; 0 |
7 | 9e: 90 e0 ldi r25, 0x00 ; 0 |
8 | a0: 08 95 ret |
Die 1 wird tatsächlich im RAM abgelegt, auch wenn sie weiterhin nicht genutzt wird. Da reicht es aus, dass sie global ist. avr-gcc 4.7.2 getestet mit -Os und -O2. Bei -O2 steht sogar noch mehr Code drin.
Falk B. schrieb: > int a; > > main() > { > > a=1; > > } hm... interessant. Wie sieht es mit folgendem (fiktiven) Konstrukt aus? mod.c:
1 | int a; |
2 | |
3 | void foo(void) |
4 | {
|
5 | if(a) |
6 | {
|
7 | // Ereignis eingetreten
|
8 | }
|
9 | }
|
main.c:
1 | extern int a; |
2 | int main(int , char**) |
3 | {
|
4 | a = 1; |
5 | }
|
wobei dann foo aus einem Interrupt aufgerufen wird.
Christopher B. schrieb: > wobei dann foo aus einem Interrupt aufgerufen wird. kann man nicht sagen, man müsste zumindest noch eine endlosschleife einbauen. Aber in der Aufgabe ging es um 2 ISR und nicht um eine Main. Das ist ein großer unterschied.
Peter II schrieb: > Aber in der Aufgabe ging es um 2 ISR und nicht um eine Main. Das ist ein > großer unterschied. Das ist mir bewusst. Falk begann aber mit der Main und es sollte ja auch nur ein fiktives Beispiel sein.
Hier mal ein Test, auch wenn er gegen mich ausgeht ;-) Frage: Kann es sein, dass Compiler bzw. der avr gcc bei ISRs Ausnahmen bezüglich des Variablenzugriffs machen? Sprich, dass globale Variablen NIE lokal optimiert bzw. zwischengespeichert werden können?
Falk B. schrieb: > Frage: Kann es sein, dass Compiler bzw. der avr gcc bei ISRs Ausnahmen > bezüglich des Variablenzugriffs machen? Sprich, dass globale Variablen > NIE lokal optimiert bzw. zwischengespeichert werden können? wo soll er sie den zwischenspeichern? Meines wissen sind alle ISR aufrufe in einer _MemoryBarrier definiert. Vor und nach der ISR muss alles im Ram landen.
@ Peter II (Gast) >wo soll er sie den zwischenspeichern? Keine Ahnung. >Meines wissen sind alle ISR aufrufe in einer >_MemoryBarrier >definiert. Vor und nach der ISR muss alles im Ram landen. Na zumindest nach der ISR. Vorher kann man ja nicht beeinflußen, dort läuft das Hauptprogramm an einer beliebigen Stelle ;-) Einigen wir uns so. Wenn NUR ISRs im Spiel sind kann man auf volatile Definition von globalen Variablen verzichten. Bei unterbrechenbaren (priorisierten) ISRs muss dennoch für atomaren Zugriff gesorgt werden.
Falk B. schrieb: > Wenn NUR ISRs im Spiel sind kann man auf volatile Definition von > globalen Variablen verzichten. Du kannst das nicht so verallgemeinern. Es klappt nur für diesen speziellen Fall in diesem Thread, wo ISR_B nur liest.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.