Forum: Compiler & IDEs Anfängerfrage - Kollision mehrer Interrupts


von snoopy (Gast)


Lesenswert?

Hallo,

ich habe mal eine prinzipielle Frage,

nehmen wir an, ich habe z.B. 2 Interruptquellen

a) schnell (Bilddarstellung/Refresh etc. - darf nicht gestört werden)
b) langsam (tritt ab und zu auf, irgendwas wird gezählt)

wenn ich nun in der Interruptroutine a) Interrups verbiete, kann diese 
frei laufen - z.B. Bilddarstellung ist ungestört - tritt aber 
währenddessen Interrupt(Ereignis) b) auf, verpasse ich dieses doch !!

Oder wartet die Verarbeitung von Interrupt b) nur, bis a) fertig ist 
(Warteschlange)?

Vielen Dank für eure Antworten,

Snoopy

von A.K. (Gast)


Lesenswert?

Wenn der Controller priorisierte Interrupts zulässt, hast du gewonnen. 
Dann ist nämlich beim höhere priorisierten Interrupt A automatisch B 
ausgeschlossen, umgekehrt kann aber A einen laufenden Interrupthandler B 
unterbrechen.

Der Rest wird erst im Austausch gegen ein bischen Information verraten: 
Welcher Controller?

von Thomas (Gast)


Lesenswert?

Es kommt auf die Prioriäten deiner IRQs an.

Wenn a) eine hohe Prio hat und b) eine niedrigere, dann wird a) nicht 
unterbrochen. Andersrum wird b) von a) unterbrochen, wenn b) gerade 
läuft und anschließend fortgesetzt.

Wenn b) eine hohe Prio hat und a) eine niedrigere, dann sollte beim 
start von a) die IRQs ausgeschaltet werden und später wieder an. 
Auftretende IRQS während dieser Zeit werden bis zu einer bestimmten 
Tiefe gespeichert und anschließend augeführt.

MfG

von snoopy (Gast)


Lesenswert?

Vielen Dank für die schnellen Antworten.

Ich beschäftige mich (noch theoretisch) mit AVRs und dachte so an ATMega 
(8,1,32) bzw. ATTiny 2313.

Es ergeben sich also folgende neuen Fragen:

Sind Interrupts bei diesen die Typen priorisierbar ?

Wenn ja, wie (oder ist das Fest verdrahtet) ?


Schon mal vielen Dank für eure Antworten.

Snoopy

von johnny.m (Gast)


Lesenswert?

Bei den AVRs gibt es, anders als z.B. bei den 8051ern, keine 
Interrupt-Prioritäten im engeren Sinne. Es existiert nur eine 
Abarbeitungsreihenfolge bei gleichzeitig auftretenden Ereignissen, die 
durch die Reihenfolge der Interrupt-Vektoren gegeben ist (niedrigste 
Vektoradresse -> wird zuerst bearbeitet).

Die Bearbeitung von Interrupt-Ereignissen wird beim Sprung in einen 
Interrupt Handler automatisch von der µC-Hardware deaktiviert (das I-Bit 
im Statusregister wird gelöscht), so dass keine weiteren Interrupts 
bearbeitet werden können, solange der aktive Interrupt Handler 
ausgeführt wird. Treten in dieser Zeit weitere Interrupt-Ereignisse auf, 
so werden die entsprechenden Interrupt-Flags gesetzt (das passiert 
immer, auch wenn der betreffende Interrupt gesperrt ist), jedoch erst 
dann bearbeitet, wenn das I-Bit im SREG wieder gesetzt ist. Dies 
geschieht beim Rücksprung aus dem Interrupt Handler (wiederum 
automatisch durch die Hardware). Sind während des aktuellen Interrupt 
Handlers mehrere neue Ereignisse eingetreten, dann werden diese nach dem 
Rücksprung ins Hauptprogramm in der Reihenfolge ihrer Vektoren 
bearbeitet (Allerdings wird nach dem Rücksprung aus einem Interrupt 
Handler mindestens ein Befehl im Hauptprogramm ausgeführt, bevor der 
nächste Interrupt Handler angesprungen wird).

Möchte man einen Interrupt Handler unterbrechbar machen, dann kann man 
am Anfang das I-Bit im SREG setzen. Dann kann allerdings im Prinzip 
jeder andere freigegebene Interrupt dazwischenhauen. Diese 
Vorgehensweise empfiehlt sich nur dann, wenn man eine überschaubare 
Anzahl von Interrupts benutzt und genau weiß, was man tut. I.d.R. ist es 
bei "vernünftiger" Programmierung (Interrupt Handler so kurz wie 
möglich) vermeidbar, unterbrechbare Interrupts zu verwenden. Ist man 
dennoch darauf angewiesen, dann muss man genau überlegen, was alles im 
konkreten Fall passieren kann.

von snoopy (Gast)


Lesenswert?

ok,

es müsste dann also folgendes auf einem ATTiny2313 funktionieren:

2 Interruptereignisse:

a) schneller Interrupt durch Timer 0 -> Refresh etc
b) langsamer Interrupt PCINT0

Prioriät:

RESET
INT0
INT1
TIMER0
TIMER1
PCINT0
PCINT1

Da a) höher priorisiert ist als b) wird a) ohne Unterbrechung 
ausgeführt.
Ist während der Ausführung von a) ein Interruptereignis b) aufgetreten, 
wird nach Abarbeitung von a) 1 Befehl des Hauptprogramms abgearbeitet 
und dann b) nachgeholt.
b) wird von a) beliebig unterbrochen.

Ist das so richtig?

Vielen Dank für die Hilfe.

Snoopy

von A.K. (Gast)


Lesenswert?

> Da a) höher priorisiert ist als b) wird a) ohne
> Unterbrechung ausgeführt.

Falsch. Wie johnny.m schon schrieb: "Bei den AVRs gibt es, anders als 
z.B. bei den 8051ern, keine Interrupt-Prioritäten im engeren Sinne.".

Was immer Atmel bei AVRs als Prioritäten bezeichnet, das dient in der 
Praxis eher der Verwirrung als der Information. Diese Priorität 
entscheidet nur, welchen Vektor der Prozessor benutzt, wenn zum 
betreffenden Zeitpunkt mehrere Anfragen anstehen. Irgendwelche 
Prioritäten zur Laufzeit den Interrupt-Handlers existieren bei AVRs 
NICHT!

Bei AVRs du muss also diesbezüglich selber tätig werden.

von Peter D. (peda)


Lesenswert?

Wenn man einen wirklich schnellen jitterarmen Interrupt braucht, wirds 
auf den AVRs haarig.

Es gibt im Prinzip 3 Möglichkeiten:


1.
Man verzichtet auf sämtliche anderen Interrupts und pollt diese im Main


2.
Man enabled einen 2. Timerinterrupt, der sich selber stoppt und dann die 
Interrupts global freigibt.
Dieser pollt dann alle anderen Interruptquellen und ruft deren Handler 
auf.
D.h. diese Interrupts werden quasi virtuelle Interrupts, dürfen also 
nicht wirklich freigegeben werden.

Dadurch erreicht man folgendes:

Der gestoppte Timer kann sich nicht selber unterbrechen
Nur der schnelle Interrupt kann ihn unterbrechen.

Allerdings werden sämtliche anderen Interruptquellen maximal durch das 
gewählte Timerintervall verzögert.


3.
Du nimmst ne andere MC-Familie mit Prioritäten, z.B. AT89LP4051


Peter

von snoopy (Gast)


Lesenswert?

ok,

wenn ich in a) zusätzlich am Anfang die Interrupts verbiete und am Ende 
wieder freigebe - wir dann ein b)-Ereignis nach Ende von a) (+ 1 x 
Hauptprogramm) trotzdem noch (verspätet) abgearbeitet ?

Danke für die Hilfe,

Snoopy

von Falk B. (falk)


Lesenswert?

@ snoopy

>a) schneller Interrupt durch Timer 0 -> Refresh etc
>b) langsamer Interrupt PCINT0

>Da a) höher priorisiert ist als b) wird a) ohne Unterbrechung
>ausgeführt.

Die Interruptroutinen werden auf dem AVR im allgemeinen immer ohne 
Unterbrechung ausgeführt, d.h eine Interruptroutine wird nicht von einem 
anderen Interrupt unterbrochen. Andere Prozessoren haben Prioritäten, da 
kann ein höherpriorisierter Interrupt einen nierderpriorisierten 
Iterrupt unterbrechen.
>Ist während der Ausführung von a) ein Interruptereignis b) aufgetreten,
>wird nach Abarbeitung von a) 1 Befehl des Hauptprogramms abgearbeitet
>und dann b) nachgeholt.

Ja.

>b) wird von a) beliebig unterbrochen.

Nein, nicht auf dem AVR. Man kann mit einigen Tricks das so hinbiegen, 
ist aber bisweilen schwierig.
MFG
Falk

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


Lesenswert?

Du musst wahrscheinlich einfach gar nichts weiter tun.  Lass dich von
den vielen ,,man kann das auch so und so machen''-Antworten mal nicht
zu sehr verwirren.  Beim AVR sind die Interrupts während der ISR
einfach gesperrt, damit läuft deine wichtige Routine immer bis zu
Ende durch.  Alle anderen Interrupts, die in dieser Zeit auftreten,
bleiben anhängig und werden nach deren Ende abgearbeitet.

Natürlich sollte dein wichtiger Interrupt nicht gerade so lange in
seiner Bearbeitung brauchen, dass zwei der anderen Interrupts in
dieser Zeit auftauchen können: dann würdest du natürlich nur noch
von einem ausgehen.  Zwei verschiedene andere Interrupts jedoch
werden (an Hand ihrer Interruptflags) unterschieden.

von Peter D. (peda)


Lesenswert?

Jörg Wunsch wrote:

> Natürlich sollte dein wichtiger Interrupt nicht gerade so lange in
> seiner Bearbeitung brauchen, dass zwei der anderen Interrupts in
> dieser Zeit auftauchen können:

Ich vermute, er wills genau umgekehrt:

Die unwichtigen Interrupts sollen nicht den wichtigen Interrupt 
verzögern.


Peter

von snoopy (Gast)


Lesenswert?

Vielen Dank für eure Antworten,

ich will mal meine Erkenntnisse zusammenfassen, um zu sehen, ob ich es 
nun prinzipiell verstanden habe.

bei ATmega (8, 16, 32) und Attiny2313 gelten folgende Aussagen:

1. Interrupts werden (bei "normaler" Anwendung) nicht durch andere 
unterbrochen, "wer zuerst kommt, malt zuerst"

2. Treten 2 Interruptereignisse gleichzeitig auf, wird der ausgeführt, 
dessen Vector in der Liste vorn steht (der andere steht in der 
Warteschlange)

3. Kann eine Interruptroutine nicht ausgeführt werden, da gerade eine 
andere Interruptroutine läuft, wird diese nach Beendigung der laufenden 
Routine (zwischendurch 1 Befehl Hauptprogramm) ausgeführt (steht 
sozusagen in einer Art Warteschlange).

Frage: wie viel darf sich denn in der Warteschlange so anstauen ? Liegt 
die auf dem Stack?

Fazit:

1. Interrupts gehen nicht verloren
2. wirklich exaktes Timing kann bei mehreren Interrupts nie garantiert 
werden

Ich sollte als besser in der schnellen, wichtigen Interruptroutine oder 
im Hauptprogramm das langsamere Ereignis pollen, also nur einen 
Interrupt verwenden.

Hab ichs jetzt ??

Vielen Dank,

Snoopy

von Karl H. (kbuchegg)


Lesenswert?

snoopy wrote:
> andere Interruptroutine läuft, wird diese nach Beendigung der laufenden
> Routine (zwischendurch 1 Befehl Hauptprogramm) ausgeführt (steht
> sozusagen in einer Art Warteschlange).

Die existiert aber nur auf einer logischen Ebene.

>
> Frage: wie viel darf sich denn in der Warteschlange so anstauen ? Liegt
> die auf dem Stack?

Nein.
Es existiert keine Warteschlange.
Für jeden Interrupt gibt es ein Flag in einem Register.
Ist das Flag gesetzt ist eine entsprechende Interrupt-
anforderung eingegangen.
Die CPU schaut einfach die Flags nach einem bestimmten
Schema (daher auch die Reihenfolge) durch: Ist das entsprechende
Flag gesetzt, wird der Interrupt ausgeführt. Kommt während
einer Interruptbearbeitung ein neuer Interrupt herein, wird
das entsprechende Flag gesetzt. Hat die CPU den bisherigen
Interrupt fertig, beginnt sie auch wieder sich um diese Flags
zu kümmern und findet dann das inzwishcen gesetzte Flag.

> 1. Interrupts gehen nicht verloren

Das kann man so nicht sagen.
Wenn man sich nur genug anstrengt, kann man sehr wohl
Interrupts verlieren.

> 2. wirklich exaktes Timing kann bei mehreren Interrupts nie garantiert
> werden

Yep.

>
> Ich sollte als besser in der schnellen, wichtigen Interruptroutine oder
> im Hauptprogramm das langsamere Ereignis pollen, also nur einen
> Interrupt verwenden.

Das kommt drauf an welche Timingvorstellungen du hast.
EIn µC ist ja kein Beamter, bei dem das Blumengiessen von
9:30 bis 10:15 Uhr dauert. Der ist schon ein bischen schneller.

von Falk B. (falk)


Lesenswert?

@ snoopy

1.-3. Alles Korrekt.

>Frage: wie viel darf sich denn in der Warteschlange so anstauen ? Liegt
>die auf dem Stack?

Nö, das sind die Interrupt-Flags in den Registern. Also theoretisch und 
praktisch können alle gleichzeitig gesetzt sein, das sollte die Hardware 
nciht aus dem Tritt bringen. Ob es die Software verkraftet ist eine 
andere Frage. ;-)

>1. Interrupts gehen nicht verloren

Interrupts gehen nur verloren, wenn während eines laufenden Interrupts 
zwei andere Interrupts vom gleichen Typ auftreten. Wenn beispielsweise 
deine 10ms Timerroutine zu lang ist und währenddessen 2 Interrupts vom 
Empfänger des UARTs kommen, weil der mit 115k2 Baud Daten empfängt.

>2. wirklich exaktes Timing kann bei mehreren Interrupts nie garantiert
>werden

Definiere "wirklich exakt".

Im worst case kann die Interruptausführung verzögert werden, mämlich um 
die maximale Laufzeit des Iterrupts der kurz vorher (ein Takt reicht) 
sich angemeldet hat. Da der Zeitpunkt der Interrupts zufällig ist, ist 
auch die Verzögerung im Bereich 0..maximale Laufzeit des anderen 
Interrupts zufällig (Jitter).

>Ich sollte als besser in der schnellen, wichtigen Interruptroutine oder
>im Hauptprogramm das langsamere Ereignis pollen, also nur einen
>Interrupt verwenden.

JAIN. Ist von der Anwendung abhängig.

>Hab ichs jetzt ??

Ich denke schon.

MfG
Falk

von Falk B. (falk)


Lesenswert?

Mist, wieder zu langsam. ;-)

MFG
Falk

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


Lesenswert?

snoopy wrote:

> 2. Treten 2 Interruptereignisse gleichzeitig auf, wird der
> ausgeführt, dessen Vector in der Liste vorn steht (der andere steht
> in der Warteschlange)

Wobei dieser Fall in aller Regel nur eintritt, wenn mehrere Interrupts
während einer Interruptsperre eintrafen (egal ob während einer ISR
oder während einer sonstigen CLI-Periode) und die Sperre aufgehoben
wird.

> Frage: wie viel darf sich denn in der Warteschlange so anstauen?
> Liegt die auf dem Stack?

Du hast einfach eine falsche Vorstellung davon.  Das ist keine
Schlange oder sowas.  Jede Interruptquelle hat ihr Interruptflag (in
einem IO-Register).  Zusammen mit den Freigabebits der einzelnen
Interruptquellen werden diese Flags über eine große ODER-Logik
vernknüpft.  Das bildet dann das Signal der globalen
Interruptanforderung.  Dieses wird nochmals mit dem I-Bit aus SREG
UND-verknüpft und entscheidet dann, ob der laufende Code unterbrochen
wird.

Sobald also eine freigegebene Interruptquelle einen Interrupt anmelden
würde, hängt es nur noch vom I-Bit ab, ob es zu einer Unterbrechung
kommt.  Wenn du gerade in einer ISR bist, ist das I-Bit normalerweise
gelöscht.  Das RETI setzt es dann wieder, und damit können alle noch
anhängigen Interrupts sich erneut um die CPU streiten.

Pro freigegebenen Interrupt kannst du also in einer beliebigen
Sperrzeit maximal ein Ereignis puffern.  Sind es mehrere, wird dir nur
ein Ereignis via Interrupt signalisiert.

> 2. wirklich exaktes Timing kann bei mehreren Interrupts nie
> garantiert werden

Wirklich exaktes Timing kann bei Interrupts nie garantiert werden. ;-)
Wirklich exaktes Timing macht man mit Hardware.

Einzige Ausnahme: du hast keinerlei Interruptsperrzeiten.  Aber das
ist unrealistisch.  Der Compiler selbst baut ja schon Code ein, um die
Interrupts mal kurz zu sperren, wenn er den Stackpointer (für den
Stackframe) manipuliert.  Du wirst sicher selbst auch noch weitere
Sperren brauchen.

> Ich sollte als besser in der schnellen, wichtigen Interruptroutine
> oder im Hauptprogramm das langsamere Ereignis pollen, also nur einen
> Interrupt verwenden.

Muss nicht sein.  Wenn du nur zwei Interruptquellen hast, kannst du
auch die unwichtige problemlos unterbrechbar machen.  Wenn es dir
tatsächlich auf die letzte Nanosekunde ankommt, dann geht das mit
einer Deklaration wie
1
void INT0_vect(void) __attribute__((interrupt));
2
void INT0_vect(void)
3
{
4
  /* hier die unterbrechbare ISR */
5
}

Das __attribute__((interrupt)) veranlasst den Compiler, ganz vorn in
der ISR bereits ein SEI einzubauen.  Damit ist die Interruptsperre auf
das absolute Minimum reduziert.

Wenn du andererseits in der unwichtigen ISR wirklich nur ein Flag
setzt, dann kannst du auf sowas wohl auch verzichten.  Das Flag pollst
du dann in main() ("volatile" nicht vergessen!).

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


Lesenswert?

Hmm, war ich ja viel zu langsam. ;-)

von snoopy (Gast)


Lesenswert?

Vielen Dank euch allen - jetzt habe ich erst mal einen Plan.

Ja, das habt ihr nun davon - jetzt werde ich euch bald mit verbugtem 
Code nerven ;-)

Viele Grüße,

Snoopy

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.