Forum: Mikrocontroller und Digitale Elektronik Hilfe, Prozessor verschwindet im Dummy_Handler(void)


von Alex (haidanai)


Lesenswert?

Hallo,
ich habe einen SAME53, AT Studio7 und ICE-Debugger.
Das Problem ist, dass der Prozessor nach 3 Sek. im DummyHandler() 
landet.
Gibt es eine Möglichkeit zu erkennen, welcher Interrupt vorher ausgelöst 
wurde?

von Max H. (nilsp)


Lesenswert?

Klar, das steht im IPSR Register.

__get_IPSR ist Dein Freund.

von Alex (haidanai)


Lesenswert?

@ Max H.
Vielen Dank für die schnelle Hilfe.
Gibts irgendwo Doku zum Register?
Kann das der Debugger nicht lesen / anzeigen?

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Alex schrieb:
> Gibts irgendwo Doku zum Register

Ja, im "ARMv7-M Architecture Reference Manual" auf Seite 517.

Die Bedeutung der Zahl ist auf S. 525 abgebildet:
- Wert 0 bedeutet kein Interrupt aktiv
- Wert 1 bedeutet Reset wird gerade durchgeführt, kann eigentlich nie 
angezeigt werden
- Wert 2 bedeutet NMI Interrupt
- Wert 3 bedeutet HardFault
Usw.
- Werte ab 16 sind die "normalen" Interrupts, also die die von der 
Peripherie ausgelöst werden. Bei deinem Controller sind diese hier 
definiert, auf die dortige Angabe von "Line" musst du 16 aufaddieren:

https://onlinedocs.microchip.com/oxy/GUID-F5813793-E016-46F5-A9E2-718D8BCED496-en-US-14/GUID-DA8CB38A-18D7-4512-965B-BB439142B281.html

Heißt also, IPSR=16 ist PM - Power Manager Interrupt, IPSR=17 ist MCLK - 
Main Clock usw.

Alex schrieb:
> Kann das der Debugger nicht lesen / anzeigen?

Kann er grundsätzlich, weiß nicht wie Microchip das macht, eventuell 
zeigt der Debugger nur das xPSR an. Das IPSR sind die unteren 9 Bits vom 
xPSR. Schau dich mal in der Debugger-GUI um.

Notfalls schreibst du sowas hin:
1
void DummyHandler(void) {
2
  volatile uint32_t myIPSR = __get_IPSR ();
3
}

Dank "volatile" wird die Variable nicht wegoptimiert sodass du sie im 
Debugger auslesen kannst. Das Register ist kein "normales" 
Peripherieregister mit Speicheradresse, sondern ein Spezialregister des 
Prozessors, welches über die "mrs" Instruktion ausgelesen werden muss, 
was in der __get_IPSR Funktion passiert. Der Debugger hat aber einen 
direkten Zugriff darauf.

von Alex (haidanai)


Lesenswert?

OK, IPSR ist 3237.
Das wäre INT5?
Die KI meint das sei TC1-INT, wenn ich aber in die startupxxx schaue:
/*  5 OSCCTRL_DPLLLCKF_0, OSCCTRL_DPLLLCKR_0, OSCCTRL_DPLLLDRTO_0, 
OSCCTRL_DPLLLTO_0 */

Kommt mir alles komisch vor...
Hi-Hi-Hilfe...

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Alex schrieb:
> OK, IPSR ist 3237

Kann nicht sein, das ist keine 9bit-Zahl, das Maximum ist 511 😄

von Alex (haidanai)


Lesenswert?

ICSR meldet INT3 aktiv, also XOSCFAIL1 ???
Was ist da los, dass nach 3 Sek. der stabile Osc auf einmal ausfällt?

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Alex schrieb:
> ICSR meldet INT3 aktiv,

Die unteren 9 Bits vom ICSR haben den gleichen Inhalt von IPSR - aber 
was genau hast du jetzt ausgelesen? Welcher Wert genau steht drin?

Wenn 3 drin steht ist es wie gesagt der HardFault Handler. Das ist 
meistens (immer?) die Folge eines Software-Fehlers, also z.B. Zugriff 
auf ungültige Adressen/Pointer oder Ausführung einer ungültigen 
Instruktion. In den Registern CFSR, BFAR, MMFAR, HFSR finden sich mehr 
Informationen zum Fehler.

Nur wenn 19 drin steht ist es ein XOSCFAIL1 oder XOSCRDY1.

Übrigens: Meistens kannst du im Debugger einen Backtrace/Stacktrace 
sehen, also von wo aus die aktuelle Funktion aufgerufen wurde, von wo 
diese wiederum aufgerufen wurde usw. bis zur main().

Bei Exceptions/Interrupts, inklusive dem BusFault, gilt das auch, d.h. 
du kannst dort sehen welche Codestelle unterbrochen wurde als der 
Interrupt aufgetreten ist, außer der Speicher/Stack ist durch den Fehler 
zu sehr "zerwürfelt" worden. Aber Achtung: Manche HardFault-Interrupts 
treten erst ein paar Instruktionen nach dem eigentlichen Fehler auf, 
der Fehler kann also etwas über der angezeigten Codestelle sein.

Eventuell kannst du im Stacktrace also sofort sehen wo etwas schief 
gelaufen ist, also z.B. Zugriff auf ungültigen Pointer.

von Alex (haidanai)


Lesenswert?

@Niklas G.
Vielen,vielen Dank für deine ausführlichen Infos.

Im Debugger im Fenster "Prozessor Status" findet man "Interupt Program 
Status" (aka. IPSR!).
Hier wird der Wert 3 - Hard Fault - angezeigt.
Genau das hatte ich schon, dass bei einer &Var-Adressberechnung einfach
ein Nullpointer erzeugt wurde, weil die Variable nicht volatile gemacht 
wurde...

PS:
__get_IPSR liefert dagegen 0xCA5 ????

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Alex schrieb:
> Genau das hatte ich schon, dass bei einer &Var-Adressberechnung einfach
> ein Nullpointer erzeugt wurde, weil die Variable nicht volatile gemacht
> wurde...

Kann nicht sein, Variablen werden nicht wegoptimiert wenn man ihre 
Adresse anfordert, außer die Adresse wird nirgends genutzt.

Alex schrieb:
> __get_IPSR liefert dagegen 0xCA5 ????

Dann hat der Debugger wohl die Variable nicht richtig "erkannt", der 
Ausführungsschritt ist an der falschen Stelle oder es wurde was 
wegoptimiert.

Alex schrieb:
> Hier wird der Wert 3 - Hard Fault - angezeigt.

Dann also doch kein XOSCFAIL1/XOSCRDY1 😉

von Alex (haidanai)


Lesenswert?

Ja genau!
So, die Frage ist nun, wo er den Nullpointer benutzen wollte.
Im Debugger des Atmel Studios 7 habe ich nirgends ein Fenster mit dem 
Aufrufstack gefunden.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Alex schrieb:
> Im Debugger des Atmel Studios 7 habe ich nirgends ein Fenster mit dem
> Aufrufstack gefunden.

https://www.microchip.com/content/dam/mchp/documents/atmel-start/Atmel-Studio-7-User-Guide.pdf 
S. 187

Call Stack shows the hierarchical information of callers of the current 
method. By default, the Call Stack window displays the name of each 
function. To display Call Stack, Click the menu, Debug → Windows → Call 
Stack.

Den Call Stack sollte man eigentlich immer im Blick haben, der ist 
extrem wertvoll. Andere IDEs zeigen den standardmäßig immer an beim 
Debugger, keine Ahnung warum das bei Atmel Studio nicht so ist. Ist ja 
auch schon ziemlich alt...

: Bearbeitet durch User
von Alex (haidanai)


Lesenswert?

Vieelen Dank für deine Geduld!
Ich hätte die Tomaten vor meinen Augen zum Mittag essen sollen...
OK. Jetzt sagt er: .elf Line 548.
Äh, ja super. Sicher gibt es irgend einen Trick aus elf-Datei die 
Quellcode-Datei und Zeile zu finden?

Es müsste eine µC-Sherlock Holmess-Zusatzausbildung geben.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Alex schrieb:
> Jetzt sagt er: .elf Line 548

Zeig mal nen Screenshot.

Alex schrieb:
> Äh, ja super. Sicher gibt es irgend einen Trick aus elf-Datei die
> Quellcode-Datei und Zeile zu finden

Das macht der Debugger eigentlich vollautomatisch, wenn du mit 
Debuginformationen kompiliert hast, also -g an den Compiler.

Es kann aber sein dass aufgrund deines ursprünglichen Fehlers die 
Stack-Informationen kaputt sind und die vom Debugger gelesene Adresse 
ganz falsch ist, dann bringt die Debug Information nix.

Alex schrieb:
> Es müsste eine µC-Sherlock Holmess-Zusatzausbildung geben.

Hihi, ja Debuggen ist eine Kunst.

von Alex (haidanai)


Lesenswert?

...Grr.
Eine Zeile 548 ist "zufälliger Weise" die erste Zeile (IPSR_r= 
__get_IPSR; ) im Dummy-Handler! Na wer hätte das gedacht.
Ich hab noch Program Counter Trace Fenster gefunden.
Nur wie schaltet man das Recording ein?

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Alex schrieb:
> .Grr.
> Eine Zeile 548 ist "zufälliger Weise" die erste Zeile (IPSR_r=
> __get_IPSR; ) im Dummy-Handler!

Das ist halt der oberste Level vom Call Stack. Relevant sind die Level 
darunter.

Zeig doch bitte mal einen Screenshot direkt von dem Moment wo es im 
DummyHandler gelandet ist, mit folgendem sichtbar:
- Sourcecode
- Call Stack
- Register View (Debug → Windows → Register View). Lese hier bitte den 
Inhalt des Stack Pointer aus (SP oder MSP oder r13 genannt)
- Memory View (Debug → Windows → Memory view). Gebe den eben 
ausgelesenen Inhalt des Stack Pointer bei "Address" ein. Falls möglich 
stell beim Ausgabeformat 32bit hexadecimal unsigned o.ä. ein.

Lese die Register CFSR, BFAR, MMFAR, HFSR aus.

Sonst ist das alles Kaffeesatzlesen.

Alex schrieb:
> Nur wie schaltet man das Recording ein?

Siehe Kapitel 4.19 der zuvor verlinkten Anleitung.

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
Noch kein Account? Hier anmelden.