Liebe Community,
ich habe ein Problem (so fangen wohl die meisten Forumbeiträge an):
Seit einiger Zeit habe ich meinen Mikrocontroller und die Umgebung
einigermaßen im Griff - erfolgreich PWM Signale erzeugt, LCD angesteuert
und LEDs blinken lassen (gesteuert über Warteschleifen).
Jetzt benötige ich zum Einlesen von PWM Signalen Interruptroutinen.
Das klappt auch soweit schon mal, allerdings bricht das Programm nach
Abarbeiten der Interruptroutine ab und kehrt nicht ins Hauptprogramm
zurück.
Tüftel nun seit vielen Wochen an dem Problem rum und bekomm es einfach
nicht hin.
Kann mir jemand einen Tipp geben, woran es mit eröhter
Wahrscheinlichkeit liegen könnte?
- Makefile
- Irgendwelche Speicherinitialisierung
Ich muss dazu sagen, dass ich die Entwicklungsumgebung nicht komplett
durchblicke, habe sie aber eigenständig zum Laufen gebracht... auch viel
in den Datenblättern gelesen, aber bekomme das Problem nicht in den
Griff :-( SEUFZ
Habe ein AT91SAM7A3 Entwicklerboard, benutze Eclipse, USBProg und ein
vorgefertigtes Makefile, das bisher immer funktioniert hat.
Gerne lade ich auch Files und Code hoch, wollte euch nur im ersten
Schritt nicht zu-spammen, weil ich ja keine Ahnung habe, in welcher Ecke
das Problem stecken könnte.
Vielen Dank im Voraus für alle Tips und Tricks!
Gruß
Tobias
Tobias schrieb:> allerdings bricht das Programm nach Abarbeiten der Interruptroutine ab
Was genau meinst du damit? Dass überhaupt nichts mehr ausgeführt wird?
> und kehrt nicht ins Hauptprogramm zurück.
Wurde das Hauptprogramm denn vorher überhaupt ausgeführt, oder war die
CPU gerade schlafen?
Habe das Programm gerade nochmals ausführen lassen:
In meiner main-Routine habe ich ein zeitgesteuertes Blinkmuster in einer
Endlosschleife.
In der Interrupt-Routine (ausgelöst durch ein High-Signal an einem Pin)
habe ich ein anderes Blink-Muster.
Sobald ich also den besagten Pin auf high setze, läuft die
Interrupt-Routine. Und zwar dauernd wiederholt.
Bis vor ein paar Tagen blieb das Programm noch stehen, wenn ich den Pin
wieder auf low gesetzt habe, nun läuft die Interrupt-Routine dauernd
weiter (und ich weiß leider nicht mehr, an was ich alles rumgedreht habe
:-/).
Tobias M. schrieb:> Bis vor ein paar Tagen blieb das Programm noch stehen, wenn ich den Pin> wieder auf low gesetzt habe, nun läuft die Interrupt-Routine dauernd> weiter (und ich weiß leider nicht mehr, an was ich alles rumgedreht habe> :-/).
Das ist meistens ein Hinweis darauf, das der Interrupt Handler das
auslösende Bit im Peripherial nicht zurück setzt (hier wohl GPIO oder
externer Interrupt). Dadurch wird der Handler beim Verlassen sofort
erneut aufgerufen.
@Jim Meba:
Danke für deinen Hinweis. Habe einen extern getriggerten Interrupt (wenn
Pin auf high gesetzt wird).
Ich werde heute Abend nochmal im Datenblatt unter Peripherals
nachblättern.
Kannst du noch etwas spezifischerres zum Zurücksetzen des auslösenden
Bits sagen? Das könnte evtl. meine Blätterdauer gewaltig reduzieren -
für mich als Voll-Anfänger :-/
Tobias schrieb:> Kann mir jemand einen Tipp geben, woran es mit eröhter> Wahrscheinlichkeit liegen könnte?> - Makefile> - Irgendwelche Speicherinitialisierung> Ich muss dazu sagen, dass ich die Entwicklungsumgebung nicht komplett> durchblicke
Also, da gibt es eine ganze Reihe von möglichen Fehlerursachen,
insbesondere weil es sich um einen ARM7TDMI handelt:
1. der Interrupt-Stack ist falsch oder garnicht aufgesetzt. Ort:
Startupcode. Behebung: Lernbetty runterladen, den dortigen Startupcode
verstehend lesen oder an deinen µC angepaßt verwenden. Bedenke, daß der
ARM7TDMI mehrere verschiedene Modi nebst getrennten Stacks UND separate
Stackpointer kennt.
2. dein Gnu-Compiler ist faul, sowas gab's schon mal. Abhilfe: die
Bastlerversion vom Keil runterladen und damit erstmal soweit zu Potte
kommen, bis daß du firm genug bist. Dann kannst du immer noch zum
Gnu-Compiler wechseln.
3. falscher Modus überhaupt. Der GCC kennt keine Pragmas, um
Interrupthandler (die im ARM-Modus ausgeführt werden müssen)
entsprechend zu kennzeichnen. Hat Bedeutung, wenn du den Rest im
THUMB-Modus compilieren läßt.
4. (siehe deine Quelle) du hast vergessen, die ISR als solche kenntlich
zu machen. Also das GCC-Äquivalent von __irq in die Kopfzeile des
Handlers reinschreiben. (den genauen Wortlaut merke ICH nir gewiß nicht,
also auch dazu ein Blick in die Lernbetty, dort ist das ganze nämlich
auch vorgeturnt)
W.S.
Tobias schrieb:> Kannst du noch etwas spezifischerres zum Zurücksetzen des auslösenden> Bits sagen? Das könnte evtl. meine Blätterdauer gewaltig reduzieren -
Schau mal in der Registerbeschreibung des betreffenden Peripheriegerätes
das den Interrupt auslöst (jedes Peripheriegerät sollte sein eigenes
Kapitel haben und in jedem findest Du einen Abschnitt mit der kompletten
Beschreibung all der Register dieses Peripheriegerätes mit jedem
einzelnen Bit).
Dann schau mal ob Du sowas wie ein Statusregister siehst oder eventuell
auch nur ein paar verstreute Bits in anderen Registern die "Flag" oder
den Buchstaben "F" an verdächtiger Stelle im Namen tragen, lies die
Beschreibung dieses Bits. Meist steht dann dort sowas wie "Das Bit wird
gesetzt wenn dieser oder jener Zustand aufgetreten ist, ist es wird
zurückgesetzt indem eine 1 in das Bit geschrieben wird" oder auch je
nach Gerät "es wird zurückgesetzt wenn das Datenregister gelesen wird"
oder ähnliches.
Die Interrupts die das Peripheriegerät auslösen kann sind fast immer an
solche Flags gekoppelt, wenn der zugehörige Interrupt enabled ist und
das Flag gesetzt wird löst der Interrupt aus und dann musst Du das tun
was nötig ist im dieses Flag wieder zu löschen.
Wenn das Gerät mehrere verschiedene Interrupts auslösen kann die alle in
der selben Interruptroutine münden dann fragst Du dort zunächst ab
welches der in Frage kommenden Flags gesetzt ist (dann weißt Du was die
Ursache war, z,B. Welcher Pin es war der den PinChange ausgelöst hat,
oder bei anderen Geräten ob es ankommende Daten, ein Fehler, ein
Überlauf, oder was auch immer war, jedes davon hat sein eigenes Flag und
jedes will auf eine ganz bestimmte Weise zurückgesetzt werden, wie das
genau geht steht für jedes Flag in seiner jeweiligen Beschreibung)
> Das könnte evtl. meine Blätterdauer gewaltig reduzieren
Du wirst nicht umhinkommen das in ein paar ruhigen Stunden (Tagen,
Wochen) mal ausgiebig zu studieren, daran führt mittelfristig kein Weg
vorbei.
@Bernd und W.S.:
1000 Dank für die Mühe, die ihr euch gemacht habt! Damit werde ich
weiter kommen.
Lernbetty zieh ich mir auf jeden fall mal rein :)
Ich hoffe noch, dass es mit dem von Bernd beschriebenen Thema
zusammenhängt. Die Schritte von W.S. übersteigen mindestens teilweise
meinen Horizont.
Ich melde mich auf jeden Fall, ob ich's hinkrieg, bzw. falls nicht frag
ich sicher nochmal nach :)
Selbstverständlich nicht vor Lernbetty und ausgiebigem Testen ;)
Viele Grüße und Danke nochmal
Tobias
Das Problem ist das die ARMs Tail-chaining unterstützen. Heißt tritt
ein weiterer oder auch der selbe Interrupt auf wird der hinten dran
gehängt.
Von einer höheren Priorität kann dieser auch unterbrochen werden.
Flags von PIOs müssen meist zurückgesetzt werden in dem man in ein
entsprechenden Register schreibt. Macht man das nicht wird die Routine
wieder aufgerufen :) So lange bis sie von einen höheren unterbrochen
wird. Oder in das clear Register geschrieben wurde.
Am Ende einer Interrupt Routine muss also das clear Register beschrieben
werden oder das Interrupt Register am Anfang ausgelesen werden womit es
zurückgesetzt wird.
Was wo wie nötig ist steht in der Referenz.
Das dass Vector table nicht stimmt ist unwahrscheinlich da der Pointer
von der Routine ja gefunden wird.