www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik AT91SAM7 -> Interrupts verschachteln (nested IRs)


Autor: Tom W. (nericoh)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo zusammen,

zwar habe ich hier im Forum einige wenige Beiträge gefunden, die auch 
nested IRs beim AT91SAM7 behandeln, allerdings mit etwas anderer 
Zielsetzung. Falls ich doch einen passenden Thread übersehen haben 
sollte, bitte ich um kurze Info!

Ich verwende das RealView MDK / uVision

Folgendes möchte ich tun:

mit dem PIT des AT91 möchte ich einen Interrupt auslösen. Da es 
passieren kann, dass erneut ein PIT-IR erzeugt wird, bevor die vorherige 
ISR abgearbeitet ist, möchte ich es zulassen, dass diese ISR mehrfach 
vom AIC aufgerufen werden kann (mir ist klar, dass das zunächst 
ungewöhnlich und nach Pfusch klingt, es steckt aber eine wohldurchdachte 
Firmwarearchitektur dahinter, falls es wen interessiert, erkläre ich ich 
demjenigen das auch gerne näher;p).

Soweit meine bisherige Recherche in Datenblättern, Foren, Handbüchern 
etc. ergeben hat, beherrscht der AT91 grundsätzlich verschachtelte 
("nested")IRs. Die entscheidenden Fragen sind:
- kann ich auch mehrere IRs von gleicher Prio verschachteln ?
- falls ja, ist es darüber hinaus möglich, dass über eine einzige ISR zu 
tun (die dann eben mahrach verschachtelt wird)?

Das einfach zyklische Anspringen der ISR und auch der Rücksprung 
funktionieren bereits Problemlos, nur eben die Verschachtelung klappt 
(noch) nicht. Bei Bedarf poste ich auch gerne den Code, mit dem ich das 
bisher realisiere.

Wäre wahnsinnig dankbar, wenn mir dabei jemand weiterhelfen könnte, da 
ich das dringend für meine Bachelorarbeit benötige und mein Zeitrahmen 
äußert knapp bemessen ist.

MfG,
neri aka Tom

Autor: Robert Teufel (robertteufel)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Tom,

das Stichwort, das Du benoetigst fuer die Suche ist "reentrant" und ist 
eine Stufe kniffliger als ein Nested Interrupt
Nur mal ein Link zum Wiki
http://en.wikipedia.org/wiki/Reentrant_%28subroutine%29

Hoffe das hilft Dir weiter in der Suche, ist allerdings nicht ohne!

Gruss, Robert

Autor: Tom W. (nericoh)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi Robert,

ich danke dir schonmal für den Hinweis! Werde mich da morgen wieder 
intensiv mit beschäftigen - Kniffliges bin ich mittlerweile gewohnt;)

MfG,
Tom

Autor: Marcus Harnisch (mharnisch) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Neben dem Atmel Interupt Controller, musst Du auch einige Besonderheiten 
des ARM7 Kerns kennen, um nested interrupts erfolgreich zu 
implementieren. Siehe dazu einige Beispielprogramme im MDK Verzeichnis. 
Deine Lieblingssuchmaschine könnte auch weiterhelfen.

Viel Erfolg
Marcus

Autor: Tom W. (nericoh)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nach einigen Weiteren Untersuchungen und Überlegungen komme ich zu dem 
Schluss, dass ich momentan noch ein viel grundlegenderes Problem habe:

laut Datasheet des AT91SAM7 soll in einer ISR zuallererst das "Interrupt 
Vector Register" (AIC_IVR) gelesen werden. Wenn ich das aber tue, bleibt 
der Controller an dieser Stelle hängen. Mir ist rätselhaft, warum er das 
tut.

Hier die relevanten Auszüge aus meinen Quellcode, sieht irgendjemand da 
draußen, was ich falsch mache?

//init the Advanced Interrupt Controller
*AT91C_AIC_IECR  = 0x00000002;  //enable peripheral ir
AT91C_AIC_SMR[1] = 0x00000021;  //prio of periph-ir, pos. edge triggered  
AT91C_AIC_SVR[1] = (AT91_REG) ISR_periph1; //set adress to branch to if PIT IR occurs

//init of the Periodic Internal Timer
*AT91C_PITC_PIMR   = ( 0x000FFFFF & ( TIMER_PARA_MicroCycle * (TIMER_PARA_SysClock / (16 * 1000) ) ) ) ;    //set cycle of timer
*AT91C_PITC_PIMR   |= 0x03000000;    //enable the timer and the corresponding IR

__irq void ISR_periph1 (void)           //executed every time a peripheral IR occurs
{
  //tempvar = *AT91C_AIC_IVR;         //sobald ich diesen Regzugriff mache, wird die nächste Codezeile nichtmehr ausgeführt -> warum bloß?
  
  SET_PWR_LED(ON);
      
  if ( *AT91C_PITC_PISR )          //IR caused by Periodic Interval Timer ?  
  {     
    uscount += TIMER_PARA_MicroCycle;

    if (uscount == 1000)        //when 1000us (=1ms) passed
    {  
      uscount = 0;          //reset mscounter
      task_1ms();
    }   

    *AT91C_AIC_ICCR    = 0x00000002;  //clear the IR-Bit
    tempvar   = *AT91C_PITC_PIVR;    //reading PIVR resets the timer ir

  }

  *AT91C_AIC_EOICR   = 0xFFFFFFFF;   //end of IR
}

Anmerkung: ich habe das hier stark verkürzt und vereinfacht, um besser 
nachvollziehbar zu machen, was grundsätzlich passiert.

Solange ich den Lesezugriff auf das IVR rauslasse, wird die ISR auch 
brav zyklisch aufgerufen.

Autor: Tom W. (nericoh)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Halt, Kommando zurück, auf einmal bleibt er da nichtmehr hängen... Werde 
das erstmal eingehender untersuchen, bevor ich euch damit weiter 
behellige.

Gruß,
Tom

Autor: Tom W. (nericoh)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Habe jetzt einen weiteren Beitrag zu der IVR-Problematik erstellt, da 
die Diskussion hier nicht hinpasst:

Beitrag "AT91SAM7 + uVsion3 IR-Handling"

Sobald ich das Problem geklärt habe, gehts hier weiter :)

Tom

Autor: klaus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Soweit meine bisherige Recherche in Datenblättern, Foren, Handbüchern
> etc. ergeben hat, beherrscht der AT91 grundsätzlich verschachtelte
> ("nested")IRs. Die entscheidenden Fragen sind:
> - kann ich auch mehrere IRs von gleicher Prio verschachteln ?
> - falls ja, ist es darüber hinaus möglich, dass über eine einzige ISR zu
> tun (die dann eben mahrach verschachtelt wird)?

Bei Nested-Interrupts mußt du vor allem das SPSR sowie alle bentutzten 
Register auf den Stack legen bevor du Interrupts wieder zuläßt. Das ist 
notwendig damit dein Interrupt Handler reentrant wird. Für non-Nested 
Interrupts ist das nicht nötig, da hier einfach die Register-Bank 
geswitched wird (z.B. von IRQ nach FIQ). Bei Nested-Interrupts 
unterbricht aber beispielsweise ein IRQ einen anderen IRQ, d.h. es wird 
keine Register-Bank geswitched. Dadurch zerstört der zweite Aufruf die 
Register-Zustände des vorherigen Handlers kommt aller Regel einem 
Absturz der Software gleich...

Autor: Tom W. (nericoh)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ah, interessant, das war mir in der Form nicht bewusst. Ich bin davon 
ausgegangen, dass der gesamte Kontext einer ISR, die durch einen anderen 
ISR unterbochen wird, einfach auf dem Stack gesichert und anschließend 
wiederhergestellt wird, eben so als würde eine normale Funktion 
unterbrochen. Und wenn das so wäre, wäre ja eine (mehrfache) 
Verschachtelung kein Problem, solange der Stack nicht überläuft. Kann 
mir jemand was dazu sagen, warum das so ist wie von Klaus beschrieben? 
Mir leuchtet noch nicht ein, warum damit nicht einfach so verfahren wird 
wie mit Sprung und Rücksprung bei einer regulären Funktion...

Autor: Marcus Harnisch (mharnisch) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Tom W. schrieb:
> Kann mir jemand was dazu sagen, warum das so ist wie von Klaus
> beschrieben?

RISC. Mache die einfachen Sachen einfach und die komplizierten Dinge
möglich.

Bei Cortex-M hat man das anders gemacht und lässt hier den Prozessor
selbständig seinen Kontext sichern.

> Mir leuchtet noch nicht ein, warum damit nicht einfach so verfahren
> wird wie mit Sprung und Rücksprung bei einer regulären Funktion...

Wird es ja -- fast. Nur ist beim Funktionsaufruf der Zeitpunkt
bekannt, zu dem der Kontext gesichert werden muss. Der Compiler
erzeugt den notwendigen Code. Bei einem Ereignis kann das naturgemäß
nicht erfolgen und der Entwickler muss den Code selbst implementieren.

Gruß
Marcus

Autor: klaus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Tom W. schrieb:
> Mir leuchtet noch nicht ein, warum damit nicht einfach so verfahren wird
>
> wie mit Sprung und Rücksprung bei einer regulären Funktion...

Wenn ein Interrupt auslöst wird das CPSR das ja deine Flags enthält in 
das SPSR des jeweiligen Modus (also der neuen Register-Bank) kopiert. 
Unter normalen Umständen muss der Interrupt Handler es nicht extra 
sichern, da wenn z.B. ein IRQ ausgelöst hat IRQ Interruts gesperrt 
werden. Wenn du IRQs im Interrupt handler nun wieder einschaltest, würde 
aber ein neuer IRQ den im SPSR Register gespeicherten Wert wieder 
überschreiben.


PS: Ich hoffe ich habe mich nicht mißverständlich ausgedrückt. Nicht 
alle Register werden umgeschaltet (sind also auf separaten 
Register-Bänken); eine Übersicht ist z.B. hier:

http://public.beuth-hochschule.de/~heineman/ESL6/A...

Autor: Martin (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
... Bei Nested-Interrupts mußt du vor allem das SPSR sowie alle 
bentutzten
Register auf den Stack legen bevor du Interrupts wieder zuläßt. ...

Ist das nicht die Aufgabe des Compilers?

Autor: klaus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Ist das nicht die Aufgabe des Compilers?

Wenn es entsprechende Optionen gibt über die entsprechender Entry- und 
Exit-Code erzeugt werden kann dann ja. Non-Nested interrupts werden aber 
wohl dann die Default-Einstellung sein...

Autor: Marcus Harnisch (mharnisch) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Martin schrieb:
> ... Bei Nested-Interrupts mußt du vor allem das SPSR sowie alle
> bentutzten
> Register auf den Stack legen bevor du Interrupts wieder zuläßt. ...

Und den Mode wechseln und dessen Kontext sichern, freilich nachdem man
das Stack alignment überprüft hat, etc. Kann man sich ja als inline
Assembler Makro schreiben.

> Ist das nicht die Aufgabe des Compilers?

Das Dumme ist nur, das Teile dieses erheblichen Overheads eben nicht
immer notwendig sind und eine Syntaxerweiterung, die dieses Framework
automatisch generiert, in einer gegebenen Situation nicht passend
wäre.

Gruß
Marcus

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Es zeigt sich darin das Alter der Architektur und ihr Designziel.

Das Interrupt-Konzept der ARMs ist noch fast identisch mit der ersten 
Version davon aus Mitte der 80er (erst die Cortexe brechen damit) und 
beim Design dieses ersten ARM hatte niemand im Auge, dass daraus sowas 
wie ein Standard für 32-Bit Controller mit einer Lebensdauer von 
mindestens 3 Jahrzehnten werden könnte. Der war nur als Triebwerk 
bestimmter Spiel&Lern-Computer konzipiert worden.

Die andere Kursichtigkeit, der nur 64MB adressierende Program Counter 
(R15 = 24-Bit PC und 8-Bit PSR), wurde bald repariert. Die 
Fehlkonstruktion bei den Interrupts blieb. Leider. Warum man das damals 
nicht gleich mit reparierte ist mir ein Rätsel.

Mit RISC-Sparsamkeit hat das nur insofern zu tun, als man offenbar 
meinte, für den Einsatzzweck mit 2 Interrupt-Prioritäten ohne Nesting 
auszukommen. Sonderlich komplex wäre ein Konzept mit einfacher 
Unterstützung von Nesting nicht gewesen. Es hätte völlig ausgereicht, 
bei Interrupts den PC nicht in R14 sondern in einem ausschliesslich 
dafür reservierten Spezialregister zu retten, vgl. SPSR.

Autor: Maxx (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Marcus Harnisch schrieb:
> Und den Mode wechseln und dessen Kontext sichern

Wollte ich nochmal herausheben: Nicht vergessen den Mode zu wechseln!

Neben dem SPSR wird auch R14_irq bzw LR_fiq (die jeweiligen LR) 
überschrieben. Damit wird ein BL innerhalb einer unterbrechbaren 
IRQ-Mode-Routine zum Stolperstein, weil die Rücksprungaddresse verloren 
gehen kann.

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Man kann das auch brav bei ARM nachlesen: 
http://infocenter.arm.com/help/index.jsp?topic=/co...

Ein anderer Ansatz besteht darin, als ISR zunächst einen zentralen in 
Assembler geschriebenen Interrupt-Handler anzuspringen, der diesen 
Verwaltungskram erledigt, und darin dann den vom Interrupt-Controller 
gelieferten Vektor aufzurufen. Bremst ISRs ohne Nesting etwas ab, man 
wird damit aber völlig unabhängig von irgendwelchem Compiler-Zauber weil 
die ISRs nun wie bei den Cortexen ganz normale C Funktionen sind.

Autor: gerhard (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hallo tom,
ich würde dir empfehlen die atmel beispiele (software packages) mal 
anzusehen.
in board_cstartup_keil.s findest du den entsprechenden irq-handler der 
auch nested interrupt unterstützt.

gruss
gerhard

Autor: Marcus Harnisch (mharnisch) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
A. K. schrieb:
> Das Interrupt-Konzept der ARMs ist noch fast identisch mit der ersten
> Version davon aus Mitte der 80er (erst die Cortexe brechen damit)

Nein, nur Cortex-M. Bei den anderen hat sich da nichts geändert.

> Warum man das [Exception Handling] damals nicht gleich mit reparierte ist
> mir ein Rätsel.

Ich vermute, dass der Verlust der Kompatibilität als zu schmerzhaft 
eingeschätzt wurde, vor allem, da durchaus praktikable Workarounds 
existieren. In der v6 Architektur hat man schließlich einige Befehle 
ergänzt (SRS, CPS und RFE), die den top-level handler erheblich 
vereinfachen. In Applikationsprozessoren, die letztlich alle ARM 
Prozessoren zu ihrer Zeit waren, sind die Kosten dieser Einschränkung 
vergleichsweise gering.

Erst mit dem Cortex-M3 hat man direkt auf den Microcontroller Markt 
gezielt, wodurch man die Änderung des Modells rechtfertigen konnte.

--
Marcus

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Marcus Harnisch schrieb:

> Ich vermute, dass der Verlust der Kompatibilität als zu schmerzhaft
> eingeschätzt wurde,

Sicher, aber die ging mit der Abkehr von der 26-Bit Adressierung und der 
deshalb neuen Register CPSR und SPSR sowieso schon vor die Hunde. Das 
wäre der exakt richtige Zeitpunkt für ein analoges Register SPC gewesen. 
Danach nicht mehr, das stimmt.

> Erst mit dem Cortex-M3 hat man direkt auf den Microcontroller Markt
> gezielt, wodurch man die Änderung des Modells rechtfertigen konnte.

Mag auch damit zusammenhängen, dass dies m.W. die einzigen Cores ohne 
ARM-Modus sind, somit eine Kompatibilität zum bisher zwangsläufig darin 
landenden ISR-Code dazu ohnehin nicht drin war.

Autor: Tom W. (nericoh)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke erstmal für die vielen Gedanken und Anregungen zum Thema!

Die nested IRs habe ich inzwischen am Laufen, werde jetzt noch 
versuchen, reentrant zu implementieren. Ich hoffe ich werde 
anschließend die Zeit finden, hier ein HowTo zu posten, damit alle, die 
auch mal vor diesem Problem stehen, sich da nicht so lange mit 
aufhhalten müssen ;p

Tom

Autor: Tom W. (nericoh)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Falls noch jemand nach der Lösung suchen sollte:
der Hinweis von prx auf das ARM Infocenter hat die Lösung gebracht

http://infocenter.arm.com/help/index.jsp?topic=/co...

Ich stehe auf Anfrage auch gerne zur Unterstützung zur Verfügung.

Tom

Autor: Lothar (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Auch Cortex-A und Cortex-R nutzen noch das IRQ/FIQ Konzept. Re-entrante 
Interrupts sind auch nicht schwierig. Der IRQ Handler sieht doch am 
Anfang welcher Interrupt kommt, kann prüfen ob der vorher schon lief und 
unterbrochen wurde, und entsprechend den Kontext sichern. Üblich ist für 
die IRQ eine Queue anzulegen, meist doppelt verkettete Liste, wo man 
sich die aktiven und pending IRQ merkt und auch nach Prioriäten 
rumschiebt. Damit sind praktisch unbegrenzt viele Interrupts und 
Instanzen möglich, solange der Stack reicht. Beim FIQ Handler sollte man 
keine Instanzen zulassen.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.