Debugging ESP32 Code with JTAG
AD
Table of Contents
- Introduction
- Debugging Methods
- Using the Serial Terminal
- External Debugging Devices
- Choosing a Debugger Tool
- Setting up the Debugger
- Connecting the Debugger to the ESP32
- Connecting the Debugger to the PC
- Installing the FTDI2232H USB JTAG Driver
- Configuring OpenOCD
- Configuring GDB in Visual Studio Code
- Automating the Debugging Process
- Debugging Example
- Conclusion
Introduction
In this article, we will explore the process of debugging ESP32 IDF applications inside Visual Studio Code using an external debugger. Debugging is an essential skill for firmware developers, allowing them to find and fix problems during and after code execution. We will discuss different methods of debugging, focusing on using an external debugger and the advantages it offers. We will guide You through the process of setting up the debugger, configuring OpenOCD and GDB, and automating the debugging process. Finally, we will provide a debugging example to illustrate the benefits of using an external debugger.
1. Debugging Methods
Using the Serial Terminal
The first and simplest method of debugging a microcontroller is using the serial terminal. By adding debug messages to your code, you can Gather information about the execution of your code. This method is straightforward and useful when you don't have access to an external debugger. The ESP-IDF framework provides a built-in capability for catching exceptions and misconfigurations, which can be displayed in the serial terminal. However, this method has limitations, especially when you cannot use prints inside interruption callbacks or when you need more advanced debugging features.
External Debugging Devices
External debugging devices, also known as debug interfaces, provide a more powerful and versatile solution for debugging microcontrollers. These devices use common debug interfaces like SWD, JTAG, or ICE to communicate with the microcontroller. They allow you to set breakpoints, control the execution of your code, access variables and pointers, and retrieve valuable information in case of crashes or exceptions. In this article, we will focus on using JTAG as the debugging interface since it is natively supported by the ESP32 and widely used.
2. Choosing a Debugger Tool
Before setting up the debugger, you need to choose a suitable debugger tool. There are various debugging tools available in the market, ranging from professional-grade and expensive tools to simpler and more affordable options. One popular and cost-effective option is the ESP-PROG debugger, which uses the FTDI2232H chip. You can purchase a debugger board with this chip for less than $25 online. It is recommended to start with the ESP-PROG debugger for beginners, as it is the official debugger from Espressif and offers good performance and compatibility.
3. Setting up the Debugger
To set up the debugger, you will need to connect it to the ESP32 and your PC. The ESP-PROG debugger has two connectors: one for JTAG and one for the serial interface. Both connectors can be connected to the ESP32 using a single USB cable, but we will focus on connecting only the JTAG for simplicity. Ensure that you have the necessary drivers installed for the debugger to be recognized correctly by your PC. We will use the FTDI2232H USB JTAG driver, which can be updated using a driver updater tool called Zadig.
Connecting the Debugger to the ESP32
The ESP32 is connected to the JTAG debugger through its IO pins. The specific pin connections depend on the debugger board you are using. For the ESP-PROG debugger, the connections should be made as follows:
- Connect Ground to Ground.
- Connect 3V3 to 3V3.
- Connect TCK to IO13.
- Connect TDI to IO12.
- Connect TDO to IO15.
- Connect TMS2 to IO14.
Connecting the Debugger to the PC
To connect the debugger to your PC, you will need to use two different USB ports. One USB port is used for the serial interface, allowing you to use the serial monitor, while the other USB port is used for the debugger's JTAG interface. Ensure that you have the necessary drivers installed for the USB-to-serial interface and that the device is recognized by your PC. Use the provided USB cables to establish the connections between the debugger and your PC.
Installing the FTDI2232H USB JTAG Driver
In order for the JTAG interface of the debugger to work properly and be recognized by your PC, you need to install the FTDI2232H USB JTAG driver. By default, Windows has a generic version of the FTDI driver with only the UART interface enabled. We need to update the driver to add support for the JTAG interface. To do this, we will use the Zadig driver updater tool. Download and install Zadig from their official Website. Open Zadig, go to Options, select "List All Devices," and then find the "Dual RS232 (Interface 0)" entry in the device list. Click on "Replace Driver" to update the driver for the FTDI chip. After updating the driver, unplug and plug the USB cable of the debugger to refresh the driver connection. Keep in mind that if you plug the debugger into a different USB port, you might need to install the driver again.
4. Configuring OpenOCD
Now that the physical connections are established and the correct drivers are installed, we need to configure OpenOCD, the open on-chip debugger software responsible for managing the communication with the debugger driver. Open a new terminal in Visual Studio Code, ensuring that your environment is already configured for ESP-IDF development. Type the following command in the terminal:
openocd -f board/esp32-rover-kit-3.3v.cfg
This command uses the provided OpenOCD configuration file for the ESP32, specifically the ESP32 Rover Kit version. If you are using a different ESP32 module, you may need to provide a different configuration file. Refer to the ESP-IDF documentation for details about different board configurations. If you have connected the ESP32 correctly and the driver is installed correctly, you should see the output confirming that OpenOCD is running and the debugger is ready.
5. Configuring GDB in Visual Studio Code
GDB, the GNU Debugger, is an open-source debugging software used by Visual Studio Code to communicate with OpenOCD and the ESP32. To configure GDB, open the Debug view in Visual Studio Code by clicking on the debug icon and then on the "Run and Debug" button. Click on "C++ (GDB/LLDB)" to Create a launch configuration. This will create a file called "launch.json" inside the ".vscode" directory of your project. Remove any unnecessary lines from the launch configuration file and add the following parameters:
- "name": Specify a name for the debug configuration.
- "type": Set the debug type to "cppdbg".
- "request": Set the request type to "launch".
- "cwd": Set the Current working directory to your workspace/build directory.
- "program": Specify the path to your ELF file, typically located in your workspace/build directory.
Next, set the "miDebuggerPath" parameter to the path where your ESP32 GDB executable is located. If you have followed the previous video tutorial, the folder structure should be similar to the one shown in the tutorial. Make sure to use forward slashes instead of backslashes in the file path. Finally, add the following "setupCommands" to configure the connection to OpenOCD:
"setupCommands": [
{
"text": "-target-select remote localhost:3333",
"description": "Connect to OpenOCD"
},
{
"text": "set remote hardware-breakpoint-limit 2",
"description": "Set hardware breakpoint limit"
},
{
"text": "monitor reset halt",
"description": "Reset ESP32 and halt"
},
{
"text": "flushregs",
"description": "Flush register cache"
}
]
Save the launch configuration file. At this point, you have successfully configured GDB in Visual Studio Code to communicate with OpenOCD using the ESP32 GDB executable. You can now use the debugging features provided by Visual Studio Code, such as setting breakpoints, stepping through code, accessing variables, and more.
6. Automating the Debugging Process
Manually starting OpenOCD and loading the firmware every time you want to debug can be time-consuming and prone to errors. To make our debugging process more efficient, we can automate these steps. To automate the launch of OpenOCD when we start debugging, create a file called "tasks.json" inside the ".vscode" folder. Delete any existing lines and add the following properties for our new task:
{
"label": "Pre-Launch Task",
"type": "shell",
"command": "clear && start opencd -f board/esp32-rover-kit-3.3v.cfg && exit"
}
This task will start OpenOCD automatically in a new terminal every time we start the debugging session. Save the file. To call this task before running the debug session, open the launch configuration file, and add the following line:
"preLaunchTask": "Pre-Launch Task"
Now, when you click on the "Start Debugging" button, Visual Studio Code will automatically start OpenOCD, establish the connection, and load the firmware for debugging.
7. Debugging Example
To illustrate the benefits of using an external debugger, let's go through a simple debugging example. We have a program that doubles a counter variable until it reaches 128, at which point it displays 0. We have connected a button to an IO Pin, which triggers an external interruption every time it is pressed. The interruption callback function doubles the counter value. However, We Are facing a bug where the displayed number turns to 0 when it exceeds 128. To debug this issue, we can set a breakpoint inside the interruption callback and observe the variable values. By stepping through the code, accessing variables, and setting conditional breakpoints, we can identify and fix the problem. This example demonstrates how an external debugger provides insights into the flow of our program, allows us to pause execution, and inspect variables, ultimately helping us find and solve bugs efficiently.
8. Conclusion
Debugging is an essential skill for firmware developers, and using an external debugger can greatly facilitate the process. In this article, we discussed different debugging methods, highlighted the benefits of using an external debugger, and provided a step-by-step guide to setting up and configuring an external debugger for ESP32 IDF applications in Visual Studio Code. We also demonstrated a debugging example to showcase the capabilities of an external debugger. By following the instructions in this article, you can improve your firmware development process and effectively debug ESP32 applications. Happy debugging!
Highlights
- Debugging is an essential skill for firmware developers, allowing them to find and fix problems during code execution.
- Using an external debugger provides advanced debugging features such as setting breakpoints, controlling code execution, and accessing variables.
- The ESP-PROG debugger with the FTDI2232H chip is a cost-effective and popular option for debugging ESP32 IDF applications.
- Setting up the debugger involves connecting it to the ESP32 and the PC, installing the necessary drivers, and configuring OpenOCD and GDB in Visual Studio Code.
- Automating the debugging process can save time and improve efficiency by automatically starting OpenOCD and loading the firmware when starting the debugging session.
- In a debugging example, we demonstrated how to use an external debugger to identify and fix a bug in a simple ESP32 application.
FAQ
-
Which debugger tool should I choose for debugging ESP32 IDF applications?
- The ESP-PROG debugger with the FTDI2232H chip is recommended for beginners due to its affordability and compatibility.
-
How do I connect the debugger to the ESP32?
- Connect the ground, 3V3, TCK, TDI, TDO, and TMS2 pins of the debugger to the corresponding pins on the ESP32.
-
How do I connect the debugger to my PC?
- Use two different USB ports to connect the debugger to your PC. One port is for the serial interface, and the other is for the JTAG interface.
-
How do I configure OpenOCD for debugging?
- Use the OpenOCD configuration file specific to your ESP32 module. Open a terminal in Visual Studio Code and run the command "openocd -f board/.cfg".
-
How do I configure GDB in Visual Studio Code?
- Update the launch configuration file (launch.json) with the necessary parameters for your project, such as the debugger path, program path, etc.
-
How can I automate the debugging process?
- Create a task.json file to automate the launch of OpenOCD when starting the debugging session. Modify the launch configuration file to include the pre-launch task.
-
How can I debug my ESP32 application using breakpoints and variable inspection?
- Set breakpoints at Relevant points in your code using the Debug view in Visual Studio Code. Use the step over, step in, and step out buttons to navigate through your code. Access variable values in the variable list window.
-
Can I use an external debugger if my code uses interrupt callbacks?
- Yes, an external debugger allows you to debug interrupt callbacks by pausing execution and inspecting variables at the desired breakpoints.