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
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?
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
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
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.
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
> 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.
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
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
@ 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
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.
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
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
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.
@ 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
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
voidINT0_vect(void)__attribute__((interrupt));
2
voidINT0_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!).
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