ich habe noch eine verständnisfrage zu den AVR interrupts. wenn man mehrere interrupts verwendet besteht ja die möglichkeit, daß sich diese zufällig überlagern. sprich interrupt B wird ausgelöst während die ISR von interrupt A noch nicht beendet wurde. der AVR sollte in so einem fall nun aus der ISR A in die ISR B springen, diese abarbeiten, danach wieder zur ISR A zurückkehren und dort fortsetzen wo sie unterbrochen wurde. machen die AVRs das von hause aus so oder muß ich dieses verhalten erst irgendwie "anfordern"?
Der neuere Interrupt wird erst dann abgearbeitet, wenn du Interrupts global wieder aktivierst. Die geschieht z.B. mit sei oder reti. Wenn du am Anfang der ISR A die Interrupts wieder frei gibst und der Interrupt B auftritt, wird zu ISR B gesprungen und am Ende von B wird A fertig abgearbeitet. Wenn aber immer wieder ein Interrupt kommt, bevor der letzte fertig wird, geht das nur solange, bis dein Stack überläuft vor Rücksprungadressen.
In einer ISR sind andere Ints per Global Interrupt Flag gesperrt. Evtl. weitere auftretende Int-Anforderungen werden in entsprechenden Flags "gemerkt" und dann ausgeführt, sobald die gegenwärtige ISR beendet ist. Sind mehrere Ints gleichzeitig "gemerkt", so gibt's eine Ausführungspriorität. In einer ISR können weitere Ints mit SEI erlaubt werden. Bei der expliziten Freigabe, und damit der Umgehung des AVR Int Systems, sollte man allerdings genau wissen was man da so macht.
Ja, Interrupts werden gemerkt, allerdings, wenn mehrere der gleichen Sorte auftreten, dann wird nur der erste dieser Sorte gemerkt. Beschrieben ist das im Datenblatt. "Normal/Üblicher" ist, dass Interrupt B erst bearbeitet wird, wenn Interrupt A fertig ist. Dein beschriebenes Verhalten nennt man /nested interrupts/ und das ist in der avr-libc beschrieben http://www.nongnu.org/avr-libc/user-manual/group__avr__interrupts.html
Prinzipiell ist kein "mehrstufiger Merker" für Interrupts im AVR vorgesehen. Aber Jede Hardware Einheit hat ein Interruptflag, was bei der jeweiligen Bedingung gesetzt wird. Und dann gilt einfach eine UND Verknüpfung (Maskierung) mit sei und dem jeweiligen Interrupt Enable. Heißt: Wenn ein Interrupt ausgelöst wird, wird das Flag gesetzt. Die Verarbeitung kann aber verzögert stattfinden (gelöschtes I-Bit. Kommt allerdings ein zweiter (gleicher) Interrupt, setzt er das Flag noch mal. Und das ist die Stelle an der der erste Interrupt "verloren" geht. Es sind zwar zwei aufgetreten, aber das kann ja nicht mehr unterschieden werden.
sprich wenn ich eine usart-RX ISR habe und während ich mir mein zeichen hole, es irgendwo in den speicher schmeiße und gleichzeitig wird ein timer compare interrupt ausgelöst bzw. "vorgemerkt" dann kann dieser auf keinen fall verlorengehen? ist jetzt nicht so superkritisch, die timer ISR kann ruhig die paar takte warten bis usart-RX abgeschlossen wurde. die macht nichts weiter als ein flag fürs hauptprogramm zu setzen. aber für spätere anwendungen wäre es mit einem SEI am anfang einer ISR auch möglich, interrupts geschachtelt auszuführen? natürlich nur solange genug platz auf dem stack ist und sich nichts rekursiv aufruft. dieser situation könnte man zur not ja auch mit einem hilfsflag zuleibe rücken.
>gleichzeitig wird ein timer compare interrupt ausgelöst bzw. "vorgemerkt" >dann kann dieser auf keinen fall verlorengehen? Ja. einer. Wenn mehrere aufgrund einer zu langen ISR auftreten, wird nur ein Interrupt registriert. >aber für spätere anwendungen wäre es mit einem SEI am anfang einer ISR >auch möglich, interrupts geschachtelt auszuführen? Ja, ich bin auch der Meinung, dass es von Atmel zu dem Thema eine Application Note gibt.
Jedesmal, wenn Interrupts global erlaubt sind, werden alle freigegebenen Interruptquellen von neuem geprüft und dann der niedrigste Interrupt ausgeführt. Damit das funktioniert, haben alle Interruptquellen ein Interruptflag, welches durch das Ereignis gesetzt wird (unabhängig von der Interruptfreigabe). Und solange dieses nicht gelöscht wurde, wird es nach Freigabe einen Interrupt auslösen. Manchmal will man aber nicht einen Interrupt auf längst vergangene Ereignisse auslösen, dann muß man das Interruptflag vor Interruptfreigabe löschen (also auf 1 setzen). Manchmal will man auch das Ereignis wissen, aber keinen Interrupt auslösen, dann kann man auf das Interruptflag pollen, muß es danach aber per Software löschen. Peter
danke euch für die antworten! bei mir ists schon so, daß ich die interrupts haben will weil ich mich dann weniger um den programmfluß zu kümmern brauche. die flags zu pollen finde ich nicht besonders schön. ich kenne es halt vom PC nur so, daß sich der x86 keine interrupts merkt. sprich der unterdrückte interrupt ist verloren. ist aber auch das komplexere system, es lassen sich z.b. auch interrupts per software aufrufen, welche dann vom BIOS oder TSR-programmen verarbeitet werden.
Ben _ schrieb: > die flags zu pollen > finde ich nicht besonders schön. Mußt Du ja nicht schön finden. Schön ist aber, daß man die Möglichkeit hat. Wird z.B. sehr gerne für die UART verwendet. > ich kenne es halt vom PC nur so, daß sich der x86 keine interrupts > merkt. sprich der unterdrückte interrupt ist verloren. Nö. Eine CPU, wo Interrupts verloren gehen, wäre nutzlos und würde keiner benutzen. Du hast ein OS und da wäre es blöd, wenn Interrupts ohne Handler ins Nichts laufen würden. Wenn Du einen Handler aufsetzt, kriegst Du auch alle Interrupts. Peter
gerade beim usart finde ich es toll, daß ich kein polling machen muß, sondern der µC sich "von alleine" darum kümmern kann. und wenn man es einmal verstanden hat ist es meiner meinung nach die deutlich einfachere lösung.
Ja, klar. Timer Interrupts machen bei Multiplexing zum Beispiel auch Sinn. Aber wenn man einfach nur einen definierten Takt in der Main haben will, braucht man nicht unbedingt einen Interrupt (der dann eh wieder nur ein Variablen-Flag setzen würde). Dann kann man besser direkt das Interrupt Flag des Timers pollen (Statt dem Variablen-Flag).
das ist eine frage des programmierstils und wie komplex das programm ist. wenn ich z.b. eine uhr habe würde ich die berechnung der stunden, minuten und sekunden in die ISR packen damit ich das im hauptprogramm aus dem sinn habe. dort kann ich die mich interessierenden werte dann direkt verarbeiten ohne sie erst berechnen zu müssen.
Ben _ schrieb: > das ist eine frage des programmierstils und wie komplex das programm > ist. Richtig. > wenn ich z.b. eine uhr habe würde ich die berechnung der stunden, > minuten und sekunden in die ISR packen damit ich das im hauptprogramm > aus dem sinn habe. dort kann ich die mich interessierenden werte dann > direkt verarbeiten ohne sie erst berechnen zu müssen. Das kann aber auch nach hinten losgehen, wenn das Programm sich noch um einige andere zeitkritische Dinge kümmern muss. Dann kann eine zu lange ISR schonmal den ganzen Programmablauf stören, weil ein anderer Interrupt (z.B. ICP oder Soft-ICP per ext.-Int.) nicht pünktlich zum Zuge kommt und Impulse verliert oder verfälscht. Wenn nur ein Interrupt (Timer) im Programm ist, dann kann man sogar das gesamte Programm in die ISR legen. Sind mehrere Interrupts involviert, dann müssen alle Interrupts eben so kurz wie möglich sein. Dann müssen aber auch die Mainloop-Jobs so geschrieben werden, dass sie nirgends auf irgendetwas warten müssen, sondern sofort zur Mainloop zurückkehren, wenn ein Arbeitsschritt momentan nicht ausführbar ist. Es (das Konzept eines Programms) ist also immer eine Frage der Situation. Was in einem Programm sinnvoll erscheint, kann in einem anderen Programm kontraproduktiv sein. Wenn Interrupts verloren gehen, dann stimmt das Konzept nicht. ...
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.