|
| 1 | +--- |
| 2 | +title: "Debugging with ESP-IDF VS Code extension: Part 1" |
| 3 | +date: 2025-05-20 |
| 4 | +showAuthor: false |
| 5 | +authors: |
| 6 | + - francesco-bez |
| 7 | +tags: |
| 8 | + - Debugging |
| 9 | + - ESP-IDF |
| 10 | + - ESP32-C3 |
| 11 | + - ESP32-S3 |
| 12 | +summary: "This two-part guide shows how to set up VS Code with the ESP-IDF extension to debug Espressif boards using JTAG. This first part covers the debugging process, hardware setup and connections, and starting the openOCD server." |
| 13 | +--- |
| 14 | + |
| 15 | +## Introduction |
| 16 | + |
| 17 | +Debugging is a critical part of the development process, especially when working with embedded systems. It allows developers to identify and fix errors, ensuring that the firmware interacts correctly with the peripherals and the external hardware. While there are several ways to debug code, the most powerful method is to use a _debugger_, which provides real-time insights into how the code runs on the hardware. |
| 18 | + |
| 19 | +Many developers start with basic debugging, often using `printf` statements to track program flow and check variable values. While helpful, this method has major limits. Printf-based debugging forces you to change the code and recompile it each time you test something new. In contrast, debuggers let you step through code, inspect memory, and set breakpoints without touching the source. |
| 20 | + |
| 21 | +In this guide, we'll walk through the steps necessary to set up debugging for Espressif devices using [Visual Studio Code](https://code.visualstudio.com/) (VS Code) and the [ESP-IDF Extension](https://docs.espressif.com/projects/vscode-esp-idf-extension/en/latest/). The ESP-IDF Extension manages the whole toolchain, but knowing the tools it uses, like `openOCD` and `gdb`, gives you more control and helps you fix problems that may arise along the way. |
| 22 | + |
| 23 | +This guide will show you the two available hardware paths to debug Espressif devices (JTAG pins and USB pins) and the interacting tools which make debugging possible. |
| 24 | + |
| 25 | +This article has two parts. |
| 26 | +In this first part, we will explain the debugging process, describe the tools, set up the hardware, and start the `openOCD` server. |
| 27 | +In the second part, we will run `gdb` and explore its options for debugging the code. |
| 28 | + |
| 29 | +In the rest of the article, we’ll use “Espressif device" to refer to both the modules and SoCs, since the steps below apply to both. |
| 30 | + |
| 31 | +__Prerequisites__ |
| 32 | + |
| 33 | +Before you begin, make sure you have the following: |
| 34 | + |
| 35 | +- An Espressif development board based on one of the following series: **ESP32-C3**, **ESP32-C6**, or **ESP32-S3** |
| 36 | + |
| 37 | +- Either an _expendable_ USB cable (that supports data transfer) or the [**ESP-PROG**](https://docs.espressif.com/projects/esp-iot-solution/en/latest/hw-reference/ESP-Prog_guide.html#introduction-to-the-esp-prog-board) debug probe |
| 38 | + |
| 39 | +- Visual Studio Code (VS Code) |
| 40 | + _If not installed, follow the [installation instructions](https://code.visualstudio.com/docs/setup/windows)_ |
| 41 | + |
| 42 | +- ESP-IDF Extension for VS Code |
| 43 | + _If not installed, follow the [setup instructions](https://github.com/espressif/vscode-esp-idf-extension?tab=readme-ov-file#esp-idf-extension-for-vs-code)_ |
| 44 | + |
| 45 | + - Ability to use ESP-IDF extension for VS Code to build, flash, and monitor a simple example project, such as `blink` or `hello_world` |
| 46 | + _If you're unsure, check [Create an ESP-IDF Project](https://docs.espressif.com/projects/vscode-esp-idf-extension/en/latest/startproject.html#create-an-esp-idf-project)_ |
| 47 | + |
| 48 | + |
| 49 | +## Debugging process |
| 50 | + |
| 51 | +The debugging process requires several tools working together. You interact with the IDE, which manages the compiler, the debugger and the flasher (software) tool. The flasher tool communicates to a (hardware) programmer which can upload the firmware to the flash memory of the microcontroller and manage JTAG interactions. |
| 52 | + |
| 53 | +{{< alert icon="circle-info" cardColor="#b3e0f2" iconColor="#04a5e5">}} |
| 54 | +With USB enabled devices, the programmer/debugger is built into the SoC (but remains external to the workstation). |
| 55 | +{{< /alert >}} |
| 56 | + |
| 57 | +You can find an overview of the debugging process in Fig. 1. |
| 58 | + |
| 59 | +<!--  --> |
| 60 | +{{< figure |
| 61 | +default=true |
| 62 | +src="img/debuggingWorkflow.webp" |
| 63 | +height=200 |
| 64 | +caption="Fig.1 - Debugging Workflow" |
| 65 | + >}} |
| 66 | + |
| 67 | +We will use VSCode IDE with `ESP-IDF Extension`, which manages the following tools for both flashing and debugging: |
| 68 | + |
| 69 | +* __Compiling and flashing__: The extension uses [`idf.py`](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/tools/idf-py.html#idf-frontend-idf-py), which is a CLI front-end tool which takes care of the compilation ([CMake/ninja](https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-guides/build-system.html#using-the-build-system)) and the flashing ([esptool.py](https://github.com/espressif/esptool?tab=readme-ov-file#esptoolpy)) processes. |
| 70 | +* __Debugging__: The extension connects seamlessly with `esp-gdb` which derives from the venerable [GNU Debugger](https://en.wikipedia.org/wiki/GNU_Debugger) (gdb). The `esp-gdb` interfaces with a forked version of `openOCD` called [`openocd-esp32`](https://github.com/espressif/openocd-esp32) which supports newly released SoC series sooner than the original `openOCD`. We will use the terms `openocd-esp32` and `openOCD` interchangeably. The same goes for `esp-gdb` and `gdb`. |
| 71 | + |
| 72 | +{{< alert icon="circle-info" cardColor="#b3e0f2" iconColor="#04a5e5">}} |
| 73 | +With older ESP-IDF plugin versions, you needed to install openOCD separately. Now it comes directly with ESP-IDF plugin. |
| 74 | +{{< /alert >}} |
| 75 | + |
| 76 | +__Testing openOCD availability__ |
| 77 | + |
| 78 | +Let's check if your version of VS Code extension comes with `openOCD` installed. |
| 79 | + |
| 80 | +{{< alert iconColor="#df8e1d" cardColor="#edcea3">}} |
| 81 | +Most commands in VSCode are executed through the _Command Palette_, which you can open by pressing `CTRL+SHIFT+P` (or `CMD+SHIFT+P` if you're on mac-os). In this guide, commands to enter in the _Command Palette_ are marked with the symbol __`>`__ . |
| 82 | +{{< /alert >}} |
| 83 | + |
| 84 | +* Lauch VS Code. |
| 85 | +* Open a new Terminal. |
| 86 | + > `ESP-IDF: Open ESP-IDF-Terminal` |
| 87 | +* In the terminal type |
| 88 | + ```bash |
| 89 | + openocd --version |
| 90 | + ``` |
| 91 | + |
| 92 | +You should read something like |
| 93 | +```bash |
| 94 | +Open On-Chip Debugger v0.12.0-esp32-20241016 (2024-10-16-14:27) |
| 95 | +``` |
| 96 | + |
| 97 | +Now that we ensured we're using an updated IDE, let's set up the hardware. |
| 98 | + |
| 99 | +## Hardware for debugging |
| 100 | + |
| 101 | +Espressif devices usually require separate hardware for flashing and debugging via JTAG. By default, you flash Espressif devices using the serial port (UART0) which does not support JTAG. |
| 102 | +Note that most of Espressif development boards do __not__ include a JTAG probe. A notable exception is the [ESP32-WROVER-KIT](https://docs.espressif.com/projects/esp-dev-kits/en/latest/esp32/esp-wrover-kit/user_guide.html#functionality-overview). They only offer a USB-to-UART connection for flashing and monitoring. |
| 103 | + |
| 104 | +To debug an development board—or any Espressif-based board—you have two options: |
| 105 | + |
| 106 | +1. JTAG over JTAG pins (with a JTAG probe) -- briefly described below for completeness |
| 107 | +2. JTAG over USB pins -- used in the rest of the article |
| 108 | + |
| 109 | + |
| 110 | +All Espressif devices support the first option. The second option works only with USB-equipped devices, such as the ESP32-S3 or ESP32-C3. Although both options are shown, in the rest of the article, we will use the JTAG over USB pins option. |
| 111 | + |
| 112 | +### JTAG over JTAG pins |
| 113 | + |
| 114 | +To debug using the JTAG pins, you first need a JTAG probe. Espressif offers a probe called [ESP-PROG](https://docs.espressif.com/projects/esp-iot-solution/en/latest/hw-reference/ESP-Prog_guide.html), whose JTAG connector is shown in Fig.2. |
| 115 | + |
| 116 | +<!--  --> |
| 117 | + |
| 118 | +{{< figure |
| 119 | +default=true |
| 120 | +src="img/esp_prog_jtag.webp" |
| 121 | +width=350 |
| 122 | +caption="Fig.2 - ESP-PROG JTAG connector" |
| 123 | +>}} |
| 124 | +
|
| 125 | +To enable JTAG programming, connect the four pins `TMS`, `TCK`, `TDO`, `TDI` of the JTAG probe to the corresponding Espressif module pins. |
| 126 | + |
| 127 | +In the table below, you can find the pins for three common modules. |
| 128 | + |
| 129 | +|JTAG|ESP-PROG|ESP32-C3-MINI-1|ESP32-S3-WROOM-1|ESP32-C6-WROOM-1 |
| 130 | +|---|---|---|---|---| |
| 131 | +|__TMS__|ESP_TMS|GPIO 4|GPIO 42|GPIO 4| |
| 132 | +|__TCK__|ESP_TCK|GPIO 6|GPIO 39|GPIO 6| |
| 133 | +|__TDO__|ESP_TDO|GPIO 7|GPIO 40|GPIO 7| |
| 134 | +|__TDI__|ESP_TDI|GPIO 5|GPIO 41|GPIO 5| |
| 135 | + |
| 136 | +For other modules, consult the _Pin Description_ section of the datasheet and look for `MTMS`, `MTCK`, `MTDO`, `MTDI` pins. |
| 137 | + |
| 138 | +The JTAG peripheral is generally enabled by default and can be [disabled in production](https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/security/security.html#debug-interfaces) and for security reasons using the appropriate eFuses (`EFUSE_DISABLE_JTAG` or `EFUSE_HARD_DIS_JTAG` depending on the SoC series). |
| 139 | + |
| 140 | +While the ESP-PROG works with most Espressif devices, it requires additional hardware and uses up to four pins. In newer cores, you have a second option via USB, as shown Debugging workflow illustration in Fig.1. |
| 141 | + |
| 142 | +### JTAG over USB |
| 143 | + |
| 144 | +Most newer Espressif SoC series integrate the USB peripheral and it can be used for JTAG debugging. |
| 145 | +Take a thick usb cable (designed for both charging and data transmission) and strip it using a wire stripper or a pair of scissors. You should see the four wires inside, as shown in Fig.3. |
| 146 | + |
| 147 | +<!-- |
| 148 | + --> |
| 149 | + |
| 150 | +{{< figure |
| 151 | +default=true |
| 152 | +src="img/usb_pins.webp" |
| 153 | +width=400 |
| 154 | +caption="Fig.3 - USB cable pins" |
| 155 | +>}} |
| 156 | +
|
| 157 | +Now connect `GND` , `D+` and `D-` to the corresponding Espressif module pins. |
| 158 | +If you're using an development board you can connect `VCC` to the `+5V` of the pin (__not__ the `3v3` pin!). |
| 159 | + |
| 160 | +{{< alert iconColor="#df8e1d" cardColor="#edcea3">}} |
| 161 | +USB supply pin is about 5V. To power your board with it, connect VCC to the input of an LDO regulator that outputs 3.3V for the Espressif module. |
| 162 | +{{< /alert >}} |
| 163 | + |
| 164 | +In the table below, you can find the pins for three common modules. |
| 165 | + |
| 166 | +||ESP32-C3-MINI-1|ESP32-S3-WROOM-1|ESP32-C6-WROOM-1| |
| 167 | +|---|---|---|---| |
| 168 | +|__D+__|GPIO 19|GPIO 19|GPIO 13| |
| 169 | +|__D-__|GPIO 18|GPIO 20|GPIO 12| |
| 170 | + |
| 171 | +For other modules, consult the _Pin Description_ section of the datasheet and look for `USB_D+` and `USB_D-`. |
| 172 | + |
| 173 | +Now that the hardware is ready, we can move back to the IDE. We will use the JTAG over USB pin option. |
| 174 | + |
| 175 | +## OpenOCD connection |
| 176 | + |
| 177 | +OpenOCD uses a server-client model to debug embedded systems. The OpenOCD server connects to the target hardware through a debug adapter (usually via JTAG). It exposes a _network interface_ that clients, such as `gdb` or `telnet`, can use to send commands or load code. |
| 178 | + |
| 179 | +<!-- Now, we create a project and set the connection between `gdb` and `openOCD`. The steps below apply to every Espressif module and SoCs, but the specific detail is given for the ESP32-C3-Mini-1-N4 connected via USB pins. --> |
| 180 | + |
| 181 | +Next, we'll start the openOCD server and test the connection with the hardware. The steps below are for an ESP32-C3 board, but you can easily adjust them for your module. We will use the JTAG over USB pins option. If you're using the ESP-PROG, modify steps 2 and 3 accordingly. |
| 182 | + |
| 183 | +1. Create a project from the `hello_world` example. |
| 184 | + _If you're unsure, please check [the documentation](https://docs.espressif.com/projects/vscode-esp-idf-extension/en/latest/startproject.html#esp-idf-show-examples-projects)_ |
| 185 | +2. > `ESP-IDF: Select Port to Use (COM, tty, usbserial)` - Choose the port you're connected to. You may find the SoC name and package next to the correct option (e.g. ESP32-C3 (QFN32) (revision v0.3)) |
| 186 | +3. >`ESP-IDF: Set Espressif Device target` → `esp32c3` →`ESP32-C3 chip (via Built-in USB-JTAG)` |
| 187 | + ("`esp32c3`" should now appear at the bottom left corner) |
| 188 | +4. >`ESP-IDF: Select OpenOCD Board Configuration`→`ESP32-C3 chip (via Built-in USB-JTAG)` |
| 189 | +5. >`ESP-IDF: OpenOCD Manager` → `Start OpenOCD` |
| 190 | + |
| 191 | +{{< alert icon="circle-info" cardColor="#b3e0f2" iconColor="#04a5e5">}} |
| 192 | +The `Scan for kits` notification may appear. You can allow it to automatically set up the port and board, but be sure to check the result! |
| 193 | +{{< /alert >}} |
| 194 | + |
| 195 | +After completing the steps, you should see: |
| 196 | +```bash |
| 197 | +Open On-Chip Debugger v0.12.0-esp32-20241016 (2024-10-16-14:27) |
| 198 | +Licensed under GNU GPL v2 |
| 199 | +For bug reports, read |
| 200 | + http://openocd.org/doc/doxygen/bugs.html |
| 201 | +debug_level: 2 |
| 202 | + |
| 203 | +Info : only one transport option; autoselecting 'jtag' |
| 204 | + |
| 205 | +Info : esp_usb_jtag: VID set to 0x303a and PID to 0x1001 |
| 206 | +Info : esp_usb_jtag: capabilities descriptor set to 0x2000 |
| 207 | + |
| 208 | +Info : Listening on port 6666 for tcl connections |
| 209 | +Info : Listening on port 4444 for telnet connections |
| 210 | + |
| 211 | +Info : esp_usb_jtag: serial (84:F7:03:42:8C:A8) |
| 212 | + |
| 213 | +Info : esp_usb_jtag: Device found. Base speed 40000KHz, div range 1 to 255 |
| 214 | + |
| 215 | +[...] |
| 216 | + |
| 217 | +Info : [esp32c3] Examination succeed |
| 218 | +Info : [esp32c3] starting gdb server on 3333 |
| 219 | +Info : Listening on port 3333 for gdb connections |
| 220 | +``` |
| 221 | + |
| 222 | +Congratulations, `openOCD` server is now waiting for a connection. In the second part, we'll start `gdb` and connect to it. |
| 223 | + |
| 224 | +### Troubleshooting |
| 225 | + |
| 226 | +Some issues may have logs that are hard for beginners to understand. Below are two common problems and how to fix them. |
| 227 | + |
| 228 | +#### Address already in use |
| 229 | + |
| 230 | +You could gets |
| 231 | +```bash |
| 232 | +❌ Error: couldn't bind tcl to socket on port 6666: Address already in use |
| 233 | +``` |
| 234 | +it means that `openOCD` is already running. To close it, you have to: |
| 235 | +
|
| 236 | +* Open an ESP-IDF terminal: `≫ESP-IDF: Open ESP-IDF Terminal` |
| 237 | +* Find the process number: `ps aux | grep openocd` (e.g. 13819) |
| 238 | +* Kill the process: `kill <process-nr>` (e.g. `kill 13819`) |
| 239 | +
|
| 240 | +#### Could not find or open device |
| 241 | +
|
| 242 | +You could get |
| 243 | +`Error: esp_usb_jtag: could not find or open device (ESP32-S3-DevKitC-1) (OCD-631) #219` |
| 244 | +
|
| 245 | +it may mean that the firmware inside the board does not expect the connection. |
| 246 | +
|
| 247 | +You may need to |
| 248 | +* Build the project |
| 249 | + > `ESP-IDF: Build your project`. |
| 250 | +* Flash the firmware |
| 251 | + > `ESP-IDF: Flash (UART) your project`. |
| 252 | +
|
| 253 | +If you followed the steps above, the flashing is performed via the JTAG peripheral through the USB pins. |
| 254 | +
|
| 255 | +If it's still not working, connect your board via UART0 pins (which in an development board can be accessed using the development board USB port) |
| 256 | +* Choose the right port |
| 257 | + ≫ `ESP-IDF: Select Port to Use (COM, tty, usbserial)` |
| 258 | +* Flash it again |
| 259 | + > `ESP-IDF: Flash (UART) your project`. |
| 260 | + |
| 261 | +## Conclusion |
| 262 | + |
| 263 | +In this tutorial, you learned how to connect your Espressif module via JTAG and start the openOCD server. In part two, we'll launch `gdb` and explore the code using various commands. |
| 264 | +
|
0 commit comments