JTAG 调试

[English]

本文将介绍如何安装 ESP32 的 OpenOCD 调试环境,以及如何使用 GDB 来调试 ESP32 的应用程序。本文结构如下:

引言

介绍本指南主旨。

工作原理

介绍 ESP32、JTAG(Joint Test Action Group)接口、OpenOCD 和 GDB 如何相互连接,从而实现 ESP32 的调试功能。

选择 JTAG 适配器

介绍有关 JTAG 硬件适配器的选择及参照标准。

安装 OpenOCD

介绍如何安装官方预编译好的 OpenOCD 软件包并验证是否安装成功。

配置 ESP32 目标板

介绍如何设置 OpenOCD 软件并安装 JTAG 硬件,两项共同构成调试目标.

启动调试器

介绍如何从 Eclipse 集成开发环境命令行终端 启动 GDB 调试会话。

调试范例

如果您不熟悉 GDB,请查看此小节以获取 Eclipse 集成开发环境 以及 命令行终端 提供的调试示例。

从源码构建 OpenOCD

介绍如何在 WindowsLinuxmacOS 操作系统上从源码构建 OpenOCD。

注意事项和补充内容

介绍使用 OpenOCD 和 GDB 通过 JTAG 接口调试 ESP32 时的注意事项和补充内容。

引言

ESP32 具有两个强大的 Xtensa 内核,支持多种程序架构。ESP-IDF 自带的 FreeRTOS 操作系统支持多核抢占式调度,允许用户以更加直观的方式编写软件。

与此相对地,由于缺乏合适的工具,简便的编程方式也会给程序的调试带来困难,比如找出由两个线程引起的错误,并且这两个线程在单独的 CPU 核上同时运行,那么仅凭 printf 语句会花费很长时间来定位该错误。调试此类问题更好(往往也更快)的方法是使用调试器,将其连接到处理器的调试端口。

乐鑫已完成 OpenOCD 移植,以支持 ESP32 处理器和多核 FreeRTOS 架构(此作为大多数 ESP32 应用程序的基础)。此外,乐鑫还提供了一些 OpenOCD 本身并不支持的工具,以进一步丰富调试功能。

本文将介绍如何在 Linux、Windows 和 macOS 环境下为 ESP32 安装 OpenOCD,并使用 GDB 进行软件调试。除部分安装流程有所不同外,所有操作系统的软件用户界面和使用流程都是相同的。

注解

本文使用的图片素材来自于 Ubuntu 16.04 LTS 上 Eclipse Neon 3 软件的截图,不同的操作系统(Windows、macOS 或 Linux)或不同的 Eclipse 软件版本在用户界面上可能会有细微差别。

工作原理

通过 JTAG(Joint Test Action Group)接口使用 OpenOCD 调试 ESP32 时所需要的关键软件和硬件包括 xtensa-esp32-elf-gdb 调试器OpenOCD 片上调试器 和连接到 ESP32 目标的 JTAG 适配器,如下图 “Application Loading and Monitoring” 标志所示。

JTAG debugging - overview diagram

JTAG 调试 - 概述图

“Application Loading and Monitoring” 标志显示一组关键的软件和硬件组件,可用于编译、构建和烧写应用程序到 ESP32 上,以及监视来自 ESP32 的运行诊断信息。

Eclipse 环境集成了 JTAG 调试和应用程序加载、监视的功能,使得软件从编写、编译、加载到调试的迭代过程变得更加快速简单。Eclipse IDE 及其集成的调试软件均适用于 Windows、Linux 和 macOS 平台。

若使用 ESP-WROVER-KIT 开发板,由于其板载 FT232H 芯片,仅需一根 USB 线即可连接 PC 与 ESP32。FT232H 提供了两路 USB 通道,一路连接到 JTAG,另一路连接到 UART。

根据用户喜好,除了使用 Eclipse 集成开发环境,还可以直接在命令行终端运行 debuggeridf.py build

选择 JTAG 适配器

上手 JTAG 最快速便捷的方式是使用 ESP-WROVER-KIT 开发板,因为它板载了 JTAG 调试接口,无需使用外部 JTAG 硬件适配器和额外线缆来连接 JTAG 与 ESP32。ESP-WROVER-KIT 采用 FT2232H 提供的 JTAG 接口,可以稳定运行在 20 MHz 的时钟频率,外接的适配器很难达到这个速度。

上手 JTAG 最快速便捷的方式是将一根 USB 线连接到 ESP32 的 D+/D- USB 管脚,无需使用外部 JTAG 适配器和额外线缆。

如果您想使用单独的 JTAG 适配器,请确保其与 ESP32 的电平电压和 OpenOCD 软件都兼容。ESP32 使用的是业界标准的 JTAG 接口,它未使用(实际上也并不需要)TRST 信号脚。JTAG 使用的 IO 管脚由 VDD_3P3_RTC 电源管脚供电(通常连接到外部 3.3 V 的电源轨),因此 JTAG 硬件适配器的管脚需要能够在该电压范围内正常工作。

在软件方面,OpenOCD 支持相当多数量的 JTAG 适配器,请参阅 OpenOCD 支持的适配器列表 (请注意这一列表并不完整),其中还列出了兼容 SWD 接口的适配器,但请注意,ESP32 目前并不支持 SWD。此外,被硬编码为只支持特定产品线的 JTAG 适配器也无法在 ESP32 上工作,例如仅针对 STM32 系列产品的 ST-LINK 适配器。

JTAG 正常工作至少需要连接的信号线有:TDI、TDO、TCK、TMS 和 GND。一些 JTAG 适配器还需要 ESP32 提供一路电源到适配器的某个管脚上(比如 Vtar),用于设置适配器的工作电压。您也可以选择将 SRST 信号线连接到 ESP32 的 CH_PD 管脚上,但请注意,目前 OpenOCD 对该信号线提供的支持相当有限。

ESP-Prog 中展示了使用外部电路板进行调试的实例,方法是将其连接到 ESP32 的 JTAG 管脚上。

安装 OpenOCD

如果您已经按照 快速入门 完成了 ESP-IDF 及其 CMake 构建系统的安装,那么 OpenOCD 已经被默认安装到了您的开发系统中。在 设置开发环境 结束后,您应该能够在终端中运行如下 OpenOCD 命令:

openocd --version

终端会输出以下信息(实际版本号可能会更新):

Open On-Chip Debugger  v0.10.0-esp32-20190708 (2019-07-08-11:04)
Licensed under GNU GPL v2
For bug reports, read
    http://openocd.org/doc/doxygen/bugs.html

您还可以检查 OPENOCD_SCRIPTS 环境变量的值,以确认 OpenOCD 配置文件的路径,Linux 和 macOS 用户可以在终端输入 echo $OPENOCD_SCRIPTS,Windows 用户需要输入 echo %OPENOCD_SCRIPTS%。如果终端输出了有效路径,则表明您已经正确安装 OpenOCD。

如果无法执行上述步骤,请再次阅读快速入门手册,参考 设置安装工具 章节。

注解

另外也可以从源代码编译 OpenOCD 工具,详细信息请参阅 从源码构建 OpenOCD 章节。

配置 ESP32 目标板

OpenOCD 安装完成后就可以配置 ESP32 目标(即带 JTAG 接口的 ESP32 板),具体分为以下三个步骤:

  • 配置并连接 JTAG 接口

  • 运行 OpenOCD

  • 上传待调试的应用程序

配置并连接 JTAG 接口

此步骤取决于使用的 JTAG 和 ESP32 板,请参考以下两种情况。

运行 OpenOCD

配置完目标并将其连接到电脑后,即可启动 OpenOCD。

打开终端,按照快速入门指南中的 设置好开发环境 章节进行操作,然后运行如下命令,以启动 OpenOCD(该命令适用于 Windows、Linux 和 macOS):

openocd -f board/esp32-wrover-kit-3.3v.cfg

注解

上述命令中 -f 选项后跟的配置文件专用于 板载 ESP32-WROOM-32 模组的 ESP-WROVER-KIT 开发板。基于具体使用的硬件,您可能需要选择不同的配置文件,具体内容请参阅 根据目标芯片配置 OpenOCD

例如,对于带有用于 JTAG 连接的 FT2232H 或 FT232H 芯片的定制板,或带有 ESP-Prog 的定制板,可使用 board/esp32c3-ftdi.cfg

现在您应该可以看到如下输出(此日志来自 板载 ESP32-WROOM-32 模组的 ESP-WROVER-KIT 开发板):

user-name@computer-name:~/esp/esp-idf$ openocd -f board/esp32-wrover-kit-3.3v.cfg
Open On-Chip Debugger  v0.10.0-esp32-20190708 (2019-07-08-11:04)
Licensed under GNU GPL v2
For bug reports, read
        http://openocd.org/doc/doxygen/bugs.html
none separate
adapter speed: 20000 kHz
force hard breakpoints
Info : ftdi: if you experience problems at higher adapter clocks, try the command "ftdi_tdo_sample_edge falling"
Info : clock speed 20000 kHz
Info : JTAG tap: esp32.cpu0 tap/device found: 0x120034e5 (mfg: 0x272 (Tensilica), part: 0x2003, ver: 0x1)
Info : JTAG tap: esp32.cpu1 tap/device found: 0x120034e5 (mfg: 0x272 (Tensilica), part: 0x2003, ver: 0x1)
Info : esp32: Debug controller was reset (pwrstat=0x5F, after clear 0x0F).
Info : esp32: Core was reset (pwrstat=0x5F, after clear 0x0F).
  • 如果出现指示权限问题的错误,请打开 ~/esp/openocd-esp32 目录,参阅 OpenOCD README 文件中关于 “Permissions delegation” 的说明。

  • 如果遇到无法找到配置文件的错误,例如 Can't find board/esp32-wrover-kit-3.3v.cfg,请检查 OPENOCD_SCRIPTS 环境变量是否设置正确,OpenOCD 根据此变量来查找 -f 指定的文件,详见 安装 OpenOCD。此外,还需要检查配置文件是否确实位于该路径下。

  • 如果出现 JTAG 错误(例如输出为 ...all ones...all zeroes),请检查硬件连接是否正确,除了 ESP32 的管脚之外是否还有其他信号连接到了 JTAG,并查看是否所有器件都已经上电。

上传待调试的应用程序

按照正常步骤构建并上传 ESP32 应用程序,具体请参阅 第八步:编译工程 章节。

除此以外,您还可以使用 OpenOCD 通过 JTAG 接口将应用程序镜像烧写到闪存中,命令如下:

openocd -f board/esp32-wrover-kit-3.3v.cfg -c "program_esp filename.bin 0x10000 verify exit"

其中 OpenOCD 的烧写命令 program_esp 格式如下:

program_esp <image_file> <offset> [verify] [reset] [exit]

  • image_file - 程序镜像文件存放的路径

  • offset - 镜像烧写到闪存中的偏移地址

  • verify - 烧写完成后校验闪存中的内容(可选)

  • reset - 烧写完成后重启目标(可选)

  • exit - 烧写完成后退出 OpenOCD(可选)

现在可以调试应用程序了,请按照以下章节中的步骤进行操作。

启动调试器

ESP32 的工具链中带有 GNU 调试器(简称 GDB),它和其它工具链软件共同存放于 xtensa-esp32-elf-gdb 中。除了直接在命令行终端中调用并操作 GDB 外,也可以在 IDE (例如 Eclipse、Visual Studio Code 等)中进行调用,使用图形用户界面间接操作 GDB,这一方法无需在终端中输入任何命令。

关于以上两种调试器的使用方法,详见以下链接。

建议首先检查调试器能否在 命令行终端 下正常工作,然后再使用 Eclipse 集成开发环境 进行调试工作。

调试范例

本节适用于不熟悉 GDB 的用户,下文将使用 get-started/blink 下简单的应用程序来演示 调试会话的工作流程,同时会介绍以下常用的调试操作:

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

  2. 设置和清除断点

  3. 手动暂停目标

  4. 单步执行代码

  5. 查看并设置内存

  6. 观察和设置程序变量

  7. 设置条件断点

此外还会提供在 在命令行终端进行调试 下使用 GDB 调试的案例。

在演示之前,请完成 ESP32 目标板设置并加载 get-started/blink 至 ESP32 中。

从源码构建 OpenOCD

以下文档分别介绍了如何在各操作系统平台上从源码构建 OpenOCD。

本文档在演示中所使用的 OpenOCD 是预编译好的二进制发行版,在 安装 OpenOCD 章节中有所介绍。

如果要使用本地从源代码编译的 OpenOCD 程序,需要将相应可执行文件的路径修改为 src/openocd,并设置 OPENOCD_SCRIPTS 环境变量,使得 OpenOCD 能够找到配置文件。Linux 和 macOS 用户可以执行:

cd ~/esp/openocd-esp32
export OPENOCD_SCRIPTS=$PWD/tcl

Windows 用户可以执行:

cd %USERPROFILE%\esp\openocd-esp32
set "OPENOCD_SCRIPTS=%CD%\tcl"

针对 Linux 和 macOS 用户,运行本地编译的 OpenOCD 的示例:

src/openocd -f board/esp32-wrover-kit-3.3v.cfg

Windows 用户的示例如下:

src\openocd -f board\esp32-wrover-kit-3.3v.cfg