Forum: Mikrocontroller und Digitale Elektronik Diskussion Interrupts beim ARM7 LPC2138


von Martin (Gast)


Lesenswert?

Hallo Leute!

Ich habe das IRQ-System des ARM-Prozessors noch nicht ganz verstanden. 
Aus diesem Grund bitte ich euch, ob wir darüber einwenig diskutieren 
können.
Wenn meine Ausführung nicht der Richtigkeit entsprechen sollten, bitte 
ich darum mich zu korrigieren.

Soweit ich gehört habe, sind der IRQ-Controller und der Prozessor-Core 
zueinander nicht synchron. Aus diesem Grund kann es passieren, dass 
unerwünschte IRQs entstehen (Spurious). Diese muss man in einer leeren 
IRQ-Routine abfangen, wobei man das Register VICVectAddr beim Verlassen 
beschreiben muss. Z.B:
void spurious_handler() __irq
{

VICVectAddr=0x00;
}

Soweit ich das verstanden habe tritt ein Spurious-IRQ dann auf, wenn ein 
IRQ zu kurz (z.B. Level IRQ an einem Eingang) anliegt. Der 
IRQ-Controller meldet an den Core, dass ein IRQ anliegt. Der Core 
versucht nun die Adresse des Vektors zu laden. Ist der IRQ zu diesem 
Zeitpunkt bereits wieder verschwunden, dann kann auch keine Adresse 
geladen werden und der Prozessor springt die Spurious-Routine an.


Dann gibt es anscheinend noch ein Problem, wenn man die IRQs sperren 
möchte. Um die IRQs zu sperren kann man sich mit folgendem Befehl 
helfen:
 VICIntEnClr = 0xFFFFFFFF;                // disable all interrupts

Danach kann man sie wieder einschalten. Doch bei einem Ausschalten kann 
es passieren, dass ebenfalls Spurious-IRQs auftreten.
Warum ist das so?
Was passiert eigentlich, wenn mit dem obigen Befehl alle IRQs 
ausgeschaltet wurden und ein IRQ auftritt? Wird die Vektoradresse erst 
wieder geladen wenn die IRQs wieder eingeschaltet sind?

Wenn sich der Prozessor in einer IRQ-Routine befindet und ein weiterer 
IRQ auftritt, wann wird dann die Vektoradresse des nächsten IRQs 
geladen, nach dem Austritt aus der aktuellen Routine?


Es würde mich freuen, wenn wir darüber einwenig diskutieren können.
Ich habe noch ein paar Fragen, aber die möchte ich erst im Laufe der 
Diskussion einfließen lassen.

Danke, einen schönen Abend wünsche ich noch.

Tschüss
Martin

von Andreas K. (a-k)


Lesenswert?

Martin wrote:

> Soweit ich das verstanden habe tritt ein Spurious-IRQ dann auf, wenn ein
> IRQ zu kurz (z.B. Level IRQ an einem Eingang) anliegt.

Korrekt.

> Dann gibt es anscheinend noch ein Problem, wenn man die IRQs sperren
> Danach kann man sie wieder einschalten. Doch bei einem Ausschalten kann
> es passieren, dass ebenfalls Spurious-IRQs auftreten.
> Warum ist das so?

Aus exakt dem gleichen Grund wie oben. Der VIC meldet dem Core den 
Interrupt. Einige Takte später führt das zum Lesen des Vektors. Wenn 
exakt dazwischen das
  VICIntEnClr = 0xFFFFFFFF;
liegt, dann reagiert der VIC zwangsläufig etwas ratlos auf die Frage 
nach dem Vektor.

> Wird die Vektoradresse erst
> wieder geladen wenn die IRQs wieder eingeschaltet sind?

Der Vektor wird erst final bestimmt, wenn der Prozessor ihn explizit 
läd. Das passiert ja nicht automatisch, sondern ist Teil des 
Interrupt-Codes, oft in Form eines Befehls direkt an der Stelle des 
Vektors.

> Wenn sich der Prozessor in einer IRQ-Routine befindet und ein weiterer
> IRQ auftritt, wann wird dann die Vektoradresse des nächsten IRQs
> geladen, nach dem Austritt aus der aktuellen Routine?

Wenn während der Abarbeitung des ersten Interrupts der IRQ abgeschaltet 
war, dann geht der Weg erst wieder zurück ins unterbrochene Programm, 
bevor der nächste Interrupt ausgelöst wird.

Gibt die Interrupt-Routine die Interrupts vorher frei, kann sie ab 
diesem Zeitpunkt durch höher priorisierte Interrupts unterbrochen 
werden.

von Martin (Gast)


Lesenswert?

Hallo Andreas!

Danke für deine ausführliche Antworten.

>Wenn während der Abarbeitung des ersten Interrupts der IRQ abgeschaltet
>war, dann geht der Weg erst wieder zurück ins unterbrochene Programm,
>bevor der nächste Interrupt ausgelöst wird.
Nehmen wir mal an die IRQ-Routine wird abgearbeitet und sie benötigt 
relativ lange. Wenn jetzt in dieser Zeit ein weiterer IRQ ausgelöst wird 
und dieser wieder verschwindet, bevor der Prozessor die Möglichkeit hat 
in das Hauptprogramm zurückzukehren, wird dann zwangsläufig ein 
Spurious-IRQ ausgelöst?


Tschüss
Martin

von Andreas K. (a-k)


Lesenswert?

Martin wrote:

> wird dann zwangsläufig ein Spurious-IRQ ausgelöst?

Nein. Würde sich der VIC alle IRQ Anforderungen merken, gäbe es den 
spurious interrupt nicht. Denn dann wäre klar, woher der Auslöser kam.

Tatsächlich speichert der VIC die Anfragen nicht, sondern bildet rein 
kombinatorisch aus allen freigegebenen IRQ-Inputs eine Gesamtsumme, die 
als IRQ an den Prozessor weitergereicht wird. Der wiederum speichert 
ebensowenig, sondern prüft bei jedem Befehl, ob er normal weiter machen 
soll oder unterbrechen. Aber das tut er nur wenn er darf, also wird die 
IRQ Anfrage erstmal ignoriert. Und wenn sie verschwindet bevor die IRQs 
wieder eingeschaltet werden, dann passiert garnichts.

Das ganze lässt sich ungefähr am Unterschied zwischen "level triggered" 
und "edge triggered" erklären. Flankengetriggerte Interrupts speichern 
die Anfrage, war die Flanke mal da, dann bleibt der Request gespeichert 
bis er bearbeitet und gelöscht wurde. Pegelgetriggerte Interrupts 
speichern nicht, sondern müssen solange anliegen bis sich jemand drum 
kümmert, sonst gehen sie verloren. LPC21xx Interrupts sind seitens des 
Prozessors und seitens des Interrupt Controllers pegelgetriggert.

von Martin (Gast)


Lesenswert?

Hallo Andreas!

OK, ich glaube ich verstehe soweit. Ich versuche das Ganze nochmal 
zusammenzufassen:
Wenn der Prozessor gerade das Hauptprogramm abarbeitet und plötzlich ein 
IRQ ansteht und bevor der Vektor geladen werden kann, der IRQ wieder 
verschwindet oder mit VICIntEnClr = 0xFFFFFFFF; der IRQ abgeschaltet 
wird, dann wird ein Spurious-IRQ ausgelöst, weil der Vektor unbekannt 
ist.

Befindet sich der Prozessor in einer IRQ-Routine und steht dort 
plötzlich ein weiterer IRQ an, dann wird dieser so lange ignoriert bis 
nach der IRQ-Routine der Prozessor wieder im Hauptprogramm ist und die 
Sperr-Bits im PSR-Register wieder frei sind. Jetzt erst erkennt der 
Prozessor den nächsten IRQ und lädt darauf den Vektor. Wäre dieser 
zweitanstehende IRQ wieder verschwunden, bevor der Prozessor aus der 
ersten IRQ-Routine gesprungen ist, dann hätte dieser von dem zweiten IRQ 
nichts mitgekriegt.

Wenn ich jetzt den Prozessor z.B. im Privileg-Mode laufen lasse und ich 
die IRQ-disable-Flags im PSR-Register selbst ein und abschalte, um IRQs 
im Hauptprogramm zu sperren, können im Prinzip keine Spurious-IRQs 
entstehen, weil der Prozessor durch das Ausschalten der 
IRQ-Disable-Flags nicht mitkriegt, dass IRQs überhaupt anliegen. Sehe 
ich das richtig?

Auf jeden Fall danke ich dir schon jetzt für deine Antwort und für deine 
bisherigen Antworten. Damit hast du mir weitergeholfen.

Tschüss
Schönes Wochenende

Martin

von Andreas K. (a-k)


Lesenswert?

Spurious Interrupts sind kaum zur Gänze vermeidbar, weil die Ursache 
auch anders als durch Interrupt-Enables verschwinden kann. NXP gibt in 
der sonst nicht so ganz gelungenen AN10414 als Beispiel die UART an, 
deren Timeout-Interrupt durch grad rechtzeitig eintrudelndes Byte wieder 
verschwinden kann. Mit dem dort auch genannten Lösungsansatz bin ich 
allerdings über Kreuz. Aber dazu hat es im Internet (Yahoo Group zu 
LPC2000) schon reichlich Zündstoff gegeben.

Ist aber m.E. nicht wirklich ein Problem. Man sollte halt den 
Default-Vector mit Leben füllen, wie von dir oben gezeigt, und damit hat 
es sich. Neugierige Leute inkrementieren dort einen Zähler und gucken ab 
und zu nach.

von Christian J. (Gast)


Lesenswert?

Hallo,

ich möchte hier nochmal anknüpfen, weil mir die VIC Struktur immer noch 
etwas rätselhaft ist.

Der Chip hat diverse Peripherieeinheiten von denen fast alle IRQ fähig 
sind.  Beim PIC gibt es nur einen IRQ Vektor, wo dann nacheinander 
abgefragt wird, wer es denn nun war. Aber nun der ARM7:

1. Muss man für jede Peripherie EINE Routine anlegen und kann dann in 
der Routine auslesen, welcher IRQ nun wirklich kam? Also eine für UART, 
eine für die Timer, die wieder Capture & Compare/Match Fähigkeit haben 
usw.

2. Wie kann man IRQs schachteln? Also, dass sie einander unterbrechen 
dürfen?

3. Was macht VICVectAddr=0x00 denn genau?

4. Was sind die "Slots"?

Bei mir sind, egal ob PIC oder ARM7 Programme meist so aufgebaut, dass 
ich einen Timer-IRQ habe, der zB alle 0,1s kommt und wo allerlei Sachen 
gemacht werden, wie zB Software-Zähler-Uhren, AD Werte auslesen in 
Register, Tasten abfragen etc. Dieser IRQ muss natürlich unterbrochen 
werden könnenn, wenn zB über mein Funkmodul etwas reinkommt, bevor 
dessen Fifo überläuft.

Gruss,
Christian

von Andreas K. (a-k)


Lesenswert?

Christian J. wrote:

> 1. Muss man für jede Peripherie EINE Routine anlegen und kann dann in
> der Routine auslesen, welcher IRQ nun wirklich kam? Also eine für UART,
> eine für die Timer, die wieder Capture & Compare/Match Fähigkeit haben
> usw.

Wenn die betreffende Peripherie mit Interrupts arbeitet ja. Das wird 
übrigens von den meisten Leuten als Vorteil empfunden. Denn in den 
Routinen sollte man zwar nochmal kontrollieren, ob der Interrupt 
wirklich ausgelöst wurde, aber man muss nicht alle zig IRQs 
durchprobieren, weil ja klar ist um welchen es geht.

Wobei je nach Controller manche Periphierie auch mehrere IRQs belegen 
kann (insgesamt 9 Stück beim CAN-Modul vom LPC2194).

Wenn dich das so sehr stört, kannst du aber nach wie vor einen einzigen 
Interrupt-Handler benutzen und dort in schönster(?) PIC-Tradition alles 
durchprobieren. Denn die Vektorierung mach der ARM nicht selber, sie 
entsteht erst durch den Code an Adresse 0x18. Oft ist das ein indirekter 
Sprungbefehl der den Vektor aus dem Interrupt-Controller in den PC läd.

> 2. Wie kann man IRQs schachteln? Also, dass sie einander unterbrechen
> dürfen?

Siehe NXP Application Note AN10381. Ist abhängig vom verwendeten 
Interrupt-Controller.

> 3. Was macht VICVectAddr=0x00 denn genau?

Zu dem Zeitpunkt, zu der Vektor ausgelesen wird, wird die 
Interrupt-Logik so eingestellt, dass alle niederiger priorisierten 
Interrupts vorübergehend gesperrt sind. Das ist Voraussetzung für 
Nesting. Dieser Befehl entsperrt sie wieder.

> 4. Was sind die "Slots"?

Keine Ahnung was du meinst.

von Stefan K. (Gast)


Lesenswert?

Hallo Zusammen!

ich bin gerade auf Eure Diskussion gestoßen, da der VIC mich im Moment 
in Verbindung NXP-Prozessoren auch beschäftigt.
Auch ich möchte mit 'Nesting' von Interrupts demnächst arbeiten. Dabei 
habe ich eine Frage, die zu Eurer Diskussion passt:

Systembeschreibung:
ARM7-System von NXP mit VIC arbeitet mit 3 IRQ's unterschiedlicher 
Priorität.
Die 3 IRQ's sind unterbrechbar.

Zeitliche Abfolge der Interrupts:

1. Interrupt: Der mittelpriore Interrupt tritt auf:
Reaktion: Der mittelpriore Interrupt wird bearbeitet

2. Interrupt: Der höchtpriore Interrupt tritt auf, während mittelpriorer 
Interrupt bearbeitet wird:
Reaktion: Mitterpriorer Interrupt wird unterbrochen und der höchstpriore 
Interrupt wird bearbeitet.

3. Interrupt: Der niederpriorste Interrupt steht an, während der 
höchstpriore Bearbeitet wird:
Reaktion: Die höchstpriore ISR wird nicht unterbrochen und wird zu Ende 
geführt. Nach dem Verlassen der höchsprioren ISR wird dem VIC durch 
Beschreiben von VicVectAddr das Ende der ISR mitgeteilt.

Jetzt meine Frage:
Wird jetzt mit der mittelprioren ISR weitergemacht oder kommt der 
niederpriore Interrupt durch bzw. hat sich der VIC gemerkt, dass der 
mittelpriore Interrupt noch nicht zu Ende bearbeitet wurde?

Gruß,
Stefan

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.