0
点赞
收藏
分享

微信扫一扫

ESP32 JTAG 调试


前言


  1. 本人使用的是 Ubuntu 环境,采用 GDB 方式进行调试。
  2. 对于新手,我个人还是建议参考ESP32S3学习笔记(0)—— Vscode IDF环境搭建及OpenOCD调试介绍进行图形化的方式调试。
  3. 如果是希望在 Windows 环境下进行 GDB 调试,可以参考 Windows 环境下,使用 ESP32-S3 USB 接口进行 JTAG 调试的流程。

GDB 介绍

两种调试方式

  1. ESP32 提供了两种调试方式,一种是利用串口进行日志打印。这种方式是常用的,我们可以根据日志信息知道程序的运行信息。
  2. 但是在一些特殊场景,例如我需要让程序在某个时刻停下来进行调试,日志打印的方式就并不那么好用了。我们此时就可以使用 JTAG 调试的方式进行。

ESP32 JTAG 调试_GDB

GDB 和 Openocd 介绍

  1. 电脑端,我们需要先运行 Openocd 充当调试代理用于与目标硬件进行直接通讯,他提供一个 GDB 服务器接口(通常在TCP端口 :3333 上),GDB 可以通过该接口与 OpenOCD 通信。 GDB 会向 OpenOCD 发送调试命令,例如设置断点、查看寄存器、单步执行等。当 OpenOCD 接收到来自 GDB 的命令后,负责将这些命令转换成特定的硬件指令,并执行到目标设备上
  2. GDB 是一个高层的调试器,用户通过它来编写和管理调试会话。GDB本身不直接与硬件通信,它通过GDB服务器(如OpenOCD提供的)与设备进行交互。
  3. 如下为 电脑端 <—> 调试器 <—> ESP32C3 的方式进行调试。调试器为 FT2232/FT232 芯片。

ESP32 JTAG 调试_GDB_02

  1. 这种外置调试器的方法相对麻烦,还需要自行准备调试芯片,后面乐鑫将调试器集成到了芯片内部。

ESP32 JTAG 调试_变量名_03

  1. 我们可以通过乐鑫官方选型网站得知哪些芯片内部集成了 JTAG 调试接口。

ESP32 JTAG 调试_变量名_04

  1. 如果当前使用的芯片内部没有 JTAG 调试接口,我们可以购买 ESP-Prog 进行调试。

环境准备

打开 Openocd

  1. 通过上面的内容我们知道,要进行 GDB 调试 ESP32-S3 的话,需要先打开 Openocd 提供一个接口。我们可以输入如下命令进行开启 Openocd。

openocd -f board/esp32s3-builtin.cfg

  1. 这个 cfg 文件在如下目录中,我们可以在该目录中选择合适的文件打开 Openocd。

注:随着版本更新,你可能并不是 v0.12.0-esp32-20230921。

~/.espressif/tools/openocd-esp32/v0.12.0-esp32-20230921/openocd-esp32/share/openocd/scripts/board

  1. 这个时候肯定就会有人要说了,我怎么知道应该选择哪个 cfg 文件呢?
  • 如果是内部集成了 JTAG 接口,一般选择 builtin 名称的 cfg 文件。
  • 如果是使用的 ESP-Prog 调试器,那么就选择 bridge 名称的 cfg 文件。
  • 如果你发现上述做法都不对,那就找到对应的芯片前缀名,然后一个一个的试吧。(哭笑)
  1. 在 Ubuntu 环境中,你打开 Openocd 发现如下报错,那么说明当前用户没有足够的权限访问 USB 设备

Error: libusb_open() failed with LIBUSB_ERROR_ACCESS
Error: esp_usb_jtag: could not find or open device!

  1. 此时你需要创建一个 udev 规则文件添加规则。

sudo vim /etc/udev/rules.d/99-openocd.rules

  1. 添加如下内容。

SUBSYSTEM=="usb", ATTR{idVendor}=="303a", ATTR{idProduct}=="1001", MODE="0666"

  1. 重新加载 udev 规则。

sudo udevadm control --reload-rules
sudo udevadm trigger

进入 GDB 调试

  1. 我们需要在项目根目录中创建 gdbinit 文件,并且在该文件中加入如下内容。

tui enable 命令能够在终端中增加一个 UI 界面方便我们知道当前调试的位置,如果觉得这个 UI 界面看的不舒服,可以将这一行给删除

# 告诉 GDB 连接到运行在本地(即当前计算机)上的 OpenOCD 服务,监听端口 3333
target remote :3333
# 设置硬件观察点限制
set remote hardware-watchpoint-limit 2
# 重置并停止目标设备
mon reset halt
# 刷新寄存器状态
flushregs
# 在 app_main 函数处设置临时断点
thb app_main
# 继续执行程序
c
# 使能 UI 界面
tui enable

  1. 此时我们需要再打开一个终端,输入如下命令即可进入 GDB 调试界面。

注:当前 elf 文件应该是你烧录到芯片时,生成的 elf 文件! 调试过程中,工程代码建议不要修改。

xtensa-esp32s3-elf-gdb -x gdbinit build/gatt_client_demo.elf

  1. 不同的芯片/架构使用的 GDB 调试器不同,具体参考如下:

架构/芯片

命令

Xtensa ESP32

xtensa-esp32-elf-gdb

Xtensa ESP32-S2

xtensa-esp32s2-elf-gdb

Xtensa ESP32-S3

xtensa-esp32s3-elf-gdb

RISC-V

riscv32-esp-elf-gdb

GDB 命令

控制命令

运行命令

命令

作用

continue/c

运行程序,直到遇到断点才停止

next/n

单步执行, 跳过函数调用

next/n count

运行多步, 跳过函数调用(count 要跳过运行的步骤次数)

step/s

单步调试,进入函数调用

step/s count

多步调试,进入函数调用(count 要跳过运行的步骤次数)

finish

继续执行,直到当前函数返回

until num

运行到指定行号(num 行号)

jump/j num

直接跳转到指定行数代码,相当于 C 语言的 goto 语句

monitor reset halt

复位开发板

set 命令

命令

作用

set 变量名=num

将指定变量设置为指定值(num 数值)

set $变量名=num

设置一个 GDB 的内部变量,此方法可以用于进行特定的调试计算。具体参考ESP32 JTAG Debug 14: GDB Set 命令的第 6 min

set print address off/on

打印数据时,关闭/开启 打印对应数据地址

set style address foreground

设置内存地址的前景色(字体颜色)

set style address background

设置内存地址的背景色

信息查看命令

命令

作用

list/l

列出当前位置往下10列源代码

backtrace/bt

查看函数调用信息

where

查看当前程序运行到了哪里

info locals

查看当前作用域的局部变量信息

info registers/reg

显示所有寄存器的值

info registers/reg

显示指定寄存器的值

print 命令

命令

作用

print 变量名/数组/字符串/结构体

查看指定变量的值

print /x 变量名

以 16 进制形式打印变量值

print /d 变量名

以 10 进制形式打印变量值

print /u 变量名

以无符号 10 进制形式打印变量值

print /o 变量名

以 8 进制形式打印变量值

print /t 变量名

以 2 进制形式打印变量值

print /a 变量名

以地址格式打印变量值

print /c 变量名

以字符形式打印变量值

print /f 变量名

以浮点数形式打印变量值

print /s 变量名

以字符串形式打印变量值

print 函数名 :: 变量名

打印指定函数中,指定变量的数据

print ‘指定文件路径’ :: 变量

打印不同文件中变量的信息

print pretty on

启动 “漂亮打印”(pretty-printing)功能,这将允许 GDB 以更可读的格式输出复杂数据结构(如结构体、类、数组等),使得调试时的输出更加清晰易懂

display 命令

命令

作用

display 变量名

持续监视某个变量

display /x 变量名

以 16 进制形式持续监视某个变量

info display

查看 display 列表

disable display num

失能 display 列表中指定监视

enable display num

使能 display 列表中指定监视

undisplay num

删除 display 列表中指定监视

delete display num

删除 display 列表中指定监视

地址信息打印命令

格式 :

x/<count><format><size> <address>

  • <count>:要显示的内存单元的数量(可选,默认值为 1)。
  • <format>:指定输出格式,可以是以下之一:
  • x:十六进制(hexadecimal)
  • d:十进制(decimal)
  • u:无符号十进制(unsigned decimal)
  • o:八进制(octal)
  • t:二进制(binary)
  • c:字符(character)
  • f:浮点数(float)
  • s:字符串(string)
  • i:指令(instruction)
  • <size>:指定每个单元的大小,可以是以下之一:
  • b:字节(byte)
  • h:半字(halfword,2 bytes)
  • w:字(word,通常为 4 bytes)
  • g:巨字(giant word,通常为 8 bytes)
  • <address>:要查看的内存地址,可以是变量名、指针或具体的内存地址。

断点命令

添加断点

命令

作用

break/b n

gdb 运行到的当前文件中的某一行设置断点(n : 当前文件行号)

break/b filename: n

向指定文件的指定行设置断点(filename : 指定)

break/b func

在指定函数开头设置断点(func : 函数名)

tbreak n/func

设置临时断点,在设置之后只起作用一次(n : 当前文件行号 func : 函数名)

断点控制

命令

作用

disable n

失能指定断点号断点 (n : 断点号)

enable n

使能指定断点号断点 (n : 断点号)

delete/d

删除所有断点

delete/d n

删除指定断点号断点 (n : 断点号)

clear n

清除行 n 上面的所有断点

查看断点信息

命令

作用

info break/b

查看所有断点信息

info break/b n

查看指定断点号断点信息 (n : 断点号)

观察断点

命令

作用

watch 变量名

给指定变量名设置一个观察断点,所有与该变量名发生变化的地方进行打断,在运行到发生修改地方时,会停止并且打印该变量的原来值修改之后的值。在相同的地方,如果只有第一次该变量发生变化,那么该地方只有第一次会被打断

info watch

查看观察断点相关信息

watch 表达式

给一个表达式观察断点,例如表达式 i+j,如果变量 i 不发生变化,j 发生变化,依旧会在 j 发生变化的地方进行打断

其他命令

命令

作用

shell clear

调用 shell 清屏命令

quit/q

退出 gdb 调试

define my_command

自定义命令,能够进行自定义调试,具体用法参考ESP32 JTAG Debug 15: GDB Define 命令

TUI 使用

命令

作用

上下左右箭头

向上/下/左/右向滚动代码

PgUP/PgDn

向上/下翻页

update

回到当前运行的位置

list/l num

查看指定行号信息(num 行号)

layout asm

查看汇编代码

layout regs

显示寄存器相关信息

layout src

回到源代码

参考

  1. Windows 环境下,使用 ESP32-S3 USB 接口进行 JTAG 调试的流程
  2. B站:ESP32 JTAG Debug 01: JTAG接口简介
  3. 利用 Guru Meditation 错误打印定位问题
  4. GDB常用命令大全 GDB 命令详细解释
  5. gdb调试常见命令详细总结(附示例操作)



举报

相关推荐

0 条评论