PlatformIO JTAG Debug Adventure on ESP32
After I established that I can create a simple project for ESP32 using PlatformIO's modified version of ESP-IDF, I wanted to see if I can get PlatformIO's source code level debugging up and running. This is a luxury I lacked in my previous microcontroller development adventures. For Arduino and a few other bits of hardware, my only debugging tool was printing diagnostic text to serial terminal. For other hardware like PIC16F18345, I didn't even have that much. In theory my PICkit 3 had some limited debugging support but I never managed to get MPLAB X debugging running.
So the promise of debugging support on the ESP32 was pretty enticing. The debugger communication protocol is built on an industry standard called JTAG, and I need to have an adapter supported by OpenOCD to talk JTAG on behalf of PlatformIO. There are quite a few options, but looking over the list I realized I already had one of them: JTAG was also used to debug the Hackaday Supercon 2019 FPGA badge, and as a member of the pre-conference development team, I had bought a Segger J-Link. Since I was not doing any commercial work, I qualified for the licensing terms for the EDU edition. (Item #1369 from Adafruit.) So I went back to my box of Superconference stuff and dug out the J-Link I had bought.
The hardware connections were fairly straightforward, using some jumper wires to connect my J-Link to my ESP32 plugged in to a breadboard. Espressif has documentation on setting up JTAG debugging for an ESP32, and PlatformIO has their own page on the topic. I was sad to see that JTAG debugging would consume several of the already-precious pins that could otherwise be used for GPIO. Cross-referencing with the GPIO pin chart compiled by Random Nerd Tutorials, we see the price we have to pay for debugger support are three "OK with caveat" pins and one unencumbered "OK" pin.
The software connection side proved to be more challenging than the hardware. I didn't expect it to work right off the bat but I didn't expect to run into this many problems, either. My first obstacle was an error message LIBUSB_ERROR_NOT_SUPPORTED
. A little web searching found that this is the message if there are no drivers installed for the JTAG adapter. I went to Segger's web site to download and install their software suite, but that made no difference. Further web searching found that it actually wanted the more generic WinUSB driver, which I could install using the Zadig utility. Once installed, OpenOCD could communicate to J-Link, but J-Link could not talk to ESP32.
More reading of various forum posts followed, where I learned a common diagnostics step is to try connecting at a lower speed. This mitigates problems caused by poor connections, which is highly likely in my case as I'm connected using jumper wires and breadboards. I would not be a surprised if it couldn't sustain the 20MHz connection speed. Looking in the debug output, I see the applicable configuration file is boards/esp-wroom-32.cfg
and I found the adapter_khz
parameter to reduce the default speed down to 5MHz. But when I ran that configuration, I saw the output was set to 5MHz (yay!) and immediately overridden to 20MHz again (Boo!)
Open On-Chip Debugger v0.10.0-esp32-20201202 (2020-12-02-17:38)
Licensed under GNU GPL v2
For bug reports, read
http://openocd.org/doc/doxygen/bugs.html
WARNING: boards/esp-wroom-32.cfg is deprecated, and may be removed in a future release.
2
Info : FreeRTOS creation
adapter speed: 5000 kHz
adapter speed: 20000 kHz
Info : tcl server disabled
Info : telnet server disabled
Info : J-Link V10 compiled Jan 4 2021 16:15:44
Info : Hardware version: 10.10
Info : VTarget = 3.241 V
2
Info : Reduced speed from 20000 kHz to 15000 kHz (maximum).
Info : clock speed 20000 kHz
Info : JTAG tap: esp32.cpu0 tap/device found: 0x120034e5 (mfg: 0x272 (Tensilica), part: 0x2003, ver: 0x1)
Info : JTAG tap: esp32.cpu1 tap/device found: 0x120034e5 (mfg: 0x272 (Tensilica), part: 0x2003, ver: 0x1)
Info : accepting 'gdb' connection from pipe
Warn : No symbols for FreeRTOS!
Error: Target not examined yet
Error executing event gdb-attach on target esp32.cpu0:
Error: Target not halted
Error: auto_probe failed
Examining all the debugger configuration files I could find applicable to ESP32, I eventually found the culprit in the PlatformIO configuration file platform.py
for espressif32 platform. It would override speed to 20MHz no matter what the specified adapter_khz
value is. Editing that file directly on my computer, reducing to 5 MHz, allowed PlatformIO debugger to connect to my ESP32 running my code. I could set breakpoints! I could see variable values! I could walk the call stack! I could step through source code! This is amazing. I went back to PlatformIO to file a bug, but found that someone had already filed issue #459 and a fix is on its way.
One thing this debugger doesn't seem to do is to catch fatal issues. I had hoped it would automatically break into debugger if one is attached, but the chip just resets. I was mildly disappointed but I'm happy with what I already have. Besides, it looks like a fatal crash stack decoder is on its way as well. At the moment I'm content because this is far better than debugging from serial port. Or worse, doing it blind. I'm going to need good debugging tools as I start increasing project complexity.