ESP32 Debugging – Setup and Troubleshooting

The ESP32 microcontroller supports in-circuit debugging, i.e. your code can be run on real hardware while stepping through it line by line, running to the next breakpoint, inspecting variables etc. These instructions help you set up debugging, both for Arduino and ESP-IDF projects.

Unfortunately, ESP32 debugging is unreliable as there are many things that can go wrong. Thus, this post also contains a long troubleshooting section.

Debugging Instructions

Hardware Setup

To debug an ESP32 microcontroller, a JTAG debug adapter is needed. The most common one is the ESP-Prog board from Espressif. Alternatives are FT2232HL and FT232H based adapters (see https://medium.com/@manuel.bl/low-cost-esp32-in-circuit-debugging-dbbee39e508b), Segger J-Link or any other debug adapter with JTAG support. These instructions assume you are using ESP-Prog.

Note: The ESP32-S3 microcontroller provides a built-in JTAG adapter, which is available if a USB connector is fitted, connected to the built-in USB peripheral and not used for something else. Such a setup is not covered here.

The ESP-Prog board is connected via USB to the computer running PlatformIO. The ESP32 development board must also be powered (independently from the ESP-Prog). So it is also connected via USB to the computer.

Finally, GND and the JTAG signals must be connected between the ESP-Prog board and the ESP32 development board according to this table:

JTAG signal ESP32 ESP32-S2 ESP32-S3
GND GND GND GND
TDO GPIO15 GPIO40 GPIO40
TDI GPIO12 GPIO41 GPIO41
TCK GPIO13 GPIO39 GPIO39
TMS GPIO14 GPIO42 GPIO42

Software Setup

Driver Configuration

Do not install any drivers

ESP-Prog does not require any drivers. In fact, installing drivers will likely cause additional problems. Some operating systems require driver configuration though:

Linux configuration

On most Linux systems, USB devices are mapped with read-only permissions by default. To allow PlatformIO (or rather OpenOCD) to work with ESP-Prog, add a new udev rule. Create a file at /etc/udev/rules.d/50-espprog.rules with the following content:

SUBSYSTEM=="usb", ATTR{idVendor}=="0403", ATTRS{idProduct}=="6010", MODE="0664", GROUP="plugdev"

Make sure your user is a member of the plugdev group. Then, unplug and reconnect the ESP-Prog board.

PlatformIO has more detailed instructions covering more USB devices at 99-platformio-udev.rules — PlatformIO latest documentation

macOS configuration

No special configuration is needed on the Mac. It should just work.

Windows configuration

By default, Windows will either not install any driver or the wrong one. For ESP32 debugging, interface 0 of ESP-Prog must be using the WinUSB driver.

In order to configure this driver, download a tool called Zadig and start it.

  • In the Options menu, check List All Devices
  • Select Dual RS232-HS (Interface 0) from the main drop down
  • Select WinUSB on the right-hand side of the green arrow (if not already selected)
  • Click Replace Driver

Project Configuration

In PlatformIO, only minimal additions to platformio.ini are needed:

  • debug_tool = esp-prog configures ESP-Prog as the debug adapter
  • debug_init_break = tbreak setup is recommended for Arduino projects so the debugger initially stops in the setup() function (instead of the main() function).
  • upload_protocol = esp-prog can optionally be used to upload the firmware via JTAG (instead of via the serial connection)

A complete platformio.ini file can look like this:

[env:esp32dev]
platform = espressif32
board = esp32dev
framework = arduino
upload_protocol = esp-prog
debug_tool = esp-prog
debug_init_break = tbreak setup

Note that the JTAG adapter does not use serial ports. Thus, no upload port and no debugging port must be specified.

Start Debugging

To run your software with the debugger:

  • Select the Debug icon on the left side to open the debugger view
  • Click the green triangle icon (Start Debugging) at the top to start your app with the debugger.
  • PlatformIO will recompile the software, upload it, run it and stop on the first line of setup()
  • You can then set additional breakpoints by clicking left of the line number. A red dot will appear.

Troubleshooting

Troubleshooting approach

As many components are involved, it is important to isolate the problem. In order to do that, it is recommended to:

  1. Use the simplest possible code like a Blink sketch
  2. Test the JTAG connection by uploading code (configure upload_protocol = esp-prog and click the upload icon in the status bar)
  3. Then test debugging (still using the Blink sketch)
  4. Finally, debug using the real code

Once a problem is encountered, dig deeper by analyzing the error messages. Most of them will appear in the Debug Console.

The error messages will indicate which part of the setup is causing the issue.

Isolating problem area

Most of the problems are either related to:

  • the communication between your computer and the JTAG adapter, or
  • the communication between the JTAG adapter and the ESP32 microcontroller.

As a rule of thumb: If the output in the terminal (for upload) or in the debug console (for debugging) contains an error message about “no device found” and then ends about 5 lines later, the communication between computer and JTAG adapter is not working. Otherwise, the problem is between JTAG adapter and ESP32.

Error: no device found
Error: unable to open ftdi device with vid 0403, pid 6010, description '*', serial '*' at bus location '*'
Error: no device found
Error: unable to open ftdi device with vid 0403, pid 6014, description '*', serial '*' at bus location '*'
** OpenOCD init failed **
shutdown command invoked

Note that the output can be confusing: OpenOCD tries several VID/PID combinations. If the first one fails but the second one works, the “no device found” message might appear even though it’s working fine.

Troubleshooting communication between JTAG adapter and ESP32

Most likely cause: wiring

By far the most likely cause of communication problems between JTAG adapter and ESP32 are wiring issues. Hardly any ESP32 board provides a JTAG connector. So several individual wires must be connected, opening the field for mistakes and bad connections.

A strong indication is the below error message (or a similar one with “all zeroes”):

Error: JTAG scan chain interrogation failed: all ones

Thus:

  • Check that the correct pins have been connected
  • Use short wires
  • Connect the wires directly, without going through a breadboard
  • If using Dupont wires: push the wire down, not just the black connector housing
  • Ensure with a multimeter that all connections are making good contact
  • Check and check again

Conflict with JTAG peripheral

In the ESP32 microcontroller, JTAG is a peripheral like UART or I2C. It is enabled by default after reset. But it can be disabled, or software and hardware conflicts can be created. Thus:

  • Ensure that the JTAG pins are not used for anything else than JTAG and are not wired to other hardware like buttons, LEDs, pull-down/pull-up resistors, SPI devices etc.
  • Do not configure the JTAG pins in any way, be it as a GPIO, UART, SPI etc.
  • Ensure your code is not using deep sleep as deep sleep disables the JTAG peripheral

Further things to check

  • Check that both the ESP32 board and the JTAG debug adapter are powered independently. The adapter cannot provide sufficient power to the ESP32.
  • Check that the ESP32 board and the JTAG adapter have their ground directly connected. It is important for JTAG signal quality. The indirect connection via USB ground or shield is not sufficient.

Troubleshooting communication between computer and JTAG adapter

Most likely cause: USB driver configuration

Communication between the computer and the JTAG adapter either works or doesn’t. There is hardly ever anything in-between. If PlatformIO/OpenOCD can talk to the adapter, it works; if not, the adapter won’t even be “found”.

The main cause are driver configuration issues and they are specific to each operating system.

Linux

If the communication fails, it usually a permission problem with the USB device, which in turn indicates an incorrect or incomplete udev rules setup. Try to follow the instructions at 99-platformio-udev.rules — PlatformIO latest documentation

Note: Two additional serial ports will appear if ESP-Prog is plugged in. For debugging, they are not used. They aren’t a problem either as long as they are not used concurrently.

macOS

The likely cause on macOS are outdated drivers that hold on to the ESP-Prog exclusively. Since macOS Mojave (released in 2019), all Macs come out-of-the-box with drivers for all relevant USB-to-serial chips (FTDI, WCH, SiliconLabs etc.). The drivers are provided by Apple and allow the same USB device to be used with other protocols if the serial port is not open. This non-exclusive access is required for ESP-Prog.

Drivers from the manufacturer can cause problems, are not needed and should be uninstalled. For the FTDI drivers, which could be in conflict with ESP-Prog, these commands can be used to remove the drivers (if they are listed with ls -l):

ls -l /Library/Extensions
sudo kextunload /Library/Extensions/FTDIUSBSerialDriver.kext/
sudo rm -r /Library/Extensions/FTDIUSBSerialDriver.kext/

Also check:

ls -l /System/Library/Extensions
sudo kextunload /System/Library/Extensions/FTDIUSBSerialDriver.kext/
sudo rm -r /System/Library/Extensions/FTDIUSBSerialDriver.kext/

Note: If you connect the ESP-Prog board, two additional serial ports will appear as /dev/cu.usb.... That is to be expected. But do not use the one with the lower number as it would interfere with the use for the JTAG protocol.

Windows

The USB driver architecture on Windows is quite rigid. It’s not possible to use both the general WinUSB driver and a serial port driver at the same time (for a given interface of a USB device). So interface 0 of ESP-Prog must be configured to use the WinUSB driver and the serial port driver must be deactivated.

Use Zadig to verify that Interface 0 of Dual RS232-HS is indeed using WinUSB. WinUSB must appear on the *left-hand side of the green arrow. If not, click Replace Driver again.

Configurations made with Zadig often only apply if the device is plugged in to a specific USB port. So always use the same port to avoid problems, and use Zadig when you change the port.

Further things to check

  • Make sure the USB cable to the ESP-Prog can transmit data (some cables are stripped down and are only suitable for power supply)
  • Try with a different USB port for ESP-Prog, in particular if you are using a USB hub
  • Check that the monitoring port is correct and that you didn’t accidentally specify one of the ESP-Prog ports.

Please use this topic for adding more learnings, tips and information about ESP32 debugging.

If you have a debugging issue, start a new topic instead.

I’ll add that if your flashing with JTAG that modules like ESP32-WROOM32 will need to be flashed via serial the first time as the AT firmware seems to block JTAG.

1 Like