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 | 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!).
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.