Hallo,
ich arbeite mich gerade mit einem STM32F446 in die
Microcontrollerprogrammierung in C ein. Aktuell schreibe ich einfache
Interrupts, was auch funktioniert, bin hierbei aber auf ein, für mich,
unerwartetes Verhalten gestoßen.
An Port A hängt eine LED, an C Pin 15 ein Taster und B Pin 2 soll über
Kabel den Input auf GND ziehen. Durch C15 und B2 soll jeweils ein
Interrupt ausgelöst werden und die LED zum blinken bringen, was auch
funktioniert.
Allerdings springt das Programm in den Default Handler(Infinite Loop)
nach Init von Port C wenn:
1.
1
GPIO_Init(&gpioa_handle_5);
2
GPIO_Init(&gpioc_handle_13);
3
GPIO_Init(&gpiob_handle_2);
Die Reihenfolge der Initalisierung von Port B und C vertauscht wird.
2.
Init von Port B gar nicht verwendet wird, aber der struct vorher
trotzdem für Port B drin ist.
Wird die Iinitalisierung des structs auskommentiert, funktioniert das
Programm alleine mit Port C wieder wie erwartet.
Kann mir jemand erklären, wieso zum einen die Reihenfolge eine Rolle zu
spielen scheint, in der die Funktion GPIO_Init jeweils für Port B und C
ausgeführt werden und zum anderen, wieso das nicht initialisieren von
gpiob_handle_2 wieder dazu führt, dass für den Port C das Programm nicht
abstürzt?
Hi Jannik,
ohne eine wirklich brauchbare Antwort parat zu haben, kann ich dir
sagen, dass ich vor einiger Zeit ähnliche Symptome in meinem STM-based
SDR radio hatte. Irgendwann hing sich das Programm auf, was genauer
betrachtet einfach nur das Anspringen des Default Interrupt Handlers
(mit siener endless loop) war. Letztlich hatte ich es versäumt, den
korrekten (meinen eigenen) Interrupt Handler in die Int Table
einzutragen. Das hatte ich durch das Lesen der Listings für die
entsprechenden Module rausgefunden, dort stand noch der Default Handler
drinne.
Ansonsten denke ich (noch) nicht unbedingt, dass es wirklich und
wahrhaftig nur von der Reihenfolge der GPIO_Init-Routinen abhängt (lasse
mich aber gerne vom Gegenteil überzeugen), vielleicht ist es einfach nur
ein Timing Issue, bedingt durch das zitierte Kabel an dem einen Eingang,
das evtl. nicht auf einem definierten Pegel liegt, sondern in der Luft
hängt.
Suche auf jeden Fall mal weiter in Richtung "korrekt aufgesetzte
Interrupt Handler". Viel Erfolg!
Neee,die Routinen-Bezeichnung im Debugger (Hard fault Handler) ist hier
etwas irreführend. Tatsächlich sind eben alle nicht benutzten
Interrupt-Vektoren mit einem Sprung zu diesem Default Handler versehen,
um ein kontrolliertes verhalten zu erreichen. Es ist aber m.E. sehr
wahrscheinlich einfach nur ein nicht initialisierter, jedoch
getriggerter Interrupt.
Im Interrupt Control and State Register oder HardFault Status Register
sollte das lesbar sein. Die Adresse des Auslösens existiert dann
entweder auf dem Stack oder in einem seperaten Register.
Nochmal neee: die Int-Vektoren werden per Jump genutzt und nicht per
Call. Also steht nirgendwo eine Return-Adresse. Es bleibt einzig das
auslösende Int Flag. Aber natürlich ist das gesetzt/aktiv, hilft aber
nicht wirklich dabei, herauszufinden, warum nicht der eigene Int
Handler, sondern der Default Int Handler genommen wird.
Man hört gar nichts mehr vom OP? Hat er das Problem evtl. schon in
Eigenregie gelöst und lässt uns hier sinnlos weiter philosophieren? :-)
Wenn ja: lieber OP: dann teile doch Deinen Fehler - und die
Lösungsfindung - hier mit, damit evtl. auch Andere davon profitieren
können!
Erstmal rausfinden was auslöste.
Die Adresse bei der Unterbrochen wurde steht im Stack (autom. stacking
R0-R3,R12,LR,PC,PSR).
Welcher Interrupt auslöste steht im IPSR. Im LR steht ein Spezialwert
fürs unstacking.
Beim Hardfault gibt es dies Adresse auch auf dem Stack und der Rest
steht im NVIC im HFSR.
Thilo schrieb:> Nochmal neee: die Int-Vektoren werden per Jump genutzt und nicht> per Call. Also steht nirgendwo eine Return-Adresse.
Quatsch - wie sollte der Controller nach dem Interrupt denn dann da
weitermachen, wo er vor dem Interrupt war? Natürlich gibt's irgendwo
eine Return-Adresse.
Nop schrieb:> Thilo schrieb:>> Nochmal neee: die Int-Vektoren werden per Jump genutzt und nicht>> per Call. Also steht nirgendwo eine Return-Adresse.>> Quatsch - wie sollte der Controller nach dem Interrupt denn dann da> weitermachen, wo er vor dem Interrupt war? Natürlich gibt's irgendwo> eine Return-Adresse.
Und die liegt im 8x4er Packet auf dem Stack.
Ich vermute mal weil er (Thilo) im LR nix brauchbares finden konnte.
Das wäre dann eine ARMv4.
Ich empfehle mal die Bibel schlechthin
"The Definitive Guide to ARM Cortex-M3 and Cortex-M4 Processors"
von Joseph Yiu
Vielen Dank vorab für die vielen Beiträge :)
@Thilo,
Zumindest kann durch das reine Wechseln der Reihenfolge dieses Verhalten
getriggert oder auch behoben werden. Der Pin ist auf wird durch Pull Up
auf High gezogen. Habe es auch mit anderen Pins, sollte also auch nicht
an einen Defekt liegen.
@ Dennis. H
Also zumindest kein gewollter. Beim debuggen wird
GPIO_Init(&gpioc_handle_2); noch ausgeführt, aber im nächsten Step
landet man in der Infinite Loop.
Von Dennis H:
"Erstmal rausfinden was auslöste.
Die Adresse bei der Unterbrochen wurde steht im Stack (autom. stacking
R0-R3,R12,LR,PC,PSR).
Welcher Interrupt auslöste steht im IPSR. Im LR steht ein Spezialwert
fürs unstacking.
Beim Hardfault gibt es dies Adresse auch auf dem Stack und der Rest
steht im NVIC im HFSR."
Das werde ich mir mal ansehen, kann durch das debuggen, wie oben
brereits erwähnt nicht erkennen, durch was der Interrupt ausgelöst wird.
"Sind die GPIO-Einheiten alle an ?
"GPIO_PeriClockControl"
Ja, da ist alles in Ordnung. B und C funktionieren ja unabhängig
voneinander. Der Fall für B,C auch, wenn zuerst b initialisiert wird und
dann c. Die Frage ist was z.B. das wechseln der Reihenfolge verändern
könnte.