Forum: Mikrocontroller und Digitale Elektronik Atmel ISR mehrere Ansprünge


von Noppi (Gast)


Lesenswert?

Hallo, kurze Frage.

Ich habe 3 ISR Routinen.

Beispiel. Eine wird getriggert, springt dort rein. Von dort aus mache 
ich eine Funktion (kein Inline). Springt er dann in die Funktion. Könnte 
er, wenn in der Zeit ein anderer ISR getriggert wird, dort reinspringen, 
oder ist das in der Zeit blockiert, solange ein ISR nicht verlassen 
wurde (Flag nicht gelöscht).

Geht um AVRs Mega, Tiny

von Flo (Gast)


Lesenswert?

Ist blockiert.

von Verständnis Voller (Gast)


Lesenswert?

Noppi schrieb:
> Ich habe 3 ISR Routinen.

Also drei Interrupt Service Routinen Routinen, sozusagen.

von Lotta  . (mercedes)


Lesenswert?

Der Interrupt ist solang blockiert, bis Du die Interruptroutine
wieder verläßt oder den Interrupt wieder einschaltest.

Achtung! die ISR sollte möglichst schnell abgearbeitet
werden, beim UART z.b schreibst Du das ankommende Byte in
nen globalen Ringpuffer und verläßt die Routine wieder.
die weitere Bearbeitung sollte dann in der Hauptschleife erfolgen.


mfg

von my2ct (Gast)


Lesenswert?

Noppi schrieb:
> Könnte er, wenn in der Zeit ein anderer ISR getriggert wird, dort
> reinspringen, oder ist das in der Zeit blockiert, solange ein ISR nicht
> verlassen wurde (Flag nicht gelöscht).

Ob die ISR verlassen wurde, spielt keine Rolle. Entscheidend ist, dass 
der Interrupt freigegeben ist. Beim Einsprung in eine ISR werden erstmal 
weitere gesperrt und spätestens beim RTI wieder erlaubt. Freigabe 
innerhalb der ISR ist aber genauso möglich.

von Lotta  . (mercedes)


Lesenswert?

Genau!!

Mach die Interruptroutine erstmal als Normalroutine.
Steppe sie dann bitte im Debugger sorgfälig  durch,
auch die von ihr aufgerufene Funktion, bevor Du sie
als ISR definierst!

Ein Bug in ner ISR ist ekelig!

mfg

von Adam P. (adamap)


Lesenswert?

Noppi schrieb:
> Könnte
> er, wenn in der Zeit ein anderer ISR getriggert wird, dort reinspringen,
> oder ist das in der Zeit blockiert, solange ein ISR nicht verlassen
> wurde

Im Normalfall sind andere Interrupts gesperrt.
Jedoch gibt es die Möglichkeit, auch auf einem AVR "Nested Interrutps" 
zu nutzen.

: Bearbeitet durch User
von Peter D. (peda)


Lesenswert?

my2ct schrieb:
> Freigabe
> innerhalb der ISR ist aber genauso möglich.

Das Problem ist aber, daß im Gegensatz zu CPUs mit echten 
Interruptleveln auch der ursprüngliche Interrupt wieder erlaubt wird und 
er sich selber unterbrechen kann, bis zum Stacküberlauf.
Daher macht man das beim AVR für professionelle Anwendungen nicht. Es 
ist einfach zu gefährlich (den Drachen kitzeln).

von Interrupt (Gast)


Lesenswert?

Wenn die basagte Routine aber schon abgearbeitet wird, wird der 
Interrupt dazu führen, dass sie sich selbst unterbricht. Such mal nach 
Reentrant. Diese Eigenschaft muss sie dann haben, sonst gibt es die 
tollsten Nebeneffekte.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Peter D. schrieb:
> Daher macht man das beim AVR für professionelle Anwendungen nicht.
> Es ist einfach zu gefährlich (den Drachen kitzeln).
Ich würde es so sagen: es gibt nur 2 Arten von Menschen, die das tun.

1. blutige Anfänger, die es nicht besser wissen und meinen, so ihr 
"Problem" lösen zu können.

und

2. erfahrene Profis, die möglicherweise leider gezwungen sind, das zu 
tun und die potentiellen Gefahren ganz genau kennen.

Alle anderen kommen mit 1 aktiven Interrupt zurecht.

Interrupt schrieb:
> Wenn die basagte Routine aber schon abgearbeitet wird, wird der
> Interrupt dazu führen, dass sie sich selbst unterbricht.
Das Nesting von Interrupts wird eigentlich nur über SEI wieder 
freigegeben:
https://ucexperiment.wordpress.com/2013/05/20/nested-interrupts/

Und deshalb kann ein Interrupt sich nicht selber unterbrechen, weil es 
dafür ja nur 1 Quelle gibt und dieses Flag schon aktiv ist. Extrem wäre 
es natürlich, zusätzlich zum Aktivieren des globalen Enables auch gleich 
das auslösende Interruptflag zurückzusetzen. Aber dann kann man sich 
auch gleich ins Knie schießen, das tut sicher auch weh!

von Ingo E. (ogni42)


Lesenswert?

> Und deshalb kann ein Interrupt sich nicht selber unterbrechen, weil es
> dafür ja nur 1 Quelle gibt und dieses Flag schon aktiv ist. Extrem wäre
> es natürlich, zusätzlich zum Aktivieren des globalen Enables auch gleich
> das auslösende Interruptflag zurückzusetzen. Aber dann kann man sich
> auch gleich ins Knie schießen, das tut sicher auch weh!


Also lt. DaBla des 328p passiert das Löschen des Flags automatisch beim 
Eintritt in die ISR (bzw. beim Aufruf des Vektors):
"Bit 1 – INTF1: External Interrupt Flag 1
When an edge or logic change on the INT1 pin triggers an interrupt 
request, INTF1 will be set. If the I-bit
in SREG and the INT1 bit in EIMSK are set, the MCU will jump to the 
corresponding Interrupt Vector. The
flag is cleared when the interrupt routine is executed. Alternatively, 
the flag can be cleared by writing '1' to
it. This flag is always cleared when INT1 is configured as a level 
interrupt."

Wenn also die ISR(..., NO_BLOCK) deklariert wurde, kann der Interrupt in 
der ISR erneut ausgelöst werden und die ISR wird auch erneut aufgerufen, 
oder?

von Oliver S. (oliverso)


Lesenswert?

Da haben sich viele Autoren so viel Mühe mit dem Wiki hier im Forum 
gegeben, und niemand liest es.

https://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Allgemeines_.C3.BCber_die_Interrupt-Abarbeitung

Ingo E. schrieb:
> lso lt. DaBla des 328p passiert das Löschen des Flags automatisch beim
> Eintritt in die ISR (bzw. beim Aufruf des Vektors):

Das ist bei den meisten Interruptquellen so, aber nicht bei allen.

Oliver

von Peter D. (peda)


Lesenswert?

Ingo E. schrieb:
> Also lt. DaBla des 328p passiert das Löschen des Flags automatisch beim
> Eintritt in die ISR (bzw. beim Aufruf des Vektors):
> "Bit 1 – INTF1: External Interrupt Flag 1

Hier war aber kein bestimmter Interrupt angegeben.
Z.B. Schnittstellen (UART, SPI, I2C, CAN) löschen das Flag nicht.

Ingo E. schrieb:
> Wenn also die ISR(..., NO_BLOCK) deklariert wurde

Dann schmiert bei Schnittstellen der AVR gnadenlos ab.

von EAF (Gast)


Lesenswert?

Nicht jammern.... oder immer das Schlimmste annehmen.

Die Lösung hat sogar irgendwann mal ihren Namen erhalten.
Reentrance, oder Wiedereintrittsfähig.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Ingo E. schrieb:
> Wenn also die ISR(..., NO_BLOCK) deklariert wurde, kann der Interrupt in
> der ISR erneut ausgelöst werden und die ISR wird auch erneut aufgerufen,
> oder?
Ja, wie gesagt: in bestimmten Fällen. Beim Timer geht das, weil ja der 
Aufruf der ISR an sich schon das gewünschte Ergebnis ist. Bei der 
seriellen Schnitte wird das Flag aber sinnvollerweise erst beim Lesen 
des UDR gelöscht. Man muss sich also das Datenblatt genau anschauen. Und 
auch die Ressourcennutzung in den möglicherweise betroffenen ISR.

EAF schrieb:
> Die Lösung hat sogar irgendwann mal ihren Namen erhalten.
> Reentrance, oder Wiedereintrittsfähig.
Ja, war auch schon im Gespräch.
Ich bin mir aber ziemlich sicher, dass ein Anfänger so eine Funktion, 
die vollständig reentrant ist, nicht hinbekommt. Besonders, weil ja 
solche ISR gerne mit Hardware zu tun haben, die nur 1x vorhanden ist. 
Und wenn was nur einmal da ist und ein anderer nimmt es zwischendurch in 
die Finger, dann gibt das beliebig zufälige Effekte:
nehmen wir nur mal an, die erste ISR liest einen 16-Bit-Zähler aus, also 
Low- und High-Byte (im Schattenregister) nacheinander. Aber dann kommt 
nach dem Auslesen des Low-Bytes die zweite ISR und liest diesen Timer 
via Low- und High-Byte ein paar µs später auch aus, überschreibt dabei 
den Wert im Schattenregister(!!) und danach geht es zurück zur ersten 
ISR, die dann das anstelle "ihres" High-Bytes das der zweiten ISR 
nochmal ausliest ... rumpeldipumpel, wenn zwischendurch ein Überlauf 
im High-Byte stattgefunden hat...


Drehen wir den Spieß aber einfach mal um: ich halte einfach die 
Interruptroutinen so kurz, dass es sich gar nicht lohnt, sie extra noch 
zu unterbrechen.

: Bearbeitet durch Moderator
von Ben B. (Firma: Funkenflug Industries) (stromkraft)


Lesenswert?

Der AVR sollte das bei korrekt geschriebenen ISRs können, auch wenn man 
das möglicherweise beim Start jeder ISR explizit erlauben muß, 
jedenfalls so lange bis der Stack voll ist (danach zerschießt man sich 
den RAM-Inhalt).

Es geht aber nicht bei jedem Interrupt, sondern nur bei solchen, die 
nicht dauerhaft aktiv sein können. Sonst erzeugt man eine sehr schnell 
laufende Endlosschleife und der RAM-Inhalt wird quasi sofort 
geschreddert.

Es geht auch nicht besonders gut, wenn man in den ISR Daten verarbeitet, 
also beispielsweise ein vom UART empfangenes Zeichen ins RAM schreibt. 
Solche Routinen sollten ohne Unterbrechung durchlaufen. Ansonsten würde 
ein zweiter Aufruf zu Problemen führen wenn die erste Instanz lange 
genug unterbrochen wurde.

von Jobst M. (jobstens-de)


Lesenswert?

Lothar M. schrieb:
> Und deshalb kann ein Interrupt sich nicht selber unterbrechen, weil es
> dafür ja nur 1 Quelle gibt und dieses Flag schon aktiv ist.

Doch, das geht. Ich möchte ein Beispiel zeigen.

Ein Pulsgenerator erzeugt mittels Timer-IRQ (192k/s) einen Impuls bei 
Überlauf eines Akkumulators (DDS-Prinzip). Dass hier kein Aufruf 
ausgelassen werden darf leuchtet ein. Abhängig davon, ob ein Puls 
erzeugt wurde, wird eine neue Berechnung des Frequenzwortes fällig. Es 
werden zwei Differenzen gebildet, eine Entscheidung getroffen, eine 
Multiplikation durchgeführt, eine Wurzel gezogen und eine Begrenzung (16 
Bit) durchgeführt. Abgesehen von der Begrenzung jeweils in 32 Bit. Die 
Berechnung dauert ca. 350 Takte (Wenn ich mich nicht irre - ich müsste 
nochmal nachzählen) und kann nicht losgelöst vom IRQ in der Main 
passieren, da hier noch weitere Dinge passieren, die eine Berechnung nur 
noch weiter hinauszögern. Außerdem dürfen IRQs nicht verboten werden, 
was die Übergabe neuer Werte erschweren würde. Der Timer-IRQ wird alle 
96 Takte ausgelöst, die Pulsausgabe benötigt ca. 30 Takte, sofern ein 
Puls ausgegeben wird. Sonst ist sie nur halb so lang.
Nach dieser Ausgabe wird die Routine wieder unterbrechbar. Eine 
Verriegelung sorgt nun dafür, dass immer nur eine Berechnung in Arbeit 
ist. Erst wenn die Berechnung abgeschlossen wurde, darf ein weiterer IRQ 
eine neue Berechnung starten.

Dieser Mechanismus darf auch durch andere IRQs nicht gestört werden, 
alles weitere läuft deshalb in der main per polling. Viel ist da aber 
auch nicht mehr.
Gesteuert wird der ganze Apparat über die UART, auf welcher ein 
Kommandointerpreter Befehle entgegen nimmt. Bei voller Geschindigkeit 
mit 192000 Pulsen/s merkt man bei einem bestimmten Kommando schon die 
geringere verbleibende Rechenleistung. Dabei bleiben alle 3 bis 4 IRQs 
nur eine Hand voll Takte für die Main übrig.

Das Überspringen der Berechnungen für einige Impulse ist bei hohen 
Pulsraten akzeptabel.



Ich möchte noch ein weiteres Beispiel zur Unterbrechung von ISRs durch 
andere IRQs aus meinem Fundus zeigen:

Ein Timer, welcher einen Hardware-Impuls ausgibt. Mit diesem Impuls 
werden Daten des SPI Jitterfrei an die parallelen Ausgänge eines 
Schieberegisters übernommen. Außerdem wird durch die Hardware eine 
AD-Wandlung angestoßen. Weiterhin erzeugt dieses Timerereignis einen 
IRQ, welcher dafür sorgt, dass neue Daten per SPI in das Schieberegister 
gelegt werden. Dieser IRQ unterbricht nun die ISR des ADC, welche die 
Daten aus der Wandlung des vorherigen Ereignisses verarbeitet. Die in 
der Timer-ISR erzeugten Daten werden in der ADC-ISR benötigt, weshalb 
absolute Synchronität notwendig ist. Also wieder kein Fall für die Main. 
Allerdings ist hier noch genug restliche Zeit für diese übrig, auch wenn 
auch hier schon wieder mit ~75k/s gearbeitet wird.


Gruß
Jobst

von m.n. (Gast)


Lesenswert?

Noppi schrieb:
> Von dort aus mache
> ich eine Funktion (kein Inline).

Erst noch machen? Die Funktion ist sicherlich schon vorhanden und soll 
aufgerufen werden.
Kann man machen und man kann die Interrupts auch verschachtelt ausführen 
lassen, allen Unkenrufen hier zum Trotz.

Das Hauptargument gegen einen Funktionsaufruf aus einer ISR bei einem 
AVR8 ist für mich die zusätzliche Latenz, die durch das Sichern und 
Restaurieren (push/pop) aller CPU-Register auftritt. Da beim Eintritt in 
die ISR nicht überprüft wird, welche Register die aufgerufene Funktion 
verwendet, müssen eben alle Register gesichert werden. Das kostet 
richtig Zeit.

von Carsten-Peter C. (carsten-p)


Lesenswert?

Hallo, ich möchte kurz einen Teil aus einer PDF zeigen, deren URL nicht 
mehr verfügbar ist.

Tritt ein Interrupt auf, dann wird das I-Bit im Statusregister gelöscht 
und alle anderen Interrupts gesperrt. Dieses I-Bit wird wieder gesetzt, 
sobald der aufgetretene Interrupt abgearbeitet wurde und der Befehl RETI 
zur Rückkehr an die Stelle im Programm zum Zeitpunkt des Aufrufes 
ausgeführt wurde. Wird ein Interrupt-Flags gesetzt, dann bleibt es bis 
zur Abarbeitung oder Löschung durch das Programm erhalten. Treten 
mehrere Interrupts auf, werden sie nacheinander abgearbeitet. Da einem 
externen Interrupt kein
Flag zugeordnet ist, bleibt dieser nur solange in Evidenz, solange jene 
Bedingung besteht, die zu seinem Auftreten geführt hat.

Tritt ein INT auf, der auch freigegeben ist z.B durch u.a Register 
GIMSK, werden wie beim Befehl CLI (Global Interrupt Disable) alle 
weiteren INT gesperrt und durch RETI wieder freigegeben (wie RET + SEI 
gleichzeitig). Genaueres im Datenblatt.
Gruß Carsten

von Falk B. (falk)


Lesenswert?

Carsten-Peter C. schrieb:
> Hallo, ich möchte kurz einen Teil aus einer PDF zeigen, deren URL nicht
> mehr verfügbar ist.

Sehe ich nicht.

> mehrere Interrupts auf, werden sie nacheinander abgearbeitet. Da einem
> externen Interrupt kein
> Flag zugeordnet ist, bleibt dieser nur solange in Evidenz, solange jene
> Bedingung besteht, die zu seinem Auftreten geführt hat.

Stimmt nicht. Das gilt bestenfallst für einen low level Interrupt. Die 
flankensensitiven, externen Interrupts setzen ein Bit.

von Peter D. (peda)


Lesenswert?

Jobst M. schrieb:
> Ich möchte ein Beispiel zeigen.

Du sagst nur, welche Schritte diese beiden Beispiele ausführen. Mich 
würde aber mehr interessieren, wozu man sowas praktisch einsetzen kann. 
Mir fällt da erstmal nichts ein, was solche Berechnungen im Interrupt 
benötigt.
Was sind das für konkrete Anwendungen oder ist das geheim?

Ich fand das damals (1997) schon einen herben Rückschritt vom 8051 mit 4 
Interruptleveln zum AVR ohne Interruptlevel.

von Stefan F. (Gast)


Lesenswert?

Peter D. schrieb:
> Ich fand das damals (1997) schon einen herben Rückschritt vom 8051 mit 4
> Interruptleveln zum AVR ohne Interruptlevel.

Als ich zum ersten mal den Umgang mit AVR lernte war ich sehr irritiert, 
dass es dort keine Interrupt-levels gibt. Bis dahin dachte ich, das sei 
allgemeiner Standard.

Andererseits hat mich das bei der praktischen Anwendung noch nie 
ernsthaft behindert. Für großartige Hochleistungs-Programme würde ich 
ohnehin andere Mikrocontroller verwenden.

von Oliver S. (oliverso)


Lesenswert?

Lothar M. schrieb:
> Und deshalb kann ein Interrupt sich nicht selber unterbrechen, weil es
> dafür ja nur 1 Quelle gibt und dieses Flag schon aktiv ist. Extrem wäre
> es natürlich, zusätzlich zum Aktivieren des globalen Enables auch gleich
> das auslösende Interruptflag zurückzusetzen.

Es gibt kein "schon aktives Flag", was man "zurücksetzten" kann oder 
muß. Das Flag ist entweder gesetzt, oder nicht. Die CPU kennt auch gar 
keinen Status "in Interrupt" o.ä. Ist ein ISR-FLAG gesetzt, und ist der 
Interrupt freigegeben, wird der ISR-Vector bei nächter Gelegenheit (= 
Ende der Ausführung des aktuell laufenden Befehls) angesprungen. Ob das 
Flag neu gesetzt wurde, oder schon gesetzt war, oder vergessen wurde, es 
zu löschen, spielt keine Rolle.

Oliver

: Bearbeitet durch User
von Walter T. (nicolas)


Lesenswert?

Jobst M. schrieb:
> Ein Pulsgenerator erzeugt mittels Timer-IRQ (192k/s) einen Impuls bei
> Überlauf eines Akkumulators (DDS-Prinzip).

Jobst M. schrieb:
> Es
> werden zwei Differenzen gebildet, eine Entscheidung getroffen, eine
> Multiplikation durchgeführt, eine Wurzel gezogen und eine Begrenzung (16
> Bit) durchgeführt.

Das sieht nach einer G-Code-gesteuerten CNC-Steuerung aus. Dabei gibt es 
nur eine ISR, die alle anderen unterbrechen darf (um den Jitter klein zu 
halten). Kein Anfängerprojekt, aber auch kein Grund für merkwürdige 
Klimmzüge.

: Bearbeitet durch User
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.