Ich programmiere grade ein Eval-Board von Atmel mit dem SAM7X256. Als Entwicklungsumgebung nehme ich Yagarto und ich nutze als Basis den Beispielcode von Yagarto für das Board. Ausgänge schalten und Eingänge abfragen klappt, auch die Interruptregister auslesen klappt, aber eben nicht das direkte ausführen einer Funktion, wenn der Interrupt auslöst. (Bisher frage ich quasi ständig ab, ob eine Änderung in dem Interruptregister steht, das ist im späteren Betrieb aber nicht mehr möglich) Ich habe mir das Datenblatt durchgelesen und soweit auch verstanden. Also Interruptquelle muss generell aktiviert werden, das ist soweit passiert. Nun müssen auch die Adressen in Form einer Vector Tabelle angegeben werden. Mir ist klar warum, nur wie das ganze im Quelltext umgesetzt wird (also Syntax etc) fehlt mir. Habe bisher keine Erfahrung mit Microcontrollern, mir würde schon ein Bispielprogramm helfen. Bisher habe ich schon von ramfunc und attribute interrupt gelesen, aber wo und wie das ganze dann geschrieben werden muss, verstehe ich nicht nicht ganz. Vielleicht kann mir hier ja jemand helfen.
Christian S. schrieb: > > Nun müssen auch die Adressen in Form einer Vector Tabelle angegeben > werden. Der Controller verfügt über einen Interrupt Controller (AIC). Es düfte nützlich sein, sich zuerst mit dem Interrupt-Konzept der ARM7TDMI-Kerns zu informieren (z.B. im Infocenter von arm.com) und dann im Manual des AT91SAM7 zu lesen, wie der AIC damit verbunden ist. Der "Vector-Tabelle" bezieht sich erstmal auf den Kern (Reset, IRQ, FIQ, SWI etc.). Der AIC bietet die Möglichkeit, Peripheral Interrups direkt anzuspringen, die Adresse der Serviceroutine wird bei Setup in AIC Regsiter geschrieben. > Mir ist klar warum, nur wie das ganze im Quelltext umgesetzt > wird (also Syntax etc) fehlt mir. Es gibt im Grunde drei Möglichkeiten: (a) Die ISR wird mit einem speziellen Attribut für Interrupts versehen (u.a. IRQ). Damit fügt der Compiler Maschinencode ein, der für ISRs erforderlich ist (z.B. Rücksprungadresse anpassen). Ist analog zu den __IRQ Erweiterungen der Compiler von ARM und IAR. Dieser Ansatz hat bei älteren GNU-Compilerversionen nur unter bestimmten Bedingungen funktioniert. Mag sich inzwischen gebessert haben. (b) Die ISR wird mit einem naked Attribut versehen, die den Compiler davon abhält die für normale Funktionen erforderlichen Codes einzufügen. Über Inline-Assembler werden dann "von Hand" die Instruktionen für eine ISR eingefügt. Quasi ein Workaround zu den in (a) erläuterten Problemen. Spröde. Nach Möglichkeit nicht so machen. (c) Eine zentrale Verteilerfunktion wird bei jedem Core-IRQ aufgerufen, bereitet den Spung in einen Verarbeitungsroutine vor, fragt den AIC nach der Routinenadresse, springt zur Routine und räumt hinterher auf. Die Behandlungsroutine selbst kann dann normaler C-Code sein (kein Attribut, kein Inline-Assembler). Da es eine solche "Verteilerfunktion" fertig im Beispielcode von Atmel gibt (atmel.com, AT91SAM7S/X-EK Seite) und da diese Funktion noch ein paar Extras bietet, kann man sie für den Anfang verwenden, bis man die erste Timer-Interrupt-Anwendung in Betrieb hat. Nachteil dieses Ansatzes: ein paar Prozessorzyklen Überhang. > Habe bisher keine Erfahrung mit Microcontrollern, mir würde schon ein > Bispielprogramm helfen. Welche Suchmaschine wirft bei der Suche nach AT91SAM7 example code nichts aus? Die Controller sind zwar nicht mehr brandaktuell aber Beispielcode gibt es weiterhin an vielen Stellen. Ansonsten mit dem Code von Atmel anfangen (den gibt es für verschieden Toolchains inkl. GNU). Damit sind die Chancen größer, Unterstützung zu finden. Nicht vom Umfang erschrecken lassen, es sind auch ein paar einfache Beispiele dabei. Wer es genau wissen will, schaut durch den Startup-Code (ist ARM-Assembler) und versucht das "warum" hinter jeder Anweisung zu verstehen - zumindest grob. > Bisher habe ich schon von ramfunc und attribute interrupt gelesen, aber > wo und wie das ganze dann geschrieben werden muss, verstehe ich nicht > nicht ganz. Vielleicht kann mir hier ja jemand helfen. "ramfunc" hat mit Interruptbehandlung direkt nichts zu tun, sondern dient zur Laufzeitoptimierung. Ist für den nächsten Lernabschnitt. Lesenswert besonders weil schon für AT91SAM7 (ob S oder X spielt bei den Grundlagen erstmal keine Rolle): http://www.state-machine.com/resources/articles.php -> Building bare-metal ARM Systems with GNU.
Danke erstmal, der Artikel der EE-Times sieht ganz interessant aus, das werde ich morgen mal genauer lesen. Ich bevorzuge eigentlich Version a, die notwendige Syntax habe ich schon herausgefunden. Wie bekomme ich denn raus, wo die Funktionen abgespeichert werden? (Linkerscript nehme ich an, fiel mir grad erst ein und ich komme erst morgen wieder an meine Files) In den Registern des AIC gibt es ja auch die Abteilung, wo eine passende Vector Adresse eingetragen werden muss, die müsste ja entsprechend gewählt werden. Im Interrupt Pending Register wird der Interrupt schon angezeigt (von PIO_A). Wird dann direkt die abgespeicherte Vector Adresse angesprungen oder muss noch etwas beachtet werden? Beispielcode habe ich bisher für Variante B gefunden, inline Assembler fällt bei mir aber flach bin eher VBA und Delphi gewohnt. Sind die AIC Controller so identisch? Beim LPC2468 sieht ja sehr viel anders aus bei den Periphals. (den hatte ich mir erst angesehen, aber wegen falscher Linker und Lowlevel Files nicht in Betrieb nehmen können...)
Habe mich nun noch ein wenig damit befasst. Eine Verteilerfunktion ist eigentlich das einfachste, aber ein Beispielprogramm von Atmel habe ich damit nicht gefunden bisher. Die anderen Beispielprogramme von Atmel habe ich mir auch angesehen, habe aber nichts zum Thema Interrupt gefunden (zumindest nichts, was ich verstanden habe, muss ich ehrlich sagen). Ich bekomme ja problemlos die Interruptquellen in das Interrupt Pending Register geschrieben, eine Adresse habe ich auch eingetragen als Vectoradresse. (Habe ich einfach durch das ausführen der Funktion herausgefunden, da stand dann eine Adresse bei, aber das sollte doch auch irgendwie einfacher gehen oder?) Beim Anzeigen lassen der aktuellen Interruptfunktion bekomme ich aber nur 0 zurückgeliefert. Kann ich irgendwie prüfen, ob überhaupt die Interrupts im Prozessor aktiviert sind? Ich gehe momentan schon davon aus, dass es daran auch schon hapert. Im Startupfile steht:
1 | IRQHandler: |
2 | b IRQHandler |
ruft das automatisch ein Funktion IRQHandler auf, sofern vorhanden? Oder was macht das? (also wenn ein Interrupt an den Prozessor gesendet wird und die aktiviert sind) Im Linkerfile ist auch eine IRQ-Stacksize angegeben, was macht die? Ich habe dazu leider nicht wirklich Informationen gefunden. Und was mache ich dann, wenn ich Timer-Interrupts habe? Ich muss alle 10 oder 20ms (muss ich noch festlegen) CAN-Botschaften senden... Wenn ich dich richtig verstehe funktioniert das dann nicht richtig oder ist das dann nur bei extrem kurzen Timerzeiten, wo es Probleme gibt?
Nun wird's kurios. Ich habe nur was am CAN-Controller geändert und auf einmal lösen die Interrupts aus, werden aber leider immer wieder durchlaufen (obwohl ich den Befehl zum Beenden des Interrupts gesetzt habe). Bzw. lösen die Interrupts schon wieder nicht mehr aus, habe alle Befehle, die ich hinzugefügt oder weggelassen habe überprüft, egal was ich ändere, mittlerweile bleiben die Befehle einfach nur im Pending Register. Komischerweise wird auch manchmal das SVR Register gefüllt (also das, wo beim entsprechenden Interrupt hingesprungen werden soll im AIC), allerding nicht immer und immer nur beim 1. Mal auslesen des Interrupts. Danach wird das Register wieder geleert und nicht wieder beschrieben und es wird auch nicht an die Adresse gesprungen, sondern einfach ignoriert... Ich bin mit meinem Latein ein wenig am Ende... Habe auch eine Funktion geschrieben, die im Startup File genannt wird (den IRQ_Handler), aber da ist er eben auch nur zum Anfang hingesprungen, wo er tatsächlich ausgelöst hat und nicht wieder rauskam. Mittlerweile leider nicht mehr. Aber was kann so ein Verhalten hervorrufen?
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.