Exceptions und Fehlermeldungen eines ESP-Mikrocontroller entschlüsseln

Exceptions und Fehlermeldungen eines ESP-Mikrocontroller entschlüsseln

Immer wieder kommt aus vor, dass die Mikrocontroller einfach abstürzen und Fehlermeldungen und Exceptions werfen und im schlimmsten Falle auch in einer Boot-Schleife festhängen. Dann ist es sinnvoll die Ausgabe des Serial-Ports zu begutachten und den Exception-Stack zu analysieren. Dieser ist aber in der Regel recht kryptisch. In diesem Artikel erfährst du, wie du diesen Stack entschlüsseln und auswerten kannst und damit das Debugging vereinfachen kannst.

Warum rebootet mein Controller?

In der Regel handelt es sich dabei um unbehandelte Ausnahmen, die den Controller dazu zwingen, das Programm bzw. deinen Sketch neuzustarten. Das kann durch arithmetische Überläufe passieren oder durch andere Konditionen. Ein ähnliches Problem hatte ich im Artikel ESP8266 stürzt in nur einem WLAN ab und hängt in einer Bootschleife.

Der Exception-Stack

Wenn dein Controller wirklich einmal in eine solche Ausnahme läuft, wirst du sicherlich schon den „nichts sagenden“ Fehlerblock bemerkt haben. Dieser Block ist aber nicht so nichtssagend wie man vielleicht im ersten Moment denken mag.

Ein exemplarischer Block könnte wie folgt aussehen:

Decoding 10 results
Exception (28):
epc1=0x40219f8c epc2=0x00000000 epc3=0x00000000 excvaddr=0x00000000 depc=0x00000000
ctx: cont
sp: 3fff26e0 end: 3fff2960 offset: 01a0
>>>stack>>>
3fff2880: 00000000 3ffe8f0c 3fff1778 40219f8c
3fff2890: 00000000 00000000 00000000 00000000
3fff28a0: 00000000 00000000 00000000 00000000
3fff28b0: 00000000 3fff5f7c 0000003f 00000034
3fff28c0: 00000000 3fff3198 3fff1778 4021a0ed
3fff28d0: 00000000 00000000 00000000 4020ba68
3fff28e0: 00000000 00000000 3fff5e3c 4020bbcc
3fff28f0: 00000000 00000000 4021961c 4021b72c
3fff2900: 00000000 3fff14b8 3fff15cc 3fff5ea4
3fff2910: 0000000f 0000000a 3fff1778 4021197e
3fff2920: 00000000 3fff14b8 3fff1778 4021bb44
3fff2930: 00000000 00000000 00000000 feefeffe
3fff2940: 3fffdad0 00000000 3fff1924 40202ef8
3fff2950: feefeffe feefeffe 3fff1940 40205064
<<

Im ersten Moment ist er wirklich sehr kryptisch. Diesen kann man aber mit einem Tool und der Arduino-IDE entschlüsseln

Vorbereiten der Arduino-IDE

Damit das klappt, musst du die Arduino-IDE auf deinem Rechner installiert haben. Dieser Artikel richtet sich in erster Linie an Installationen auf einem Windows-Rechner. Das Verfahren sollte aber bei Linux bzw. macOS identisch sein.

Anmerkung: Ich selbst nutze generell nur Visual Studio Code, weil es der Arduino-IDE in einigen Punkten weit voraus ist (in welchen, erfährst du in meinem Artikel ESP-Mikrocontroller mit Visual Studio Code programmieren). Doch das ist der einzige Weg, den ich bisher raus gefunden habe, wie man die Exception-Stacks dekodieren kann.

Herunterladen und installieren

Damit du nun die Fehlermeldungen entschlüsseln kannst, benötigst du den „Arduino ESP8266/ESP32 Exception Stack Trace Decoder„. Diesen kannst du auf der Github-Seite des Projektes herunterladen.

Nun solltest du den Inhalt entpacken und nach %HOMEPATH%\Documents\Arduino\tools kopieren. Unter Umständen musst du den Order Tools erstellen.

Hast du die Arduino-IDE noch geöffnet, musst du diese nun einmal schließen und erneut öffnen. Damit steht dir nun der Exception Decoder zur Verfügung.

Entschlüsseln der Exceptions

Wenn du nun eine Exception erhälst, kannst du in der Arduino-IDE unter „Werkzeuge“ den Decoder auswählen:

Exception Decoder in Arduino-IDE

Mit einem Klick öffnet sich dann ein neues Fenster, in der du kompilierte Firmware suchen musst. Dabei handelt es sich um eine Datei mit der Endung .elf.

Auswählen der kompilierten Firmware

Da ich PlatformIO (wie du PlatformIO nutzen kannst erfährst du in meinem Artikel ESP-Mikrocontroller mit Visual Studio Code programmieren) nutze, liegen die kompilierten Firmwares in der Regel unter %HOMEPATH%\Documents\PlatformIO\Projects\[Projektname]\.pioenvs\[Board]\firmware.elf. Hast du eine Firmware ausgewählt, öffnet sich ein weiteres Fenster, in dem du deine Exception oben hinein kopieren kannst. Das Auswählen der Firmware ist zwingend erforderlich, da damit die Herkunft der Exception angezeigt wird.

Passt die Firmware nicht auf die Referenzen der Exceptions, dürfte die Entschlüsselung recht wenig Erkenntnisse über den Ursprung liefern:

Exception mit alter Firmware

Daher achte bitte da unbedingt auf eine aktuelle Firmware.

Wenn du alles richtig gemacht hast, solltest du dann auch die einzelnen Funktionsaufrufe im Stack sehen und kannst so recht schnell lokalisieren, wo es Fehler gibt oder Probleme gibt:

Decoding 10 results
0x40219f8c: checkRegistration() at ?? line ?
0x4021a0ed: registerDeviceAPI() at ?? line ?
0x4020ba68: UdpContext::UdpContext() at ?? line ?
0x4020bbcc: WiFiUDP::begin(unsigned short) at ?? line ?
0x4021961c: std::_Function_base::_Base_manager ::_M_manager(std::_Any_data&, std::_Function_base::_Base_manager const&, std::_Manager_operation) at main.cpp line ?
0x4021b72c: std::_Function_handler ::_M_invoke(std::_Any_data const&) at main.cpp line ?
0x4021197e: Ticker::start() at ?? line ?
0x4021bb44: setup at ?? line ?
0x40202ef8: loop_wrapper() at core_esp8266_main.cpp line ?
0x40205064: cont_norm at cont.o line ?

Da ich aktuell keine Exceptions mehr habe, kann ich dir leider keinen Screenshot von mir zeigen. Dennoch möchte ich dir einen Screenshot einer Entschlüsselung nicht vorenthalten:

Beispiel einer Exception und Entschlüsselung auf einem Mac (Bild aus dem Projekt von Github übernommen)

Ich hoffe, dass ich dir damit weiterhelfen konnte und du somit schnell die Ursachen von Problemen und „willkürlichen“ Reboots finden kannst.