Forum: Mikrocontroller und Digitale Elektronik ARM7 mit VIC und Spurious Interrupts


von Dietmar (Gast)


Lesenswert?

Hallo ARM7-Gemeinde um Philips LPC2000, Atmel, etc....,

Gibt es hier jemanden, der sich mit dem Thema "Spurious Interrupts"
(Scheininterrupts) etwas auskennt? Das betrifft wohl hauptsächlich µC,
in denen ein ARM7-Core mit dem VIC (Vectored Interrupt Controller PL190
von ARM) zusammen arbeitet.

Im Philips Datenblatt gibt es dazu immerhin ganze 2 Seiten Erklärung,
die mit denen auf der ARM Homepage übereinstimmen.

Arbeite mit Keil Tools und bin gerade dabei, einen Spurious Interrupt
Handler in Assembler zu schreiben und direkt in der Startup.s zu
platzieren. Das kostet aber Interrupt-Latenzzeit. Keil schlägt vor,
eine Default Interruptroutine zu installieren, zum Abfangen nicht
identifizierbarer Interrupts. Kostet ebenfalls Ausführungszeit. Ist das
jetzt mit Kanonen auf Spatzen geschossen?

Neuerlich, gibt es dazu auch einige Threads in Diskussionsforen, z.B.
im LPC2000-Forum bei Yahoo, und auch hier im Forum, die das Thema immer
wieder aufgreifen.

Laut Philips User Manual betrifft das hauptsächlich Fälle, in denen bei
kernnaher Programmierung die Interrupt-Flags verändert werden.

Und wenn ich das nicht tue, sondern Interrupts nur über VIC Register
sperre und freigebe? Bin ich dann auch betroffen?

Nun, ich erwarte von meiner sehr interruptlastigen Anwendung, daß sie
vernünftig läuft. Messe Zeiten mit Timer Capture und einigen 10000
Interrupts pro Sekunde, das soll absolut zuverlässig sein.

Nun, ich habe da verschiedene Ansätze. Möchte in meiner Anwendung auch
die Technik der "Nested Interrupts" (unterbrechbarer Interrupt per
Software, ist standardmäßig bei ARM nicht vorgesehen) anwenden. Und da
muß man die Interruptflags direkt im Kern ändern.

Als nächsten Schritt, möchte ich die Spurious Interrupts auch zählen,
in einer festen RAM-Location.

Hat da mal jemand etwas Erleuchtung?

Gruß

Dietmar

von A.K. (Gast)


Lesenswert?

Philips AN10414 schon gelesen?

"Das betrifft wohl hauptsächlich µC, in denen ein ARM7-Core mit dem
VIC (Vectored Interrupt Controller PL190 von ARM) zusammen arbeitet."

Das zugrundeliegende Problem betrifft alle ARM7 Prozessoren mit
vektorisiertem Interrupt-Controller, egal welchen Typs. So auch Atmel
SAM7.

Ursache liegt darin, dass die Interrupt-Bearbeitung im Prozessor nicht
exakt zeitgleich mit der Interrupt-Verarbeitung im Interrupt-Controller
erfolgt.

von A.K. (Gast)


Lesenswert?

"Und wenn ich das nicht tue, sondern Interrupts nur über VIC Register
sperre und freigebe? Bin ich dann auch betroffen?"

Ich denke ja. Das Problem tritt ja auf, wenn sich der VIC-Zustand
ändert, nachdem der Prozessor den IRQ akzeptiert hat, aber bevor er den
Vektor holt. Manipulation der Interrupt-Enables im CPSR spielen also
keine Rolle (diese Phase ist schon durch), wohl aber alle Operationen,
die Einfluss auf dem Vektor nehmen können. Wozu Interrupts-Enable-Flags
an der Quelle und aber auch die Masken im VIC gehören.

Ich würde empfehlen, den Spurious Interrupt Handler in jedem Fall zu
implementieren. Der Versuch, sorgfältig um das Problem herum zu
programmieren, mag heute funktionieren, reagiert aber sehr empfindlich
auf spätere Änderungen.

von Dietmar (Gast)


Lesenswert?

Der VIC meldet den Interrupt eines Peripherals an den ARM-Core, ist
klar.

Natürlich, habe ich alle Application Notes durch.

Aber auch um die AN10414 gab es mächtigen Aufruhr, weil keine
vollständige Lösung und keine Linderung in Sicht (Nested Interrupts,
etc.).

Habe das Schaltbild des Vectored Interrupt Controllers meines µC
(LPC2129) im User Manual. Einige Gatter und Multiplexer. Ist da
irgendwas nicht richtig, was ich übersehe? Dort gibt es doch nur die
beiden Meldeleitungen IRQ und FIQ. Parallel dazu, muß der VIC die
Adressen und den Slot zuordnen, beim Interrupt den Vektor zurückgeben.
Laut Beschreibung, gibt es manchmal keine Zuordnung zum Vektor. Ist
hier was faul?

Ist das ein Design- oder Timing- Fehler?

Gruß

Dietmar

von Dietmar (Gast)


Lesenswert?

A.K.:

Danke für die Erklärung, da scheint die Arbeitsweise des VIC mit dem
ARM-Kern nicht synchron.

Also passiert das auch im "normalen" Betrieb, ohne auf den Kern
zuzugreifen.

Meine Anwendung ist mit einigen 10000 Interrupts pro Sekunde etwas
interruptlastig. Mit Spurious-Handler läuft tatsächlich meine Messung
präziser, das ist echt ein Ding !!! Simulieren oder debuggen kann man
das ja leider nicht.

Jetzt werde ich die Spurious Interrupts tatsächlich mal versuchen zu
zählen.

Also, den Default Interrupt muß ich ja dann auf jeden Fall installieren
(Interrupt, aber Zuordnung unbekannt).

Wenn ich das richtig verstanden habe, gibt es aber zum Spurious
Interrupt immer auch den echten Interrupt, so daß nichts verloren
geht?

Bin aber auch für jeden weiteren Tipp sehr dankbar.

Gruß

Dietmar

von A.K. (Gast)


Lesenswert?

"da scheint die Arbeitsweise des VIC mit dem ARM-Kern nicht
synchron."

Fairerweise muss man sagen, dass der Core hier unschuldig ist. Die
Vektorisierung ist ja im Core nicht vorgesehen, sondern findet separat
per Software statt. Daher ist das kaum vermeidbar.

"Wenn ich das richtig verstanden habe, gibt es aber zum Spurious
Interrupt immer auch den echten Interrupt, so daß nichts verloren
geht?"

Der Spurious Interrupt tritt ja nur dann auf, wenn dem VIC nichts
passenderes einfällt. Wenn du also sämtliche realen Interrrupt-Quellen
vektorisiert hast, muss im Default Handler bloss die üblichen
IRQ-Quittung stehen.

Etwas hässlich in der Philips Doku ist die mangelnde Unterscheidung
zwischen den Spurious Interrupts einerseits und dem Latency Problem bei
gleichzeitiger Abschaltung von IRQ und FIQ andererseits. Das sind aber
zwei völlig verschiedene Probleme.

Letzteres ist der radikalen Vereinfachung mit daraus folgender
inkonsistenter Verarbeitung von Interrupts zu danken: Interrupt-Check
vor/während der Ausführung eines Befehls, aber Ausführung vom Interrupt
danach. Die meisten Architekturen implementieren Interrupts so, als ob
die gesamte Interrupt-Verarbeitung konsequent zwischen zwei
aufeinanderfolgenden Befehlen erfolgt (wie auch immer das intern
realisiert sein mag).

Ich neige dazu, auf softwareseitige Priorisierung zu verzichten. Schön
ist's eh nicht, kostet Zeit und lässt sich meist durch alternative
Verarbeitung von Events lösen. Für ganz eilige Dinge hat man den FIQ,
und für den Rest sollte man im Interrupt nur das Nötigste tun, und den
Rest der Hauptschleife oder einer RTOS-Task überlassen.

von peter dannegger (Gast)


Lesenswert?

"Wenn ich das richtig verstanden habe, gibt es aber zum Spurious
Interrupt immer auch den echten Interrupt, so daß nichts verloren
geht?"


Es scheint so. Mein Kollege macht das auch so und es scheint zu
funktionieren.

Die AN10414 von Philips macht aber die Interruptbehandlung doppelt,
einmal im richtigen und einmal im Spurious Interrupt Handler. Das geht
aber nur, wenn man nur eine einzige Interruptquelle hat (aber für so
einfache Programme braucht man wiederum keinen ARM). Also ist diese
AN10414 voll fürn Arsch.

Warum solche derart wichtigen Sachen nicht mal klar und im Datenblatt
beschrieben werden, ist mir unverständlich !

Und es hat auch nichts mit ungeschickter Programmierung zu tun,
zeitweise Abschaltung von Interruptquellen ist immer dann ein Muß, wenn
ein Hauptprogramm mit einem Interrupthandler kommuniziert, wie z.B. bei
gepuffertem CAN, UART usw.. Sobald da ein Interrupt reinhaut (kritical
section), sind die Daten ja nicht mehr konsistent.

Und einsehen kann ich es auch nicht, warum nicht der richtige Vector
angesprungen wird, man hat doch nur das Enable-Bit gelöscht, der Vector
steht doch weiterhin da, wo er soll.
Und wenn CPU und VIC nicht synchron sind, was solls, schlimmstenfalls
wird der Interrupt trotz Sperre ausgeführt, wenn er schon in der Queue
ist. Mit 1-2 NOPs hinter einem Disable könnte bestimmt jeder leben.


Peter

von A.K. (Gast)


Lesenswert?

"man hat doch nur das Enable-Bit gelöscht, der Vector steht doch
weiterhin da, wo er soll."

Was soll er denn machen: Den höchstpriorisierten Vektor aller
abgeschalteten Interrupts liefern (stateless)? Oder immer den zuletzt
ermittelten?

Nope, mit Spurious Interrupts kann und muss man leben.

Solche Tierchen sind auch ausserhalb des ARM Terrariums quicklebendig.
Nur dass Intels 8259 keinen Default Vector hat, sondern anscheindend
seelenruhig den jeweils höchstnummerierten abliefert (im PC also 7 oder
15, je nachdem welchen Controller man erwischt). Da finde ich die
Philips-Variante sympathischer, wenngleich Atmel netterweise sogar
einen eigenen Vektor dafür vorsieht während Philips das mit
unvektorierten in den gleichen Topf schmeisst.

von Martin (Gast)


Lesenswert?

Hallo!

Aber ich finde, wenn man jetzt jeden IRQ, der auftreten kann in der
Standard-IRQ-Routine als spurious IRQ abfangen muss, dann finde ich
diese vektorisierten IRQs total umsonst.
Dann muss man ja alles doppelt abfragen und abfangen und über die
kleinen, älteren PICs schimpfen die meisten Leute, weil diese nur einen
IRQ-Vector besitzen.

Dann wäre es doch besser, wenn ich gleich nur die Standard-IRQ-Routine
nehme, denn dann habe ich keine Probleme mehr mit Spurious-IRQs, denn
dann fällt sowieso alles in einen Topf und ich brauch nichts doppelt zu
programmieren. Sehe ich das richtig?

Auch wenn solche Fehler bei Intel-Prozessoren anscheinend auch zum
Standard gehören, finde ich es nicht richtig, den Programmierer für
derart architektonische Nachteile büßen zu lassen, sodass dieser durch
programmtechnische Meisterleistungen glänzen muss, damit das Ding
endlich halbwegs korrekt läuft. Der Programmierer hat sowieso schon mit
der Realisierung der Anwendung zu tun.

Gruß, Martin

von A.K. (Gast)


Lesenswert?

"wenn man jetzt jeden IRQ, der auftreten kann in der
Standard-IRQ-Routine als spurious IRQ abfangen muss"

Musst du doch nicht.

Wenn ein Interrupt vektorisiert und aktiv ist, kommt der Vektor durch.
Den Default-Vektor liefert der VIC nur, wenn der Interrupt mal kurz
anlag, es aber zum Zeitpunkt des Vektorzugriffs nicht mehr tut. In
welchem Fall dich der Interrupt auch nicht interessieren muss.

Im Default-Vektor-Handler müssen sich nur nicht-vektorisierte
Interrupt-Routinen befinden. Und er muss in jedem Fall definiert
werden, auch wenn alle Interrupts vektorisiert sind. In diesem Fall
besteht die Routine nur aus dem üblichen abschliessenden Tritt in den
VIC und das war's.

von A.K. (Gast)


Lesenswert?

"finde ich es nicht richtig, den Programmierer für
derart architektonische Nachteile büßen zu lassen"

Ohne jetzt den gesamten Überblick zu haben, stelle ich hier mal die
These auf, dass jeder Controller mit vektorisierten Interrupts dieses
Problem hat, wenn die Vektoren nicht integraler Bestandteil der
Grundarchitektur sind.

Grund: Nur wenn die Information zur Interrupt-Quelle und dem dafür
auszuwählenden Vektor gleichzeitig mit der Interruptanforderung
anliegt, tritt das Problem nicht auf. Sobald der Core nur weiss
"Interrupt liegt an", nicht jedoch "welches Sprungziel" und dafür
irgendwo anfragen muss, ist das Problem mit spurious Interrupts nur
schwer zu vermeiden. Beispielsweise konnte das auch auf 68000 bei
externer Vektorquelle auftreten, nicht jedoch bei interner Vektorquelle
(Autovektoren).

von A.K. (Gast)


Lesenswert?

PS: Die Dokumentation eines Problems ist nicht notwendigerweise als
Nachteil des Produkts zu sehen! Schlimmer ist es, wenn das Problem
vorhanden und bekannt ist, man aber ohne Unterschrift unter ein NDA
(non disclosure agreement, also Maulkorb) nichts davon erfährt.

Diese Erfahrung hat z.B. Intel beim berühmten Divisionfehler des
Pentium-Classic gemacht, und daraus gelernt. Bis dahin waren bei den
Prozessoren offiziell so gut wie nie irgendwelche Fehler bekannt,
seither wimmelte es nur so von offiziell dokumentierten Fehlern.

von Martin (Gast)


Lesenswert?

Was wäre z.B., wenn man die Spurious-IRQ-Routine zwar anlegt, aber leer
ließe?
Würde der korrekte Vektor im Nachhinein vom µC nocheinmal gelesen und
angesprungen werden oder nicht?

von A.K. (Gast)


Lesenswert?

Es gibt keinen korrekten Interrupt-Vektor, weil es keinen Interrupt
gibt. Es gab zwar zeitweilig mal einen, es gibt ihn aber nicht mehr. Da
kein Interrupt vorliegt, passiert genau das was passieren soll: nichts.

Der obligatorische abschliessende Tritt in den VIC (schreiben ins
Vektorregister oder sowas in der Art, ich hab's hier grad nicht parat)
sollte in der Routine schon drin sein.

von Martin (Gast)


Lesenswert?

Ich lese mich mal in diese Problematik hinein.
Danke A.K. für deine guten Erklärungen.

Was ich nicht ganz verstehe ist das Watchdog-Handling, welches im
"AN10414 - Handling of spurious interrupts in the LPC2000"
beschrieben wird.

Dort steht über den Watchdog:
The feed sequence of the watchdog cannot be interrupted by any
interrupt source.
...
So a typical feed sequence would take the following form:

VICIntEnClr=0x... // Disabling interrupts in the VIC
WDFEED=0xAA;   // Feeding the Watchdog
WDFEED=0x55;
VICIntEnable=0x.. // Enabling interrupts in the VIC


Ich verstehe nun nicht, warum hierbei mittels VICIntEnClr der IRQ
ausgeschaltet wird, weil genau durch dieses Ausschalten und wieder
Einschalten diese spurious-IRQs herbeigeführt werden.

Wäre es dann nicht besser den IRQ mittel SWI-(Software Interrupt) zu
blockieren, damit das nicht passieren kann?

Danke.

Tschüss, Martin

von A.K. (Gast)


Lesenswert?

Ich will mal hoffen, das der Autor der AN genau weiss was er tut. Mir
erscheint das etwas mutig. Nicht wegen des möglichen spurious-IRQs,
denn der "verlorene" IRQ wird in diesem Fall später wieder
nachgeholt.

Aber diese Sequenz geht davon aus, dass die Abschaltung rechtzeitig
kommt, um das zugrundeliegende Watchdog-Problem zu vermeiden, nämlich
eine Unterbrechung zwischen den beiden FEEDs. Und das hängt vom exakten
IRQ-Timing zwischen VIC und ARM7TDMI-Core und damit vielleicht sogar von
Compiler-Optimierung ab.

Mir ist bei einer Core-internen Abschaltung wohler, also per
IRQ/FIQ-Bits im CPSR. Und spurious-IRQs kriegt man so auch nicht.

Inwiefern SWI?

von Martin (Gast)


Lesenswert?

Mit diesen SWI-Interrupts ist es möglich alle IRQs zu sperren.
Hierfür definiert man unter CARM z.B. eine Funktion. Auch ein
entsprechendes swi_verc.s-File muss noch eingebunden werden.
Sobald der µC aus der Funktion wieder rausspringt, sind alle IRQs
wieder frei.

void watchdog(void) __swi(0)
{
WDFEED=0xAA;
WDFEED=0x55;
}

Dieses Thema wird unter dem Stichwort SWI in der Keil-Umgebung genau
erklärt.

Gruß, Martin

von A.K. (Gast)


Lesenswert?

Ok, kenne Keil nicht. Ist da also ein SWI-Dispatcher drin?

Sieht sinnvoller aus, als die Variante im AN. Allerdings auch
langsamer, was aber in diesem Fall kaum stören dürfte.

von Martin (Gast)


Lesenswert?

Eine Frage habe ich noch:
Kann ein als FIQ-definierter IRQ auch einen Spurious-Interrupt auslösen
oder ist dies nicht möglich, da die FIQ-Routine auch mit einer
Standard-Adresse angesprungen wird?

Gruß, Martin

von A.K. (Gast)


Lesenswert?

Kann nicht passieren, da das FIQ-Sprungziel üblicherweise nicht durch
den VIC definiert wird. Das ist ja grad der von mir oben skizzierte
Unterschied zwischen interner und externer Vektorquelle, aus Sicht des
Cores.

von Martin (Gast)


Lesenswert?

Hallo A.K.!

Wird diese Funktion aufgerufen werden für die Dauer der Abarbeitung
alle IRQs gesperrt.
void watchdog(void) __swi(0)
{
WDFEED=0xAA;
WDFEED=0x55;
}

Ich habe es getestet und es traten beim besten Willen keine
Spurious-Interrupts mehr auf.

Aber was, wenn man nur einen bestimmten IRQ sperren möchte? Z.B. die
Serielle. Ich habe folgendes probiert:
U1IER= 0x00;  // Serieller IRQ aus.
...
U1IER= 0x07;  // Alle IRQ-S ein (außer Modem)

Mit dieser Konstruktion kam es auch immer wieder vor, dass
Spurious-Interrupts auftraten.
Ist es möglich einen einzelnen IRQ zu sperren, ohne dass später ein
Spurious auftritt oder muss man immer alle IRQs mittels SWI sperren?

Tschüss, Martin

von peter dannegger (Gast)


Lesenswert?

@Martin,

genau so ist es, die spurious Interrupts entstehen hauptsächlich beim
Sperren einer einzigen Interruptquelle.


Es wird wohl so sein, daß erstmal das Interruptflag den Interrupt
auslöst und danach dann nochmal das Interruptflag gelesen wird, um nun
den Vector zu bestimmen. Ist nun inzwischen genau diese Quelle gesperrt
worden, kann der Vector nicht mehr bestimmt werden.


Jeder auch nur einigermaßen bewanderte Hardwareentwickler hätte nun
einfach alle Interruptbits nach dem ersten Lesen gelatcht, bis ein
Vector gesendet wurde.

Das ist eigentlich absolutes Designgrundwissen, wenn ich ein Signal
später nochmal benötige, latche ich es einfach.


Peter

von A.K. (Gast)


Lesenswert?

"hätte nun einfach alle Interruptbits nach dem ersten Lesen gelatcht"

Wie stellst du dir das Zusammenspiel zwischen Core und VIC vor? Da
liest niemand automatisch die Interrupt-Bits. Die werden im VIC
sämtlich schlicht zusammen-geodert und als eine einzige IRQ-Leitung an
den Core weitergereicht. Und der fragt nicht zurück, sondern führt nur
seinen IRQ-Handler aus. Erst dort wird per Software der Vektor
abgefragt (und damit die Bits).

Wenn aus diesem Modell etwas werden soll, dann muss das IRQ-Request-Bit
im VIC "sticky" sein, d.h. es wird mit einlaufendem IRQ sofort gesetzt
und bleibt dies so lange, bis der Handler es explizit zurücksetzt.

Im UART-Beispiel von Martin würde allerdings im vergleichbaren Fall der
UART-Handler auch dann aufgerufen, wenn dieser Interrupt mittlerweile
vom o.A. Code ausgeschaltet wurde. Und die spurious Interrupts sind
folglich immer noch da, nur ein bischen anders verpackt.

von Dietmar (Gast)


Lesenswert?

Hallo Leute,

war ein paar Tage nicht im Internet und sehe zu meinem Thread 22
Postings. Da tut sich ja einiges, werde mich da auch wieder
entsprechend zu äußern.

Gruß

Dietmar

von Dietmar (Gast)


Lesenswert?

@Peter Dannegger:

"Jeder auch nur einigermaßen bewanderte Hardwareentwickler hätte nun
einfach alle Interruptbits nach dem ersten Lesen gelatcht, bis ein
Vector gesendet wurde.

Das ist eigentlich absolutes Designgrundwissen, wenn ich ein Signal
später nochmal benötige, latche ich es einfach."



==> Beim 8051 Z.B., sind Interruptflags fest gesetzt, da ist das kein
Problem mit der späteren Bearbeitung. Manche werden dann automatisch
gelöscht, z.B. TF0, manche auch nicht, z.B. TF2 beim Timer 2 Overflow.
Man hat da auch keine Architektur, in der Prozessorkern und Peripherie
komplett voneinander getrennt sind, wie beim ARM.

Nun, beim ARM bzw. LPC2000 gibt es kein Flag-Register, sondern nur eine
Interruptmeldung an den ARM-Core mit dazu gehörendem Vektor (oder auch
nicht: dann Default Interrupt oder Spurious!!!). Wie meinst du das?

Muß ich hier das VICRawIntr Register noch hinzuziehen, über das es auch
keine weitere Erläuterung im User Manual gibt?

Muß ich hier den Vectored Interrupt Controller (PL190) von ARM genauer
erforschen???

Zur allgemeinen Beruhigung: Habe sowohl direkt am Interruptvektor als
auch in der Default Interrupt Routine Fehlerzähler installiert, welche
aber nach vielen Millionen interner (Timer, 1 ms) und externer
Interrupts (10000 / sec) und einigen Betriebsstunden auf 0 stehen
geblieben sind. Also: keine Spurious Interrupts aufgetreten. Ist der
VIC Controller doch schnell genug? Warum ist dann das Thema noch so
brisant? Ist der LPC2000 doch besser als sein Ruf durch diese
Spezialitäten?

Wer möchte, bekommt da gerne auch ein paar Schnipsel Code, zur
Einfügung in die Startup.s von Keil z.B., über den ich dann gerne auch
ein Feedback oder Verbesserungsvorschläge hätte.

Gruß

Dietmar

von Dietmar (Gast)


Lesenswert?

@Peter Dannegger:

Beim LPC2000 kann man die Interruptfreigaben auf 2 Arten beeinflussen:

Einmal direkt im ARM-Kern, durch Manipulation des I- und F- Bits im
CPSR, oder über die VIC Register VICIntEnable bzw. VICIntEnClear.

Gruß

Dietmar

von Dietmar (Gast)


Lesenswert?

@A.K., und Martin:

Der VIC Default Interrupt darf in keinem Fall acknowledged werden, z.B.
mit VICVectAddr = 0 o.ä., sonst Endlosschleife im Default Interrupt!

Der muß leer bleiben.

Gruß

Dietmar

von Dietmar (Gast)


Lesenswert?

@Martin:

Ein einzelner FIQ hat eine eigene Sprungadresse und ist nicht vom VIC
abhängig.

Habe in meiner Anwendung 1 FIQ (Timer, zur absolut präzisen
Zeitmessung) und etwa 10 IRQ. Den Watchdog reloade ich nur über eine
SWI-Exception, nachdem ich feststelle, daß der Timer mit FIQ-Interrupt
noch einige Zeit entfernt ist. SWI deshalb, damit ihn nicht IRQ
durchbrechen. Dort sperre ich den FIQ (nur vorsichtshalber), und gebe
ihn nach der Watchdog Feed Sequenz wieder frei.

Gruß

Dietmar

von A.K. (Gast)


Lesenswert?

"Der VIC Default Interrupt darf in keinem Fall acknowledged werden,
z.B. mit VICVectAddr = 0 o.ä., sonst Endlosschleife im Default
Interrupt!"

Interessant. Widerspricht direkt der AN10414, denn dort steht genau das
drin.

Die Beschreibung der VIC-Makrozelle macht eine solche Schreiboperation
zwar nicht zwingend, da es unterhalb des Default Interrupts nix mehr
gibt, aber stören sollte es eigentlich auch nicht.

von A.K. (Gast)


Lesenswert?

"Ist der LPC2000 doch besser als sein Ruf"

Wie ich oben schon sinngemäss schrieb. Ein Hersteller steht bei
potentiellen Problemen, kleinen oder grossen, immer in dem Dilemma
(a) sag ich nix und hoffe dass es keiner merkt weil selten,
(b) ich dokumentiere es und ein paar Kunden flüchten davon weil ihnen
die Fehler-Doku nun zu dick wurde. Heutzutage ist dank schlechter
Erfahrungen mit (a) nun (b) üblich, aber das war nicht immer so.

Zudem muss das Problem nicht zwingend auftreten. Es gibt diese Biester
typischerweilse, wenn Interrupt-Ursachen wie von alleine wieder
verschwinden. In AN10414 wird das als Resultat der Kopplung zweiter
Interrupt-Ereignisse in der UART beschrieben. Wenn solche
Geistereffekte nicht auftreten, gibt's auch keine sprurious
Interrupts.

Probiert das doch mal aus, indem du im Hauptprogramm sehr häufig das
Interrupt-Flag des 1msec Timer zurücksetzt. Mit etwas Glück passiert
das irgendwann einmal genau zu dem Zeitpunkt, zu dem der Core sich für
den IRQ entschieden hat.

von A.K. (Gast)


Lesenswert?

Worin liegt eigentlich der Grund für diese pingelige Handhabung vom
Watchdog? Anders als bei AVR ist beim LPC2000 Feed ja keine
Zeitbedingung drin. Es muss nur sichergestellt sein, dass der zweite
Feed vor jedem anderen Watchdog-Zugriff drankommt.

Wenn also beispielsweise die Handhabung vom Watchdog an einer einzigen
Stelle der Mainloop erfolgt, kann man sich m.E. den ganzen Zirkus
sparen. Ob dann in die Feed-Sequenz ein Interrupt jedweder Art
reinrutscht, interessiert nicht wirklich.

von Thomas P. (pototschnig)


Lesenswert?

Ich hab auch schon fleissig mitgelesen, aber mir ist eins noch nicht so
ganz klar. Und zwar hab ich in meinem Cstartup.S folgendes:

        .global AT91F_Spurious_handler
        .func   AT91F_Spurious_handler
AT91F_Spurious_handler:
            b     AT91F_Spurious_handler
        .size   AT91F_Spurious_handler, . - AT91F_Spurious_handler
        .endfunc

Was hat es für einen Sinn, dass der nur im Kreis springt und da nie
wieder rauskommt?

von A.K. (Gast)


Lesenswert?

Sowas macht man, wenn man annimmt, dass der Fall nicht eintrifft, und an
dieser Stelle keine Idee für eine Debug-Ausgabe hat. Das Ergebnis ist
ein harter Stop und der JTAG-Debugger zeigt an warum.

Ob dieses Beispiel im Lichte von spurious Interrupts allerdings
wirklich sinnvoll ist, möchte ich mal bezweifeln.

von Dietmar (Gast)


Lesenswert?

@A.K.:

"Interessant. Widerspricht direkt der AN10414, denn dort steht genau
das drin."

Gibt es hier noch was spezielles zu beachten und ich darf den Default
Interrupt nicht auch noch für nicht vektorisierte Interrupts
verwenden?

Erscheint mir ja auch merkwürdig: Hatte nicht vektorisierte Interrupts
getestet, die natürlich auch in der Default-Routine auflaufen. Bei
Bestätigung mit VICVectAddr = 0 hängt der Interrupt dann tatsächlich in
einer Endlosschleife, womit man die gesamte Anwendung dann vergessen
kann. Nun, ist ja auch klar, es ist ein nicht vektorisierter Interrupt,
und der soll eben nicht bestätigt werden.

Gruß

Dietmar

von Dietmar (Gast)


Lesenswert?

@A.K.:

Habe aus dem User Manual die Info, daß die Watchdog Feed Sequenz
unmittelbar aufeinander folgen soll. Nun, einerseits geht das ja nicht,
weil einige mehrere Assemblerbefehle dahinterstecken, um auf die
Peripheral Register zuzugreifen. War mir bisher nicht so ganz klar.
Liebend gerne schaffe ich eine aufwendigere Konstruktion wie den SWI
dafür auch gerne wieder ab.

Gruß

Dietmar

von Dietmar (Gast)


Lesenswert?

@Thomas Pototschnig:

Das ist dann wie bei den Exception-Vektoren?

Wenn man sie nicht selbst ändert, hängen sie and er Stelle, wo der
Vektor steht, fest (z.B. Startup.s von Keil). Also, da muß man selbst
ran und was ändern.

Gruß

Dietmar

von A.K. (Gast)


Lesenswert?

"Habe aus dem User Manual die Info, daß die Watchdog Feed Sequenz
unmittelbar aufeinander folgen soll."

Wo?

Die einzige ähnliche Aussage, die ich finden kann, stellt nur fest,
dass dazwischen kein anderer Zugriff auf den watchdog register space
erfolgen darf.

"Endlosschleife"

Arbeitest du mit IRQ-Nesting? Wenn ja, solltest du die IRQs vor dem
Acknowledge wieder ausschalten (so wird's auch in der entsprechenden
AN gemacht).

Andernfalls ergibt dieses Verhalten für mich keinen Sinn.

von A.K. (Gast)


Lesenswert?

"ich darf den Default Interrupt nicht auch noch für nicht vektorisierte
Interrupts verwenden?"

Warum nicht?

von Dietmar (Gast)


Lesenswert?

@A.K.:

Du scheinst doch schon etwas detaillierte Kenntnisse über
ARM-Prozessoren zu haben, über die üblichen Anwendungen mit
ARM-Mikrocontrollern hinaus. Erst mal Danke für deine Anregungen.

Nun, als Entwickler ist man üblicherweise sonst auf sich alleine
gestellt und auf den gesunden Menschenverstand angewiesen.

Über die AN10414 gab es kürzlich eine Menge Aufruhr und Unstimmigkeiten
im LPC2000-Forum von YAHOO (dieses Forum ist übrigens auch sehr
empfehlenswert, jedoch "nur" englischsprachig). Da wäre z.B. ein
Konflikt mit der Spurious Behandlung und der Betriebsart "Nested
Interrupts per Software" (das ist eine Unterbrechung von IRQ durch
andere IRQ durch Software-Trick).

Das geht aber schon sehr ins Detail, und die Nested Interrupts braucht
man nicht in jeder Anwendung, da ja klare Prioritätslogik.

@Alle:

Hatte ein Stück Behandlungscode zum Spurious Interrupt IRQ angekündigt,
zur direkten Anbindung an den IRQ-Vektor, und poste das wegen der
geringen Größe direkt hier im Textfenster. Der Code wird direkt vom
IRQ-Vektor angesprungen und befindet sich in der Startup.s von Keil bei
mir auch direkt hinter den Vektoren:

IF (SPUR_IRQ_SETUP != 0)

IRQ_Spurious_Handler:     ; Sprung vom IRQ-Vektor 0x00000018:

SUB     LR,  LR, #0x04    ; Justierung der Returnadresse
STMFD   SP!, {R0-R1, LR}  ; sichere Register auf Stack
MRS     R0,  SPSR         ; Ist ein IRQ-Interrupt aufgetreten,
TST     R0,  #I_Bit       ; während IRQ-Interrupts gesperrt sind?
LDMNEFD SP!, {R0-R1, PC}^ ; spurious Interrupt: kehre zurück
; berechne Sprung zum Interrupt ohne Zerstörung von Registern:
ADD     LR,  LR, #0x04    ; Justierung der Returnadresse
LDR     R0,  =VIC_VECT_ADDR ; echter IRQ-Interrupt:
LDR     R0,  [R0, #0]     ; lade Vektor von VicVectAddr
MOV     R1,  SP           ; lade aktuelle Stapeladresse
ADD     R1,  R1, #0x08    ; Rücksprungadresse im Stapel
STR     R0,  [R1]         ; speichere Sprungadresse
LDMFD   SP!, {R0-R1, PC}  ; Sprung zur Interuptbearbeitung

ENDIF


Die ersten 5 Zeilen entsprechen in etwa dem Vorschlag aus dem Philips
User Manual. Was mir daran selbst nicht gefällt, ist, daß ich die
Rücksprungadresse zum Interrupt direkt auf dem Stack manipulieren
mußte. Eine andere Lösung habe ich programmiertechnisch noch nicht, da
ich kein Register beschädigen wollte.

Tritt ein (Spurious) Interrupt in dem Fall auf, wenn das Programm
gerade versucht hat, das I-Bit zu disablen (I=1), erfolgt eine Rückkehr
an der Stelle:
LDMNEFD SP!, {R0-R1, PC}^

Natürlich entsteht hier für jeden IRQ eine erhöhte Reaktionszeit!
Das stört jedoch nicht wirklich, weil hardwareabhängige Dinge wie z.B.
Timer Capture, dann schon abgeschlossen sind und davon relativ
unabhängig funktionieren.

Im Simulator klappt das wunderbar.

Was in der realen Anwendung passiert, habe ich noch nicht ganz genau
heraus. Vielleicht werde ich ein reines Assembler-Testprogramm für den
Simulator erstellen, auch um herauszufinden, was genau mit der Pipeline
passiert. Das Debug-Fenster bei Keil ist da etwas unübersichtlich.

Wer den Beispielcode verwenden möchte: Gerne, auf eigene Gefahr.
Wenn jemand hier noch was sieht, was nicht ganz sauber und nicht in
Ordnung ist, dann bin ich für jeden Hinweis dankbar.


Gruß

Dietmar

von Dietmar (Gast)


Lesenswert?

@A.K.:

"ich darf den Default Interrupt nicht auch noch für nicht
vektorisierte Interrupts verwenden?

Warum nicht?"

Also, dann laufen im Default Interrupt spuriouse und legale nicht
vektorisierte Interrupts auf.

OK, denkbar.

Das ist z,B. mit einem Switch-Case über das Register VICIRQStatus
machbar.

Eine Unterscheidung, welche Interrupts ich acknowledgen muß, erübrigt
sich auch, nämlich keine.

Gruß

Dietmar

von Dietmar (Gast)


Lesenswert?

@A.K.:

"Endlosschleife"

Nein, kein Interrupt Nesting, das war ein ganz simples Testprogramm mit
einer minimalen Main-Schleife und einem einzigen nicht vektorisierten
Interrupt.

In anderen Exceptions wie PAbt, DABt, Undef, darf man auch kein
Acknowledge verwenden, weil das gleiche Prinzip: Die nicht
vektorisierten Interrupts werden doch nicht vom VIC-Controller
behandelt!

Gruß

Dietmar

von A.K. (Gast)


Lesenswert?

"In anderen Exceptions wie PAbt, DABt, Undef, darf man auch kein
Acknowledge verwenden"

Logisch. Die haben ja auch rein garnichts mit dem VIC zu tun.

Die (dokumentierte) Logik beim VIC ist jedoch, dass zu einem
Lesevorgang auf VicVectAddr immer auch ein abschliessender
Schreibvorgang gehört.

Wenn allerdings in einem sehr einfachen Interruptsystem der ARM
IRQ-Handler den Vektor garnicht abfragt, sondern der Code an 0x18 statt
dessen direkt den IRQ-Handler anspringt, dann ergibt auch das
Acknowledge keinen Sinn.

von A.K. (Gast)


Lesenswert?

TST     R0,  #I_Bit       ; während IRQ-Interrupts gesperrt sind?
LDMNEFD SP!, {R0-R1, PC}^ ; spurious Interrupt: kehre zurück"

Oha, jetzt kommen wir der Sache näher! Ich hatte oben erwähnt, dass es
rund um ARM-Interrupts zwei Themen gibt, die gerne miteinander
verwechselt werden. Auch in der Yahoo group. Auch die Philips AN trennt
das nicht deutlich genug.

Das was du hier abhandelst, ist garnicht der "spurious interrupt".
Sondern dass, was in
http://water.cse.unsw.edu.au/esdk/lpc2/spurious-irq.html als "surprise
interrupt" bezeichnet wird, also das Problem bei gleichzeitigen
Abschalten von IRQ und FIQ per CPSR. Was mit dem VIC wiederum nichts zu
tun hat.

von A.K. (Gast)


Lesenswert?

Um das mal kurz und "deutsch" zusammenzufassen:

(1) "surprise interrupt": IRQ und FIQ werden gleichzeitig per
MSR-Befehl abgeschaltet. Aufgrund einer Eigenheit der ARM-Cores kann
dennoch der IRQ-Handler aktiv werden, dann aber mit abgeschaltetem FIQ
was massiv dessen Latenzzeit schadet. Hierzu siehe Philips AN10254 und
FAQ Eintrag auf www.arm.com.

(2) "spurious interrupt": Der VIC reicht eine Interrupt-Anforderung
als IRQ durch, findet aber zum Zeitpunkt der Vektorerzeugung (das ist
der Ladebefehl auf VicVectAddr) keine Interrupt-Anforderung mehr vor,
weil die in der Zwischenzeit wieder verschwand. Da der VIC die
Interrupt-Anforderung nicht speichert, kann er keinen korrekten Vektor
erzeugen und liefert den Standardvektor (Atmel SAM7 hat dazu einen
eigenen Vektor).

Beide Fälle müssen getrennt betrachtet werden.

Für (1) tut es z.B. der von dir gezeigte Code. Natürlich muss da auch
nichts in VicVectAddr geschrieben werden, denn es wurde ja auch nichts
gelesen. Man kann sich den IRQ-Handler auch vereinfachen, indem man,
wie in der AN gezeigt, den FIQ nie in einem Befehl zusammen mit dem IRQ
abschaltet.

Bei (2) gehen die Meinungen etwas aueinander. Philips legt nahe, im
Default-Handler alle möglichen Ursachen von spurious Interrupts
abzufragen. Diesen ausgesprochen komplexen Weg kann ich jedoch nicht
ganz nachvollziehen (der Autor im o.A. Link wohl auch nicht).

Bei (2) wird dein Code den Vektor aus VicVectAddr lesen und in den
Default-IRQ-Handler springen. Wenn nested Interrupts nicht verwendet
werden, reicht es m.E. aus, dort die ggf. fälligen nichtvektorierten
IRQs abzuhandeln, anschliessend per Schreibzugriff auf VicVectAddr den
VIC wieder freizugeben und dann Return. Diese Vorgehensweise wurde auch
in Beträgen in der Yahoo-Group skizziert

von Dietmar (Gast)


Lesenswert?

@A.K.:

Na klar, ich möchte beiden Problemen vorbeugen, da ich auch mal das
I-Bit und das F-Bit verändern möchte.

Die FAQ auf der ARM Homepage ist eine Teilmenge der Beschreibung im
Philips User Manual. Philips räumt noch die Sache mit dem VIC mit ein,
ARM nicht.

Spurious Interrupts des VIC konnte ich bisher nicht einen einzigen
registrieren. Und, laß den doch alle 10 Minuten mal kommen, damit kann
ich wahrscheinlich noch leben.

Warum den Default Handler ausbauen? Wenn nicht acknowledged, kommt der
Interrupt doch nochmal, und zwar mit Vektor, oder?

Gruß

Dietmar

von A.K. (Gast)


Lesenswert?

"Die nicht vektorisierten Interrupts werden doch nicht vom
VIC-Controller behandelt!"

Selbstverständlich werden auch nichtvektorierte Interrupts vom VIC
behandelt. Immerhin reicht er sie durch, wie auch die FIQs. Und liefert
bei der fälligen Abfrage von VicVectAddr den Default-Vektor.

von A.K. (Gast)


Lesenswert?

"Na klar, ich möchte beiden Problemen vorbeugen, da ich auch mal das
I-Bit und das F-Bit verändern möchte."

Darfst du ja auch, Du darfst auch beide abschalten wie es dir beliebt.
Wenn du es allerdings einrichten kannst, nie beide zusammen mit dem
selben MSR-Befehl abzuschalten, sondern allenfalls nacheinander, dann
kann die Sonderbehandlung im IRQ-Handler entfallen.

"Wenn nicht acknowledged, kommt der Interrupt doch nochmal, und zwar
mit Vektor, oder?"

Wenn der ursprüngliche Interrupt-Auslöser es sich anders überlegt und
die Anforderung gelöscht hat, dann kommt dieser zweite nicht und die
Anforderung geht verloren. Mir fällt bloss kein Szenario ein, wo mich
dieses Verhalten stört.

Im Fall der UART mit CTI und RDA beschreibt Philips recht deutlich, wie
"spurious interrupts" auftreten können und dass sie schwer zu
vermeiden sind. Soweit d'accord. Es wird freilich nicht erklärt,
weshalb im default handler unbedingt die UART gelesen werden muss. Es
kann ja eigentlich nichts schlimmeres passieren, als dass der fällige
Interrupt ein paar Bytes später erneut anlandet, nämlich sobald der CTI
Timer wieder zuschlägt oder das FIFO hinreichend voll ist.

Allerdings wird "Jayasooriah" m.E. zum Prinzipienreiter, wenn er
nahelegt, dass jeder "spurious interrupt" einer zuviel und das System
beim Auftreten eines solchen unbrauchbar ist, bloss weil er die Aussage
in der VIC-Dokumentation nicht verstanden hat.

"Philips räumt noch die Sache mit dem VIC mit ein, ARM nicht."

Für ARM sind Core und VIC zwei paar Stiefel. Der "spurious interrupt"
wird, etwas verschlüsselt, in der Doku des VIC erwähnt.

von Martin (Gast)


Lesenswert?

Hallo Leute!

Ich weiß, dass das jetzt nicht ganz zum Thema gehört, aber ich habe
eine grundsätzliche Frage zu Nesting-IRQs.

Es gibt ja von Keil so nette Makros bzw. in der Doku AN10381 sind diese
auch beschrieben, wie man es schafft, die IRQs in einer IRQ-Routine
wieder freizugeben.

Wenn jetzt z.B. die Nesting-IRQs bei der UART angewendet werden.
Sagen wir die UART empfängt ein Zeichen, die UART-IRQ-Routine wird
angesprungen, die IRQS werden nach dem Eintreten wieder freigegeben.
Nun befindet sich der Programm-Counter in der der IRQ-Routine und nun
tritt ein nächster IRQ auf, der besagt, dass der Sende-Buffer der UART
leer ist. Wird nun dieselbe IRQ-Routine nocheinmal angesprungen oder
gilt dies nur für den Fall, dass ein anderer IRQ auftritt? Kann sich
die Routine durch einen nächsten IRQ selbst unterbrechen oder nicht?

Danke.
Gruß, Martin

von A.K. (Gast)


Lesenswert?

Theoretisch sollte die Prioritätslogik des VIC verhindern, dass ein
Interrupt von einem gleicher Priorität unterbrochen wird. Praktisch
würde ich darauf keine Wetten abschliessen, da das ganze
Prioritätsgedöns vom VIC m.E. nicht schlüssig ist.

Siehe http://www.mikrocontroller.net/forum/read-1-343285.html#343285

von Martin (Gast)


Lesenswert?

Hallo Leute!

Wie ich das sehe, lasse ich das für den Anfang mit den Nestet-IRQs.

Aber mit den Spurious-IRQs arbeite ich noch einbisschen.
Ich habe mir das Beispiel mit dem Timer aus der Doku AN10414
Spurious-Interrupts noch etwas angeschaut.

VICIntEnClr=0x... // Disabling interrupts in the VIC
WDFEED=0xAA;   // Feeding the Watchdog
WDFEED=0x55;
VICIntEnable=0x.. // Enabling interrupts in the VIC

Das Lustige daran war, dass wenn ich z.B. folgende Zeilen zusätzlich
einbaute, dass der Spurious-IRQ beim besten Willen nicht ausgelöst
wurde.
VICIntEnClr=0x... // Disabling interrupts in the VIC
IOSET1=0x01<<16;
WDFEED=0xAA;   // Feeding the Watchdog
WDFEED=0x55;
IOCLR1=0x01<<16;
VICIntEnable=0x.. // Enabling interrupts in the VIC

Sehr sonderbar.
Hat jemand eine Erklärung für dieses Phänomen?

Gruß, Martin

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.