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?
Eine eigene Frage?
Dieser Thread ist über 14 Jahre alt.
Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.