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
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
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
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
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?
1 | //init the Advanced Interrupt Controller
|
2 | *AT91C_AIC_IECR = 0x00000002; //enable peripheral ir |
3 | AT91C_AIC_SMR[1] = 0x00000021; //prio of periph-ir, pos. edge triggered |
4 | AT91C_AIC_SVR[1] = (AT91_REG) ISR_periph1; //set adress to branch to if PIT IR occurs |
5 | |
6 | //init of the Periodic Internal Timer
|
7 | *AT91C_PITC_PIMR = ( 0x000FFFFF & ( TIMER_PARA_MicroCycle * (TIMER_PARA_SysClock / (16 * 1000) ) ) ) ; //set cycle of timer |
8 | *AT91C_PITC_PIMR |= 0x03000000; //enable the timer and the corresponding IR |
9 | |
10 | __irq void ISR_periph1 (void) //executed every time a peripheral IR occurs |
11 | {
|
12 | //tempvar = *AT91C_AIC_IVR; //sobald ich diesen Regzugriff mache, wird die nächste Codezeile nichtmehr ausgeführt -> warum bloß?
|
13 | |
14 | SET_PWR_LED(ON); |
15 | |
16 | if ( *AT91C_PITC_PISR ) //IR caused by Periodic Interval Timer ? |
17 | {
|
18 | uscount += TIMER_PARA_MicroCycle; |
19 | |
20 | if (uscount == 1000) //when 1000us (=1ms) passed |
21 | {
|
22 | uscount = 0; //reset mscounter |
23 | task_1ms(); |
24 | }
|
25 | |
26 | *AT91C_AIC_ICCR = 0x00000002; //clear the IR-Bit |
27 | tempvar = *AT91C_PITC_PIVR; //reading PIVR resets the timer ir |
28 | |
29 | }
|
30 | |
31 | *AT91C_AIC_EOICR = 0xFFFFFFFF; //end of IR |
32 | }
|
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.
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
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
> 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...
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...
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
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/ARM-Interrupt.pdf
... 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?
> 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...
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
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.
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.
Man kann das auch brav bei ARM nachlesen: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka11008.html 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.
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
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
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.
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
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=/com.arm.doc.faqs/ka11008.html Ich stehe auf Anfrage auch gerne zur Unterstützung zur Verfügung. Tom
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.
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.