Hallo,
wenn ein Interrupt das laufende Programm unterbricht, kann dies auch
INNERHALB einer IF-Anweisung passieren?
Also zum Beispiel:
1
if((a<b)
2
&&(c<d)// <-- Unterbrechung möglich???
3
&&(e<f)
4
&&(g<h)
5
)
6
{
7
.
8
.
9
.
10
}
Wenn ein Interrupt an der markierten Stelle möglich wäre, würden die
ersten beiden Bedingungen also vor dem Interrupt auf wahr/falsch
überprüft und die letzten beiden Bedingungen erst nach dem Interrupt.
Oder wird die IF-Anweisung immer als Ganzes (also in dem Beispiel alle 4
Bedingungen) abgearbeitet, bevor der Interrupt beginnen kann?
Anders gefragt: wo genau kann ein Interrupt das laufende Programm
unterbrechen?
Verweise auf Links (Lexika,...), wo dies erklärt wird, sind sehr
willkommen!
Vielen Dank!
Torsten
Der Interrupt kann auch innerhalb der IF auftreten.
Ein Interrupt kann auch innerhalb einer Zuweisung auftreten.
Maßstab sind hier die einzelnen Maschinenbefehle. Eine C-Anweisung wird
i.d.R. in eine Mehrzahl davon zerlegt und solange Interrupts
eingeschaltet sind kann ein Interrupt zwischen jedem dieser Befehle
angesprungen werden.
Wenn keine besonderen Maßnahmen getroffen werden kann das von dir
geschilderte Szenario auftreten.
Wenn dies aus Programmtechnischen Gründen nicht erlaubt sein darf,
kannst du vor Beginn deiner wichtigen Routine die Interrupts abschalten
und danach wieder einschalten. Das kann dann aber zu Verzögerungen bei
der Ausführung des Interrupts führen.
@ Torsten Schmidt (grizu)
>wenn ein Interrupt das laufende Programm unterbricht, kann dies auch>INNERHALB einer IF-Anweisung passieren?
Ja.
>if ( (a < b)> && (c < d) // <-- Unterbrechung möglich???
Ja.
>Wenn ein Interrupt an der markierten Stelle möglich wäre, würden die>ersten beiden Bedingungen also vor dem Interrupt auf wahr/falsch>überprüft und die letzten beiden Bedingungen erst nach dem Interrupt.
Ja.
>Oder wird die IF-Anweisung immer als Ganzes (also in dem Beispiel alle 4>Bedingungen) abgearbeitet, bevor der Interrupt beginnen kann?
Nein.
>Anders gefragt: wo genau kann ein Interrupt das laufende Programm>unterbrechen?
jetderzeit, auch "in" C-Anweisungen, weil diese ja meist aus vielen
Maschinenbefehlen bestehen.
>Verweise auf Links (Lexika,...), wo dies erklärt wird, sind sehr>willkommen!
Siehe Interrupt. Stichwort atomar.
MfG
Falk
Hi
>Wenn keine besonderen Maßnahmen getroffen werden kann das von dir>geschilderte Szenario auftreten.
Wenn die Befehlszeile mehrere Assemblerbefehle repräsentiert kann die
Unterbrechung vor oder auch nach dem eigentlichen Vergleich auftreten.
Mfg Spess
Torsten Schmidt schrieb:> Verweise auf Links (Lexika,...), wo dies erklärt wird, sind sehr> willkommen!
Das Lexikon aller Weisheiten zu einem Prozessor heißt Datenblatt.
Das steht sehr detailliert drin, was in welcher Reihenfolge bei
auftreten eines Interrupts alles passiert. Das ist von Prozessor zu
Prozessor unterschiedlich.
Aber bei allen gilt: Der Prozessor kennt nur seine Maschinensprache, und
Interrups können in der Regel nach jedem Befehl daraus unterbrechen. Ob
das Programm dabei aus einer höheren Programmiersprache kompiliert
wurde, oder nicht, ist dem egal.
Oliver
>>wenn ein Interrupt das laufende Programm unterbricht, kann dies auch>>INNERHALB einer IF-Anweisung passieren?
Ja!
Für den Prozessor gibt es keine "IF-Anweisung". Diese wird vom Compiler
in Maschinensprache umgesetzt woraus sich dann eine Sequenz von mehreren
Anweisungen ergibt. In etwa so
- vergleiche a mit b
- wenn a größer als b, gehe zu anweisung xxx
- vergeliche c mit d
- ...
Diese einzelnen Anweisungen sind dann quasi elementar und nicht
unterbrechbar. Es wird dann zwischen den Zeilen unterbrochen.
spess53 schrieb:> Wenn die Befehlszeile mehrere Assemblerbefehle repräsentiert kann die> Unterbrechung vor oder auch nach dem eigentlichen Vergleich auftreten.
Wenn die zu vergleichenden Daten breiter sind, als die Registerbreite,
kann ein Interrupt auch mitten im Vergleich auftreten.
Oliver
Dagegen macht man solche C Konstrukte 'atomic'.
Das bedeutet, man schaltet im schlimmsten Fall vor diesem Bereich alle
Interrupts tot, und danach wieder an.
Beim Cortex-M3 z.B. hat der NVIC ein Register (BasePri), in welchem man
Interrupts unterhalb einer programmierbaren Priorität disablen kann, so
dass wichtige Interrupts, die diesen Programmbereich nciht gefährden
(Stichwort 'shared memory') weiterhin aktiv und ausführbar bleiben.
Um beim CM3 zu bleiben, zwei weitere Register mit jeweils einem Bit
(PriMask, Faultmask) schalten die externen oder externen + internen
Interrupts lahm.
VG,
/th.
Ich möchte noch ergänzen, dass bei entsprechendem Design das sperren von
Interrupts nicht nötig ist.
Ganz allgemein ist die Frage, ob in dem fraglichen Interrupt eine der
Variablen geändert werden kann, die in der IF-Bedingung geprüft wird.
Als zweites ist die Frage notwendig, ob die Variable(n) in ein
Maschinenwort passt oder nicht. Evtl. mit dem Zusatz ob dies evtl. für
mehrere Variablen in der Bedingung unterschiedlich ist.
Als drittes die Frage ob es für die Funktion des Programmes in Ordnung
ist, wenn die Reaktion auf den Interrupt in main verzögert ablaufen
darf. Dabei wird das übliche Designmuster vorausgesetzt, dass Interrupts
lediglich Flags setzen und diese in einer while-Schleife in main immer
wieder getestet werden.
Falls die Antwort auf die erste Frage Nein lautet, sind keine besonderen
Maßnahmen oder Überlegungen notwendig. Sonst:
Falls die Antwort auf die zweite Frage ergibt, das eine der im Interrupt
gesetzten und in der Bedingung abgefragten Variablen mehr als ein
Maschinenwort belegt, so sollte die Auswertung atomic sein (was heisst,
das Interrupts gesperrt werden). Evtl. bietet es sich an, die Auswertung
in eine Funktion auszulagern und nur den relevanten Vergleich atomic zu
machen. Dazu müsste noch betrachtet werden ob alle Variablen (bis auf
die Ausführungszeit) synchron verändert werden.
Falls nicht:
Falls die Antwort auf die dritte Frage ergibt, das eine Verzögerung
zulässig ist, dann brauchen keine besonderen Maßnahmen ergriffen werden.
Als erstes sollte geprüft werden wie oft der Interrupt ausgelöst wird
und wie oft im Vergleich dazu die Schleife mit der Bedingung durchlaufen
wird.
Evtl. hast Du ein anderes Designpattern. In diesen Fall poste mal den
Code.
Vielen Dank für die vielen guten Antworten!
@Grrrr:
1. Frage: ja, eine der Variablen wird durch den Interrupt verändert.
2. Frage: alle Variablen passen in ein Maschinenwort
(16-Bit-Mikrocontroller, die Variable ist ebenfalls 16 Bit lang).
3. Die Reaktion auf den Interrupt darf in der "main" verzögert ablaufen.
Ich will mein Problem mal konkretisieren. Bitte vergesst dazu die im
ersten Posting genannte IF-Abfrage, da diese ein Teil einer von mir
ausgedachten Lösung ist, aber eventuell braucht man diese IF-Abfrage gar
nicht.
Ich möchte die zeitlichen Abstände zwischen Ereignissen A1, A2, A3, ...
An einerseits und die zeitlichen Abstände zwischen Ereignissen B1, B2,
B3, ... Bn andererseits messen. Für beide Ereignis-Reihen benutze ich
den gleichen Input Capture. Der im Input Capture benutzte Base Timer hat
16 Bit, was nicht ausreichend ist, um die Zeiten mit entsprechender
Genauigkeit und Länge zu messen. Daher habe ich mir einen 32-Bit-Zähler
erzeugt, indem ich einen High-Word-Zähler hochzähle, wenn der Base Timer
überläuft und dadurch einen "Überlauf-Interrupt" auslöst.
Der Überlauf-Interrupt muss eine höhere Priorität haben als der
Input-Capture-Interrupt, da ich sonst einen Überlauf verpassen würde,
wenn dieser während der Ausführung des Input-Capture-Interrupts für An
passiert und gleichzeitig das zweite Ereignis Bn passiert. Dann würde
nämlich der Input-Capture-Interrupt gar nicht beendet (while-Schleife
bis alle Ereignisse abgearbeitet sind) und daher würde die Abarbeitung
des zweiten Input-Capture-Ereignisses (Bn) den Überlauf nicht
mitbekommen. Also muss der Überlauf eine höhere Priorität haben.
Andererseits darf der High-Word-Zähler nicht hochzählen, wenn der
Überlauf nach dem Ereignis An geschieht, aber noch vor dem Verarbeiten
des Zählers im Input-Capture-Interrupt.
Genau das war am Anfang nämlich mein Problem: Ereignis An hat den
Input-Capture-Interrupt ausgelöst, ganz kurz danach gab es den Überlauf,
so dass mein 32-Bit-Zähler um einen Überlauf (also um 0x10000) zu hoch
war.
Eventuell wäre die Lösung, die Priorität des Überlauf-Interrupts am
Anfang des Input-Capture-Interrupts kurzzeitig niedriger zu setzen -
eben so lange, wie der 32-Bit-Zähler nicht berechnet ist. Wenn man also
gleich im ersten Befehl des Input-Capture-Interrupts die Priorität des
Überlauf-Interrupts verringert. Meine Frage wäre dazu: kann es
passieren, dass zwischen dem Aufruf des Input-Capture-Interrupts und der
Ausführung des ersten Befehls (dem Verringern der Priorität des
Überlauf-Interrupts) der Überlauf-Interrupt zuschlägt? Dies wäre ein
seltener Fall, aber alles was passieren kann, wird früher oder später
passieren und dann hätte ich mit dieser Lösung nichts gewonnen.
Die gleiche Frage/das gleiche Problem hat die Idee, in der ersten Zeile
des Input-Capture-Interrupts den High-Word-Zähler in eine lokale
Variable zu speichern, um nachfolgende Änderungen zu verhindern.
Danke im voraus für die Hilfe!
Torsten
spess53 schrieb:> Wenn die Befehlszeile mehrere Assemblerbefehle repräsentiert kann die> Unterbrechung vor oder auch nach dem eigentlichen Vergleich auftreten.
Und auch manche Assembler-Befehle können nicht-atomar sein, wenn sie auf
mehrere Prozessor-Befehle abgebildet werden, z.B. bei ARM-Prozessoren
die Befehle MOV32, ADRL. Folglich kann auch ihre Ausführung mittendrin
unterbrochen werden.
Wenn es zulässig ist, fragwürdige Messergebnisse zu ignorieren, dann
sollte es ausreichen, alle Capture-Werte dicht am oberen Grenzbereich
des Zählers (z.B. 0xFF00-0xFFFF) zu ignorieren. Denn das sind jene
Werte, bei denen es möglich ist, dass der Overflow-Interrupt nach dem
Capture-Event aber vor dem Auslesen des Overflow-Counters zuschlug.
Wenn im Capture-Handler der aktuelle Wert des Timers kleiner ist als der
Capture-Wert, dann war dazwischen ein Overflow und der kann entsprechend
rausgerechnet werden. Natürlich muss man den Wert des Timers dabei
zusammen mit dem Overflow-Counter konsistent kriegen, aber anders als
beim Capture ist dies problemlos möglich.
1
volatileuint16_toverflow_counter;// zählt die Overflows
Mit "OverflowInterruptPending" ist das entsprechende Bit vom Timer
gemeint. Eine Absicherung für den Fall, dass der Overflow-Interrupt zwar
vor/mit dem Auslesen des Timers ausgelöst wird, der Handler aber aus
irgendwelchen Controller-internen Gründen erst nach dem Auslesen des
overflow_counters (im while) läuft.