Hallo, ich habe mich gerade im AVR-GCC-Tutorial den Abschnitt gelesen, wie man Codesequenzen schreibt, welche via Interrupt nicht unterbrochen werden können. Macht es Sinn, diesen Ansatz auch innerhalb von ISR zu nutzen? //timer 2 overflow SIGNAL(SIG_OVERFLOW2) { uint8_t tmp_sreg = SREG; cli(); TCNT2 = 0xE0; //mach irgendwas... SREG = tmp_sreg; } Viele Grüße Tommy
Tommy Müller wrote: > Macht es Sinn, diesen Ansatz auch innerhalb von ISR zu nutzen? Nein, laß alles weg. Der AVR hat keine Interruptprioritäten und damit sind Interrupts immer schon atomar. Peter
Was macht der AVR, wenn er gerade eine ISR abarbeitet und ein neuer Interrupt "einläuft"? Gibt es dann so eine "Stack"? Tommy
>Was macht der AVR, wenn er gerade eine ISR abarbeitet und ein neuer >Interrupt "einläuft"? Gibt es dann so eine "Stack"? Er legt sich hin und stellt sich tot!
Ernsthaft: Er arbeitet die ISR zuende ab, springt dahin zurück, wo er herkam, gibt wieder alle Interrupts frei und stellt fest, dass da ein freigegebener Interrupt aufgetreten ist. Und springt in dessen ISR. AVR haben keine Interrupt-Prioritäten wie sie z.B. die 8051er haben.
Wenn eine ISR verlassen wird und in der Zwischenzeit (also während die ISR ausgeführt wurde) andere Interrupts aufgetreten sind, werden diese nach dem Rücksprung ins Hauptprogramm in der Reihenfolge abgearbeitet, wie sie in der Vektortabelle stehen (je niedriger die Vektoradresse, desto höher die "Pseudo-Priorität". "Pseudo" deshalb, weil es keine "echte" Priorität im Sinne von "höhere Priorität unterbricht niedrigere Priorität" ist, sondern lediglich eine Abarbeitungsreihenfolge). Es kann natürlich dadurch passieren, dass ein Interrupt mit niedriger Adresse so oft auftritt, dass nur noch dieser bearbeitet wird, aber das ist dann ein Fehler des Programmierers... Außerdem wird beim Einsprung in eine ISR automatisch durch die Hardware des Controllers das I-Bit im SREG gelöscht, so dass man das nicht von Hand machen muss. Es wird erst beim Verlassen der ISR wieder gesetzt (auch automatisch durch die Hardware). Deshalb ist ein cli() am Anfang der ISR überflüssig.
Vielen Dank für eure Antworten ... ich finde es immer schön, wenn die Artikel durch "trollige" Postings etwas aufgelockert werden ;-) Grüße Tommy
Mit Ausnahme des alten AT90S1200 hat bei den AVRs jede Interruptquelle ein Pending-Flag. Damit merkt sich der AVR, daß noch ein Interrupt anhängig ist und versucht ihn sobald wie möglich auszuführen. Alternativ kann man dieses Pending-Flag auch pollen und löschen, wenn man das Ereignis ohne Interrupt behandeln will. Auch kann es sein, daß man nach Verlassen des Interrupts oder längerer Interruptsperre garnicht mehr an älteren Ereignissen interessiert ist, dann löscht man das Pending-Bit unmittelbar vor dem RETI bzw. SEI. Und daß man Pending Bits beim AVR nicht mit 0 löschen kann, weiß ja jeder. Peter
@johnny.m >(auch automatisch durch die Hardware). Deshalb ist ein cli() am Anfang >der ISR überflüssig. Um die Restaurierung des SREG braucht man sich in ISR und C doch sowieso keine Gedanken zu machen, das macht der Compiler doch automatisch. MFG Falk
@Falk: Habe ich mit irgendeinem Wort die SREG-Restaurierung erwähnt? Es ging mir nur darum, dass das cli() und sei() durch die Controller-Hardware erledigt wird und deshalb im Programm überflüssig ist. Der Controller sorgt ganz alleine (und zwar völlig unabhängig von der Art der Programmierung) dafür, dass ISRs ohne weiteren Eingriff des Programmierers nicht unterbrochen werden können. Das SREG-sichern und zurückschreiben ist eine ganz andere Sache.
@johnny.m
>Habe ich mit irgendeinem Wort die SREG-Restaurierung erwähnt? Es ging
Locker bleiben ;-)
Mein Kommentar bezog sich im wesentlichen als Ergänzung auf die
Ursprungsfrage.
MfG
Falk
@Falk: Wenn Du Dich angegriffen gefühlt hast: War keine Absicht. Ehrlich.
>Außerdem wird beim Einsprung in eine ISR automatisch durch die Hardware >des Controllers das I-Bit im SREG gelöscht, so dass man das nicht von >Hand machen muss. Richtig. >Es wird erst beim Verlassen der ISR wieder gesetzt >(auch automatisch durch die Hardware). Kleine Korrektur: Nicht automatisch. Das I-Flag wird durch die "reti"-Instruktion genau im Moment (!) des Rücksprungs wieder gesetzt. Schreibt der Programmierer fälschlicherweise (oder auch absichtlich) nur ein "ret", so bleibt das I-Flag gelöscht, und alle Interrupts auch nach Verlassen des Interruptshandlers gesperrt.
@AVRFan: Eine ISR dauert grundsätzlich so lange, bis ein "reti" auftaucht, egal was sonst noch an programmiertechnischem Wahnsinn getrieben wird. Wenn kein "reti" da ist, obwohl da eins sein sollte, dann hat der Programmierer großen Mist gebaut. Das läuft dann unter "grober Programmfehler". Ich meinte oben natürlich "beim ordnungsgemäßen Verlassen der ISR" (hätte ich vll. direkt dazuschreiben sollen...). Und dabei macht die Hardware dann auch das, was sie soll. Solche Sachen nimmt einem aber tatsächlich der Compiler ab (genau wie das SREG-Sichern).
Peter Dannegger wrote: > Mit Ausnahme des alten AT90S1200 hat bei den AVRs jede Interruptquelle > ein Pending-Flag. Damit merkt sich der AVR, daß noch ein Interrupt > anhängig ist und versucht ihn sobald wie möglich auszuführen. Eine Einschränkung: pegelgesteuerte Externinterrupts bleiben nur so lange anhängig, wie der entsprechende Pegel tatsächlich anliegt. Verschwindet er also wieder, während die Interruptbearbeitung gerade gesperrt ist, dann wird danach die zugehörige ISR nicht abgearbeitet. (War zumindest bis ATmega16...128 noch so, aktuell habe ich da lange nicht mehr das Kleingedruckte im Datenblatt gelesen.)
>Eine ISR dauert grundsätzlich so lange, bis ein "reti" auftaucht, egal >was sonst noch an programmiertechnischem Wahnsinn getrieben wird. Ein "ret" beendet eine ISR gleichermaßen. Auch dann kehrt das Programm schließlich an die Stelle zurück, wo der Interrupt aufgetreten ist, und macht mit der nächsten Instruktion dort weiter. Lediglich das I-Flag bliebe bei "ret" gelöscht - so what? Ich könnte mir sogar Anwendungsfälle vorstellen, in denen das gewünscht ist (Beispiel: ein externer Interrupt soll nur genau einmal ausgelöst werden können). Dann spräche nicht das Geringste dagegen, ans Ende der entsprechenden ISR tatsächlich ein "ret" statt eines "reti" zu schreiben. >Solche Sachen nimmt einem aber tatsächlich der Compiler ab (genau wie das >SREG-Sichern). Sofern man mit einem solchen arbeitet. Aber bitte keine Grundsatzdiskussion über Vor- und Nachteile von Assemblern/Compilern/Whatever jetzt... lach
@AVRFan: Naja, da kann man jetzt tatsächlich endlos drüber diskutieren... Fest steht: Wenn man eine ISR mit einem ret beendet anstatt mit reti, dann sollte man schon ganz genau wissen, was man da tut. Oder die "i"-Taste ist kaputt...;-)
>Wenn man eine ISR mit einem ret beendet anstatt mit reti, dann >sollte man schon ganz genau wissen, was man da tut. Oder die "i"-Taste >ist kaputt...;-) Da gebe ich Dir allerdings recht :-)
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.