Inhaltsverzeichnis
Zum Debuggen des ESP32 verwenden wir den JTAG Debugger ESP-Prog von Espressif. Eine Einführung zur Inbetriebnahme und zur Funktionsweise des JTAG Debuggers, findet ihr unter diesem Link.
Debuggen ist sehr wichtig für die professionelle Firmware-Entwicklung. Es ermöglicht uns während dem Ausführen von Code, Probleme zu erkennen, oder einfach zu prüfen ob der Code genau das macht was er soll.
Bei der Entwicklung von Anwendungen, z.B. mit C# in Visual Studio oder auch mit C in z.B. Eclipse, ist uns das Verfahren des Debuggens bekannt und wir verwenden es permanent um unseren Code zu Prüfen oder Fehler finden. Das Debuggen ist in diesen Entwicklungsumgebungen fest integriert und kann direkt, nach Installation verwendet werden.
Bei der Firmware-Entwicklung sieht das anders aus, da wir hier auf Hardware zugreifen müssen. Es gibt Boards von anderen Herstellern, bei denen die Hardware für das Debuggen auf dem Entwicklerboard mitgegeben wird, wie z.B. bei einigen Boards von Texas Instruments. Bei diesen Boards kann man auch direkt nach Installation der Entwicklungsumgebung mit dem Debuggen loslegen, ohne weitere Hardware und Software installieren und konfigurieren zu müssen.
Von Espressif gibt es auch ein Entwicklungsboard (und bestimmt auch weitere), das ESP-WROVER-KIT, welches den FT2232 Chip auf dem Board integriert hat, sowie diverse andere Peripherie, wie z.B. ein LCD Display, SD-Kartenleser etc. Ich habe das Board auch zuhause, aber nie verwendet. Es ist teuer, groß, empfindlich, schwer verfügbar und leider nicht für das Steckbrett geeignet. Wenn man die notwendige Peripherie zu einem günstigen ESP32 DevkitC dazukauft, ist es günstiger. Und falls doch ein Defekt auftreten sollte, können die einzelnen Teile einfach und günstig ausgetauscht werden.
Bei den Modulen von Espressif benötigen wir einen externen Hardware Debugger, den wir über bestimmte Pins mit dem Modul verbinden um auf die Hardware zu greifen zu können. Das ist aber unproblematisch und der JTAG Debugger ist auch relativ günstig, ab 15 € erhältlich. Ich arbeite – im Gegenatz zu den Modulen – nur mit den originalen Espressif ESP-Progs und kann daher nicht viel zu anderen Herstellern sagen. Die originalen kosten etwa 35 €, funktionieren aber tadellos. Ich hatte mir gleich zwei von denen zugelegt, falls einer kaputt gehen sollte, aber nach mehreren Jahren hat mich der Debugger noch nicht im Stich gelassen. Mit printf() kann man schon viel erreichen, aber wenn man einen kostengünstigen Debugger zur Hardware erwerben kann, würde ich das auf jeden Fall empfehlen. Das Einrichten ist auch in 15 min erledigt, wenn man nicht allzu tief in die Thematik einsteigen möchte.
Problematisch wird es nur, wenn alle Pins des ESP32 verwendet werden sollen, denn auch die Pins die für das Debuggen benötigen werden, können über Software für andere Zwecke verwendet werden. Aber auch hier gibt es Lösungen. Ich gehe auch mal davon aus, dass die wenigsten wirklich alle Pins verwenden werden. Es gibt auch die Möglichkeit I/O-Expander zu verwenden, was häufig auch wirklich Sinn macht.
Der JTAG-Debugger
Wir verwenden zum Debuggen einen JTAG-Debugger, den ESP-Prog von Espressif. Es gibt diverse Schnittstellen zum Debuggen von Hardware in der Industrie, auf die wir an dieser Stelle nicht eingehen werden.
JTAG ist ein Debug- und Test-Protokoll für Mikrocontroller, Prozessoren, FPGAs. Gerade beim ESP32 ist JTAG der professionelle Debug-Zugang. Damit kann man:
- Programme flashen (Firmware aufspielen),
- Debuggen (Breakpoints setzen, Variablen live ansehen, Step-by-Step ausführen),
- Pins und Register direkt ansprechen,
- Den Chip testen, auch wenn er schon auf einer Platine verlötet ist.
- Das Programm anhalten
- Zeilenweise durch deinen Code gehen
- Variablen live auf dem Chip beobachten
- Exceptions richtig analysieren
- Kein printf()-Spaghetti mehr nötig
JTAG steht für Joint Test Action Group – das ist der Name des Industriekonsortiums, das den Standard entwickelt hat.
Der JTAG-Debugger ESP-Prog, basiert auf dem FTDI-Chip FT2232. Der FT2232 fungiert als USB-zu-JTAG-Adapter. Über USB am PC wird das JTAG-Interface des ESP32 angesteuert, sodass man debuggen und flashen kann. Dabei wird der ESP32 über I/O-Pins per JTAG an den Debugger angeschlossen und der Debugger per USB an den PC.
Hinweis: Achtet darauf, dass die Jumper an der richtigen Stelle sind. In Abb. 1 ist das etwas schwer zu erkennen, aber die Jumper sind auf 3.3V gesteckt. Die Verbindung zum Board muss dann ebenfalls über 3.3V erfolgen, wie in Abb. 2 zusehen ist.

Abb. 1 – ESP-Prog JTAG Debugger

Abb. 2 – JTAG-Debugger anschließen – Teile lizenziert unter CC-BY-SA 3.0
https://fritzing.org
Dabei bedeuten die Farben
- 3V3 (rot), Pin1 (ESP-Prog) -> auf 3.3V (ESP32 DeviKit)
- TMS (grün), Pin2 (ESP-Prog) -> auf Pin14 (ESP32 DeviKit)
- GND (schwarz), Pin3 (ESP-Prog) -> auf GND (ESP32 DeviKit)
- TCK (weiß), Pin4 (ESP-Prog) -> auf Pin13 (ESP32 DeviKit)
- TDO (organge), Pin6 (ESP-Prog) -> auf Pin15 (ESP32 DeviKit)
- TDI (gelb), Pin8 (ESP-Prog) -> auf Pin12 (ESP32 DeviKit)
Genauere Daten und die Pin-Nummerierung, gibt es auf der entsprechenden Webseite zum ESP-Prog.
Die Pinbelegung zum ESP32 DevKit in Abb. 6.

Abb. 3 – ESP-Prog und ESP32 DevKit auf Steckbrett
JTAG-Debugger konfigurieren
Zur Konfiguration des JTAG-Debuggers, benötigen wir den GNU-Debugger (GDB) und OpenOCD. Für die Inbetriebnahme noch zusätzlich den Treiber für den FT2232HL Chip Driver. Aber, alles der Reihe nach.

Abb. 4 – JTAG Debugging Diagramm (Bildquelle: Espressif Systems)
Bis auf auf den FTDI Treiber wurde uns von Espressif schon alles während der Installation des ESP-IDF in der Kommandozeile mitgeliefert. Wir müssen es gleich nur konfigurieren. Den Treiber für den FT2232 könnt ihr unter folgenden Link herunter laden -> Zadig USB Driver.
Steckt den ESP-Prog an einen USB Port und verwendet diesen auch weiterhin für den ESP-Prog, da die Installation des Treibers nur für diesen einen Port erfolgt. Wenn ihr den Port wechseln wollt, müsst ihr die Installation für den Port wiederholen.
Zadig starten und auf „List All Devices“ unter „Options“ klicken.

Abb. 5 – Zadig Konfiguration
Dual RS232-HS (Interface 0) auswählen und „Replace Driver“ bestätigen.

Abb. 6 – Zadig Konfiguration
Nach erfolgreicher Installation kann man im Gerätemanager folgendes sehen. Das ESP32 DevKit wird in weiterhin als CP210x an entsprechender COM Schnittstelle erkannt. Entfernt den Debugger nochmal aus dem USB Port und steckt ihn nochmal rein, damit er sicher erkannt wird.
Der ESP-Prog Debugger hat eine serielle- und eine JTAG-Schnittstelle. Die Serielle wird hier bei den COM-Schnittstellen angezeigt und die JTAG-Schittstelle unter USB-Geräten als Duad RS232-HS.

Abb. 7 – Gerätemanager nach Installation von Zadig
Konfiguration des ESP-Prog in VS Code
Jetzt müssen wir nur prüfen ob OpenOCD bereits installiert wurde und auch startet (Was mit der VS Code Extension geschehen sein sollte), und den GNU Debugger (GDB) konfigurieren.
OpenOCD
Mit der Konfiguration in VS Code können wir beginnen, wenn alle vorherigen Schritte erfolgreich waren. Zum Starten von OpenOCD ist es erforderlich, dass der Debugger wie oben beschrieben an den ESP angeschlossen ist. Der ESP-Prog muss an dem USB-Port angeschlossen sein für den Zadig installiert wurde, und das DevKit muss auch an einem USB Port – wie schon gehabt – angeschlossen sein.
Jetzt starten wir VS Code und öffnen das ESP-IDF Terminal mit dem kleinen Button unten in der Statusleiste.
Das ist wichtig, denn mit der Windows Eingabeaufforderung funktioniert das nicht. Zum Starten von OpenOCD, also dem Debugger, haben wir aktuell noch keinen Button, wir müssen ihn über das Terminal starten. Dafür geben wir openocd -f board/esp32-wrover-kit-3.3v.cfg in das Terminal ein. Ist alles in Ordnung und ist der Debugger richtig an das DevKit angeschlossen, sollte die Ausgabe in Abb. 9 zu sehen sein.
openocd -f board/esp32-wrover-kit-3.3v.cfg
Ist der Debugger nicht richtig angeschlossen, die vorherigen Schritte mit der Installation wurden fehlerfrei durchgeführt, dann seht ihr sowas wie in Abb. 10. Prüft alle eure Verbindungen zum DevKit. Sind Kabel richtig angeschlossen? Ist irgendwo ein Dreher?
Seid ihr nicht im ESP-IDF Terminal, sondern in der Windows Eingabeaufforderung, dann seht ihr die Meldung in Abb. 11. Rechts könnt ihr immer sehen wo ihr euch gerade befindet. In Abb. 11 ist rechts cmd markiert. Markiert ESP-IDF Terminal oder startet es und gebt alles nochmal ein.
Ihr könnt vorher auch openocd –version eingeben, ob OpenOCD bei euch korrekt installiert ist. Wenn ja, dann sollte die Versionsnummer folgen, wie in Abb. 8.
openocd --version
Näheres findet ihr auf der Espressif Seite JTAG Debugging.

Abb. 9 – OpenOCD erfolgreich gestartet

Abb. 10 – Debugger nicht richtig angeschlossen

Abb. 11 – Eingabe von openocd in Windows Eingabeaufforderung
GNU Debugger (GDB)
Der GNU Debugger wird von VS Code verwendet um mit OpenOCD zu kommunizieren. Er wurde ebenfalls schon mit der Installation von VS Code mitgeliefert, muss aber noch einwenig angepasst werden.
Geht dafür links auf das „Debug“ Symbol und klickt auf „Run and Debug“ (Abb. 12).
Oben erscheint eine Auswahl, dort wählt ihr C++ (GDB/LLDB) aus (Abb. 13).
Jetzt wird eine neue launch.json erstellt die ihr in eurem Projekt wieder findet (Abb. 14). Die Datei ist bei mir leer, da ich sie für die Repräsentation gelöscht und neu erstellt habe. Bei euch müsste da schon etwas an Code drin stehen. Das interessiert uns aber nicht, da wir den Code eh löschen und ändern.
Im folgenden seht ihr eine launch.json für OpenOCD Debugging des ESP32 unter VS Code. Basierend auf verschiedenen ESP32/OpenOCD/GDB Konfigurationen, die öffentlich verfügbar sind. Auf die genaue Bedeutung dieser Konfiguration werde ich hier nicht weiter eingehen. Kopiert diesen Code so in eure launch.json. Wir müssen aber noch die Pfade anpassen.
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "ESP32 OpenOCD",
"type": "cppdbg",
"request": "launch",
"cwd": "${workspaceFolder}/build",
"program": "${workspaceFolder}/build/ErstesProjekt.elf",
"miDebuggerPath": "C:/Espressif/tools/xtensa-esp-elf-gdb/16.2_20250324/xtensa-esp-elf-gdb/bin/xtensa-esp32-elf-gdb.exe",
"setupCommands": [
{"text": "target remote 127.0.0.1:3333"},
{"text": "set remote hardware-watchpoint-limit 2"},
{"text": "monitor reset halt"},
{"text": "flushregs"}
]
}
]
}
Codebeispiel – launch.json Konfiguration

Abb. 15 – launch.json in VS Code konfiguriert
„${workspace}“ ist ein Platzhalter von VS Code und enthält den Pfad zu eurem Arbeitsordner. Unter Visual Studio Code und ESP-IDF Extension und „Neues Projekt erstellen“, hatte ich als Projektname „ErstesProjekt“ gewählt. Unter „build“ gibt es eine Datei mir der Endung „.elf“. Diese trägt den Namen des Projektes, also des Arbeitsordners, in meinem Fall „ErstesProjekt.elf“. Da müsst ihr euren Projektnamen eintragen und bei dem Parameter „program“, wie in Abb. 15 eintragen.
Der Parameter „miDebuggerPath“ benötigt den absoluten Pfad zur Datei „xtensa-esp32-elf-gdb.exe“. Wo genau der sich befindet müsst ihr suchen. Der Pfad in der Abb. 15, ist eine gute Richtilinie.
Fürs Erste sind wir fertig und können direkt mit dem Debuggen loslegen. Vorher testen wir noch ob alles funktioniert. Dafür geben wir im ESP-IDF Terminal in VS Code wieder folgenden Befehl ein.
openocd -f board/esp32-wrover-kit-3.3v.cfg
Es sollte die Ausgabe aus Abb. 9 erscheinen.
Debuggen
Damit wir beim Debuggen auch eine interne Variable beobachten können, habe ich den Beispielcode etwas erweitert.
/*
Blinkende LED
*/
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "sdkconfig.h"
#define LED1 5 // LED an Pin 2 anschließen.
void Blink() // LED blinkt jede Sekunde
{
gpio_set_level(LED1, 1);
vTaskDelay(100 / portTICK_PERIOD_MS);
gpio_set_level(LED1, 0);
vTaskDelay(100 / portTICK_PERIOD_MS);
}
void app_main(void) // Hier startet das Programm
{
gpio_set_direction(LED1, GPIO_MODE_OUTPUT); // Pin 2 als Ausgang definieren
int counter = 0;
while(1)
{ Blink();
counter++;
if (counter >= 1000)
counter = 0;
}
}
Beispielcode – erweitert
Hier habe ich in der main die Integer-Variable int counter = 0 deklariert, mit 0 initalisiert und in der Endlosschleife einfach um 1 inkrementiert. Wenn counter = 1000, wird er wieder auf 0 gesetzt. Falls wir keine Variable einfügen würden, könnten wir beim Debuggen einen Breakpoint z.B. bei gpio_set_level(LED1, 1); setzen und beobachten, wie die LED beim Durchklicken an und aus geht, da das Programm jetzt steht und wartet. Mit einer internen Variable können wir aber auch schon eine Variable beobachten.
Wenn der OpenOCD Debugger bereits läuft, also über das ESP-IDF Terminal gestartet wurde, können wir in VS Code jetzt Debuggen, indem wir links auf das Debug Symbol klicken und oben links den grünen Pfeil anklicken. Es dauert einen Moment, dann sollten die Debugging-Tasten oben in der Mitte erscheinen. Am besten erstellen wir noch zwei Breakpoints in der Zeile int counter = 0 und gpio_set_level(LED1, 1). Dafür gehen wir mit der Maus einfach links neben die Zeilennummer. Dort erscheint ein kleiner roter Punkt, auf den wir drauf klicken.
Der Gelbe Pfeil um den roten Punkt zeigt, an welcher Stelle wir uns beim Debuggen gerade befinden.
Am besten klicken wir jetzt mit F10, oder oben in der Mitte bei den Debug-Tasten, auf das zweite Symbol von links, der Punkt mit dem runden Pfeil. Dann überspringt VS Code die Funktionen, die sich hinter z.B. gpio_set_level(); befinden, denn diese interessiert und gar nicht. Wir bleiben in unserem Fenster und können Schritt für Schritt, langsam durch die Zeilen klicken. Wenn alles funktioniert, wird die LED jetzt immer an gehen, wenn wir beim oberen Breakpoint ankommen, wie in Abb. 16, und ausgehen, wenn wir ein paar mal weiter klicken. Der counter sollte jedes Mal, wenn wir in die main springen um 1 inkrementiert werden. Die Variable erscheint oben links unter Locals, wenn wir in die Zeile kommen, in der der Breakpoint gesetzt ist (Abb. 17).
Wichtig ist, Breakpoints zu setzen, sonst passiert nichts und das Programm läuft einfach weiter. Man kann aber nicht überall Breakpoints setzen, wie z.B. nicht in Zeilen wo nur geschweifte Klammern o.ä. sind.
Zum Stoppen klickt ihr oben auf das rote Viereck.
In VS Code können natürlich weitere Eingenschaften konfiguriert werden, wie z.B. das Starten von OpenOCB beim Start von VS Code. Dann entfällt das Eintippen von openocd -f board/esp32-wrover-kit-3.3v.cfg in das ESP-IDF Terminal. Da kommen wir evtl. noch später zu. Aber so können wir schon vernünftig Debuggen. Allerdings ist das Geschmackssache, denn nicht jeder möchte jedes Mal Debuggen wenn er VS Code startet. Aber wenn der ESP-Prog nicht angeschlossen ist, erscheinen dann Fehlermeldung beim automatischen Start von OpenOCD.
Mit dem Debugger ist es auch möglich, die Firmware direkt über den Debugger in den ESP32 zu laden und somit auf das USB Kabel am ESP32 zu verzichten. Das wird in einem anderen Beitrag behandelt.
Hinweis: Falls es beim Flashen zu Fehlmermeldungen kommen sollte, wie z.B. in Abb. 18, dann liegt das höchwahrscheinlich am Debugger der am ESP32 angeschlossen ist. Der ESP32 benötigt beim Booten, an bestimmten Pins (Strapping Pins) bestimmte Pegel, Low oder High. Diese Pegel werden vom Debugger aber gestört. Wir müssen nicht alle Anschlüsse des Debuggers beim Debuggen entfernen, es genügt die 3.3V Verbindung und das USB-Kabel zu trennen, und nach dem Flashen beide Kabel wieder anzustecken.
Das bewirkt, dass der Debugger beim Flashen nicht mehr mit Spannung versorgt wird.






