Hallo Forum, ich bin STM32 Einsteiger und erstelle mein erstes Projekt. Zuvor habe ich alle nötigen Module portiert und einige öffentliche Quellen genutzt die ich bereits in der AVR Welt eingesetzt habe (Scheduler, Tastenentprellung, IRMP, u8g2 Grafik Display Lib etc.). Entwicklungsumgebung ist Visual GDB in aktueller Version. HAL, kein RTOS. Im Projektierungsverlauf führt der STM32 nun sporadisch einen Reset aus. Ich habe auch bereits einen Code Block ausfindig gemacht. Wenn dieser auskommentiert wird, tritt der Fehler nicht auf. Der Code Block für sich ist aber lauffähig und nicht allein ursächlich für den Reset. Der Fehler tritt dann irgendwann später (mal nach 10 Sekunden, mal nach 3 Minuten) auf. Letztendlich lösche ich nach abgelaufener Zeit einmalig das Display. Diese Funktion wird ein dutzend mal an anderen Programmstellen aufgerufen. Ich habe bereits eine Hard Fault Funktion hinzugefügt und einen break Point gesetzt. Der BP wird allerdings vorm Reset nicht angesprungen. Nach google und Forumssuche ist mir nicht klar, wie man hier am besten systematisch vorgeht. Ich habe bereits viele Stunden damit verbracht auszuschließen und komme nicht weiter. Ich wäre euch für Unterstütz sehr dankbar. Gruß Stefan
Stack zu klein? In der *.ld einfach mal vergrößern und probieren.
Aufbau der Hardware ist vernünftig? Stromversorgung stabil? Eventuell Watchdog aktiviert? Ich finds geschickter bei der Fehlersuche im Hardfault-Handler oder auch bei fehlgeschlagenen asserts direkt einen "bkpt" Befehl auszuführen, das verschwendet keine Debug-Resourcen und schlägt immer an.
Nach einem Reset steht im RCC_CSR Register was den Reset ausgelöst hat, also ob der von draußen kam oder vom Watchdog oder wegen Brown Out oder... Siehe RM0394 Kapitel Reset and clock control (RCC).
Hi, danke für die Tipps! Den Stack werde ich gleich mal vergrößern. Der Hardfault Handler wird vor dem Reset lt. gesetztem Break Point nicht aufgerufen. Die Stromversorgung ist stabil. Der Controller geht nicht in den Reset wenn der entsprechende Codeblock auskommentiert ist. Fas Problem ist, dass die St Link Schnittstelle auch abschmiert. So kann ich kein entsprechendes Register lesen. Wenn ich dann eine neue Debug Session starte wird das Programm erneut übertragen und der Controller gezielt resettet. Dann ist die die Reset Quelle Soft Reset. Watchdog und Brown Out nutze ich nicht. Stefan
Zum Codeteil der verantwortlich für den Reset ist: Aufruf 1x pro Sekunde
1 | void display_OffTimer(void) |
2 | {
|
3 | if (state.displayTime > 0) |
4 | {
|
5 | state.displayTime--; |
6 | |
7 | if ((parameter.display.offTime != 0) && (state.displayTime == 0)) |
8 | {
|
9 | SET(state.flags, 4); |
10 | }
|
11 | }
|
12 | schedule_Remove(display_OffTimer); |
13 | schedule_Add(display_OffTimer, SECONDS(1)); |
14 | }
|
Das flag mit der (testweise) Magic Number wird in der Hauptschleife ausgewertet.
1 | while(1) |
2 | {
|
3 | |
4 | if (READ(state.flags, 4)) |
5 | {
|
6 | CLR(state.flags, 4); |
7 | display_Off(&display, READ(parameter.display.flags, DISP_FLAG_OFFSYMBOL)); |
8 | |
9 | }
|
10 | |
11 | }
|
- state ist volatile - parameter.display.offTime ist ein Parameter der nach Init aus einem EEPROM gelesen und in einem User Menu editiert und ins EEPROM geschrieben wird - wenn parameter.display.offTime den Wert 0 hat bzw. wenn das Flag nicht geschreiben wird oder Display_Off nicht aufgerufen wird, kommt es nicht zum Reset. Vereinfachte Funktion (normalerweise mit Auswertung value, allerdings besteht der Fehler auch so)
1 | void display_Off(u8g2_t *display, uint8_t value) |
2 | {
|
3 | |
4 | |
5 | u8g2_ClearDisplay(display); |
6 | |
7 | }
|
technikus schrieb: > Der Hardfault Handler wird vor dem Reset lt. gesetztem Break Point nicht > aufgerufen. Und der break Point war auf der allerersten Instruktion im Disassembly? Ich frage das weil ein komplexer Handler gerne mal versucht was auf den Stack zu pushen. Was schief geht wenn SP ungültig ist -> Lockup. Lockup ist in vielen µC Designs mit Reset verkoppelt. technikus schrieb: > Wenn ich dann eine neue Debug Session starte wird das Programm erneut > übertragen Dieses Verhalten sollte man abstellen können. Ist bei Eclipse ein Haken in der Debug Konfiguration. technikus schrieb: > Display_Off nicht aufgerufen wird Mach da mal einen Haltepunkt rein und schau Dir den display Pointer genau an. Wenn der auf den flaschen Speicherbereich zeigt, kann der durchaus den Stack durcheinander bringen. Was zu o.g. Problem mit Fault und kaputten Stack Pointer führt...
Folgendes probiert. Dabugging Option umgestellt damit das Programm nicht erneut übertragen wird und folgende Funktion aufgerufen:
1 | uint8_t get_system_reset_cause(void) |
2 | {
|
3 | uint8_t reset_cause = 0; |
4 | if (__HAL_RCC_GET_FLAG(RCC_FLAG_LPWRRST)) |
5 | {
|
6 | reset_cause = 1;//"LOW_POWER_RESET"; |
7 | }
|
8 | else if (__HAL_RCC_GET_FLAG(RCC_FLAG_WWDGRST)) |
9 | {
|
10 | reset_cause = 2;//"WINDOW_WATCHDOG_RESET"; |
11 | }
|
12 | else if (__HAL_RCC_GET_FLAG(RCC_FLAG_IWDGRST)) |
13 | {
|
14 | reset_cause = 3;//"INDEPENDENT_WATCHDOG_RESET"; |
15 | }
|
16 | else if (__HAL_RCC_GET_FLAG(RCC_FLAG_SFTRST)) |
17 | {
|
18 | reset_cause = 4;//"SOFTWARE_RESET"; // This reset is induced by calling the ARM CMSIS `NVIC_SystemReset()` function! |
19 | }
|
20 | // else if (__HAL_RCC_GET_FLAG(RCC_FLAG_PORTRST))
|
21 | // {
|
22 | // RCC_FLAG_
|
23 | // reset_cause = "POWER-ON_RESET (POR) / POWER-DOWN_RESET (PDR)";
|
24 | // }
|
25 | else if(__HAL_RCC_GET_FLAG(RCC_FLAG_PINRST)) |
26 | {
|
27 | reset_cause = 5;//"EXTERNAL_RESET_PIN_RESET"; |
28 | }
|
29 | // Needs to come *after* checking the `RCC_FLAG_PORRST` flag in order to ensure first that the reset cause is
|
30 | // NOT a POR/PDR reset. See note below.
|
31 | else if(__HAL_RCC_GET_FLAG(RCC_FLAG_BORRST)) |
32 | {
|
33 | reset_cause = 6;//"BROWNOUT_RESET (BOR)"; |
34 | }
|
35 | else
|
36 | {
|
37 | reset_cause = 7;// "UNKNOWN"; |
38 | }
|
39 | // Clear all the reset flags or else they will remain set during future resets until system power is fully removed.
|
40 | __HAL_RCC_CLEAR_RESET_FLAGS(); |
41 | |
42 | return reset_cause; |
43 | }
|
Nach einem Reset den Debugger angeworfen und die Funktion hat eine 5 zurück gegeben (RCC_FLAG_PINRST). Das verwirrt mich jetzt total. Daraufhin habe ich Datenblatt und Layout überprüft. Ich habe am NRST lediglich einen 100nF gegen Masse. Keine Lötbrücke, kein Layoutfehler. Kann jemand etwas mit der Erkenntnis anfangen?
technikus schrieb:1 | else if(__HAL_RCC_GET_FLAG(RCC_FLAG_PINRST)) |
2 | {
|
3 | reset_cause = 5;//"EXTERNAL_RESET_PIN_RESET"; |
4 | } |
5 | // Needs to come *after* checking the `RCC_FLAG_PORRST` flag in order |
6 | to ensure first that the reset cause is |
7 | // NOT a POR/PDR reset. See note below. |
8 | else if(__HAL_RCC_GET_FLAG(RCC_FLAG_BORRST)) |
9 | {
|
10 | reset_cause = 6;//"BROWNOUT_RESET (BOR)"; |
Demnach könnte es doch auch ein BOR gewesen sein? Oder sogar ein POR? Weil das Flag nicht getestet wird? Von wem stammt eigentlich der Kommentar "Needs..."? Am einfachsten fände ich es, das komplette Register als 32 Bit Wort auszugeben.
@Bauform B: Du hast recht! Ich habe einfach blind einen Codeschnipsel aus dem Netz genommen. Das BOR FLAG ist nach einem Reset auch gesetzt...
Tatsächlich hatte die Brwon Out Detection zugeschlagen. Ich habe eine Power Bank verwendet um den Probeaufbau zu programmieren. Bei Abschalten des Displays, hat die Gesamtschaltung so wenig Strom gebraucht, das die Power Bank abgeschaltet hat. Nach einem Controller Reset ist wieder genug Strom geflossen damit die Power Bank wieder versorgt hat. Jetzt, am Netzteil, läuft alles wie gewünscht. Danke für die Unterstützung, erst recht für den Hinweis alle Flags bei der Fehlersuche zu berücksichtigen. Gruß Stefan
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.
