Espressif IDF for VSCode 爬坑之路二:ESP32 的 JTAG 调试(OpenOCD & GDB)

今天我们来探索如何在 Espressif IDF 插件里进行 JTAG 调试。如果还未成功安装与入门 Espressif IDF for VSCode,可以先参考 Espressif IDF for VSCode 爬坑之路一:ESP32 的 esp-idf 例子编译与烧录

1. JTAG 调试前的准备

如果要在 Espressif IDF for VSCode 里启动 JTAG 调试功能,只需先按 F5 键(确保您至少已经 build 并 flash ,这样调试器才能正常工作)。 为确保可以调试设备,我们也需要在 settings.json 中设置正确的 idf.deviceInterfaceidf.board 设置,或按 F1 并键入 ESP-IDF:Device configuration。下面我将以图文并茂的形式来演示上述操作。

首先打开工程,然后编译和烧写。在这里我选择打开的是 /esp-idf/examples/get-started/blink 示例,打开后我们可以在按下 F1 后依次进行 ESP-IDF:Select port to useESP-IDF:Build your projectESP-IDF:Flash your projectESP-IDF:Monitor your device。指令对应的位置如下图(按下 F1 后)。

在这里插入图片描述

在成功看到 monitor 打开且能看到程序在正常运行后,我们需要按下 F5 键(确保您至少已经 build 并 flash ,这样调试器才能正常工作)。然后按需要选择对应的 gcc gdb 版本即可。

接下来我们还需要按 F1 并键入 ESP-IDF:Device configuration,在里面设置正确的 idf.deviceInterfaceidf.board 。键入 ESP-IDF:Device configuration 并按下回车后如下图。一般 Espressif IDF for VSCode 会默认帮我们进行正确的配置,比如使用的是自带 JTAG 调试工具的 ESP32-WROVER 开发板,然后点击下图中的 Board 时发现已经默认为 board/esp32-wrover.cfg。如果发现默认填写的内容与实际不符,大家可以按上述步骤自行更改。

在这里插入图片描述

由于我们在 Espressif IDF for VSCode 初始环境配置时就已经初始安装了 OpenOCD, 而且我使用的是自带 JTAG 调试器的 ESP32-WROVER 开发板,如果需要外接 JTAG 调试器,可以参考 JTAG 调试,所以到这里我们在软件上就配置好环境了。下一节我们将正式开始 JTAG 调试。

2. JTAG 调试

2.1 打开 OpenOCD

F1 并键入 ESP-IDF:OpenOCD Manager,我们可以看到 Start OpenOCD 选项,直接点击此选项。

在这里插入图片描述

然后我们就能看到 VSCode 界面下发弹出了一个 OUTPUT,不难看出其中有 Info : Listening on port 3333 for gdb connections 这条信息。它告诉我们 gdb 的 端口为 3333,到这里就可以再开启一个终端来进行 gdb 调试了。

扫描二维码关注公众号,回复: 10811580 查看本文章

在这里插入图片描述

2.2 进行 GDB 调试

我们先打开一个终端,然后进入到 /esp-idf/examples/get-started/blink 目录下,在此目录下我们先新建一个名为 gdbinit 的文件(在终端里使用指令 touch gdbinit),这个文件里用来储存初始化配置 GDB 的相关指令(也可以跳过此步骤,然后在开启 GDB 调试后自行输入以下指令),然后打开此文件,在文件里面粘贴以下内容:

target remote :3333
set remote hardware-watchpoint-limit 2
mon reset halt
flushregs
thb app_main
c

上述每一行配置 GDB 指令的解释为:

  • set remote hardware-watchpoint-limit 2:限制 GDB 仅使用 ESP32 支持的两个硬件观察点。更多资料可以查阅 GDB 配置远程目标
  • mon reset halt:复位芯片并使 CPU 停止运行。
  • flushregs:monitor (mon) 命令无法通知 GDB 目标状态已经更改,GDB 会假设在 mon reset halt 之前所有的任务堆栈仍然有效。实际上,复位后目标状态将发生变化。执行 flushregs 是一种强制 GDB 从目标获取最新状态的方法。
  • thb app_main:在 app_main 处插入一个临时的硬件断点,如果有需要,可以将其替换为其他函数名。
  • c:恢复程序运行,它将会在 app_main 的断点处停止运行。

在完成上述操作后,我们就可以运行 xtensa-esp32-elf-gdb -x gdbinit build/blink.elf 来开启 GDB 调试了,如果提示 xtensa-esp32-elf-gdb: command not found,我们还需要添对应的工具链的路径。终端里对应的操作如下所示:

zhong@FA000972:~$ cd /home/zhengzhong/VSCODE_IDF/esp-idf/examples/get-started/blink
zhong@FA000972:~/VSCODE_IDF/esp-idf/examples/get-started/blink$ xtensa-esp32-elf-gdb -x gdbinit build/blink.elf
xtensa-esp32-elf-gdb: command not found
zhong@FA000972:~/VSCODE_IDF/esp-idf/examples/get-started/blink$ export PATH="$HOME/esp/xtensa-esp32-elf/bin:$PATH"
zhong@FA000972:~/VSCODE_IDF/esp-idf/examples/get-started/blink$ xtensa-esp32-elf-gdb -x gdbinit build/blink.elf
GNU gdb (crosstool-NG crosstool-ng-1.22.0-80-g6c4433a) 7.10
Copyright (C) 2015 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "--host=x86_64-build_pc-linux-gnu --target=xtensa-esp32-elf".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from build/blink.elf...done.
0x400e29ee in esp_pm_impl_waiti ()
    at /home/zhengzhong/VSCODE_IDF/esp-idf/components/esp32/pm_esp32.c:492
492	    asm("waiti 0");
JTAG tap: esp32.cpu0 tap/device found: 0x120034e5 (mfg: 0x272 (Tensilica), part: 0x2003, ver: 0x1)
JTAG tap: esp32.cpu1 tap/device found: 0x120034e5 (mfg: 0x272 (Tensilica), part: 0x2003, ver: 0x1)
esp32: Debug controller 0 was reset (pwrstat=0x5F, after clear 0x0F).
esp32: Core 0 was reset (pwrstat=0x5F, after clear 0x0F).
esp32: Debug controller 1 was reset (pwrstat=0x5F, after clear 0x5F).
esp32: Core 1 was reset (pwrstat=0x5F, after clear 0x5F).
Target halted. PRO_CPU: PC=0x5000004B (active)    APP_CPU: PC=0x00000000 
esp32: Core 0 was reset (pwrstat=0x1F, after clear 0x0F).
Target halted. PRO_CPU: PC=0x40000400 (active)    APP_CPU: PC=0x40000400 
Hardware assisted breakpoint 1 at 0x400d1e37: file ../main/blink.c, line 28.
Target halted. PRO_CPU: PC=0x400D1E37 (active)    APP_CPU: PC=0x400E29EE 
[New Thread 1073437804]
[New Thread 1073435904]
[New Thread 1073440460]
[New Thread 1073428196]
[New Thread 1073412780]
[New Thread 1073413520]
[New Thread 1073429328]
[Switching to Thread 1073433788]

Temporary breakpoint 1, app_main () at ../main/blink.c:28
28	    gpio_pad_select_gpio(BLINK_GPIO);

我们可以看到在使用 GDB 调试后,由于我们在 gdbinit 文件里的配置,它将会在 app_main 的断点处停止运行。现在我们可以对 GDB 调试的功能进行简单测试来确保一切正常,在这里,我使用了 l 28, 40 指令来让 GDB显示 blink.c 里的第 28 - 40 行。运行结果表明 GDB 调试 正常运行,如下:

(gdb) l 28, 40
28	    gpio_pad_select_gpio(BLINK_GPIO);
29	    /* Set the GPIO as a push/pull output */
30	    gpio_set_direction(BLINK_GPIO, GPIO_MODE_OUTPUT);
31	    while(1) {
32	        /* Blink off (output low) */
33		printf("Turning off the LED\n");
34	        gpio_set_level(BLINK_GPIO, 0);
35	        vTaskDelay(1000 / portTICK_PERIOD_MS);
36	        /* Blink on (output high) */
37		printf("Turning on the LED\n");
38	        gpio_set_level(BLINK_GPIO, 1);
39	        vTaskDelay(1000 / portTICK_PERIOD_MS);
40	    }

到此,大家就已经成功实践如何使用 Espressif IDF for VSCode 进行 ESP32 的 JTAG 调试了。

3. 附录: GDB 相关指令及资料

3.1 断点设置

  • break N:在第 N 行设置断点
  • delete N:删除第 N 行的断点
  • info break:查看已设置的断点数量和位置

3.2 调试运行

  • s(或 step):单步调试,可以跳入函数内部
  • n(或 next):单步调试,不跳入函数内部
  • c:Continue,继续运行,到断点处停止
  • Ctrl+C:随机停止
  • q:结束会话

3.3 查看、修改内存

  • x /1wx 0x3FF44004:查看 0x3FF44004 内存位置内容 0x3ff44004: 0x00000000
  • set {unsigned int}0x3FF44004=0x000010 :设置 0x3FF44004 内存位置内容
  • p i:print,打印当前i的值
  • watch i:在发生的代码处插入“观察点”

3.4 浏览代码,查看堆栈和线程

  • i threads:查看当前所有线程
  • thread N:查看编号 N 线程的代码
  • bt (或 backtrace):查看上一层,查看当前函数调用处(仅查看,未跳出)
  • l/list:打印停止点处代码
  • l 30, 40:打印第30-40行代码

3.5 查看帮助

  • help xxx:查看指令xxx的帮助
发布了53 篇原创文章 · 获赞 21 · 访问量 8368

猜你喜欢

转载自blog.csdn.net/zztiger123/article/details/103905323