# JTAG 调试

[English]

本文将介绍如何安装 ESP32-C2 的 OpenOCD 调试环境，以及如何使用 GDB 来调试 ESP32-C2 的应用程序。

备注

也可以使用 `idf.py monitor` 来调试 ESP32-C2，免于设置 JTAG 或 OpenOCD。请参阅 IDF 监视器 和 CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME。

本文档结构如下：

引言

  介绍本指南主旨。

工作原理

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

选择 JTAG 适配器

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

安装 OpenOCD

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

配置 ESP32-C2 目标板

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

启动调试器

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

调试范例

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

从源码构建 OpenOCD

  介绍如何在 Windows，Linux 和 macOS 操作系统上从源码构建 OpenOCD。

注意事项和补充内容

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

## 引言

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

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

备注

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

## 工作原理

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

JTAG 调试 - 概述图

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

Eclipse 环境集成了 JTAG 调试和应用程序加载、监视的功能，使得软件从编写、编译、加载到调试的迭代过程变得更加快速简单。Eclipse IDE 及其集成的调试软件均适用于 Windows、Linux 和 macOS 平台。根据用户喜好，除了使用 Eclipse 集成开发环境，还可以直接在命令行终端运行 debugger 和 idf.py build。

## 选择 JTAG 适配器

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

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

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

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

## 安装 OpenOCD

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

    openocd --version

终端会输出以下信息（实际版本号可能会更新）：

    Open On-Chip Debugger v0.12.0-esp32-20240318 (2024-03-18-18:25)
    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。

如果无法执行上述步骤，请再次阅读快速入门手册，Linux 和 macOS 用户请参考 设置安装工具 章节，Windows 用户请参考 ESP-IDF 工具安装器。

备注

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

## 配置 ESP32-C2 目标板

OpenOCD 安装完成后就可以配置 ESP32-C2 目标（即带 JTAG 接口的 ESP32-C2 板），具体分为以下三个步骤：

- 配置并连接 JTAG 接口

- 运行 OpenOCD

- 上传待调试的应用程序

### 配置并连接 JTAG 接口

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

- 配置其他 JTAG 接口

### 运行 OpenOCD

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

打开终端，按照《快速入门指南》中的 设置开发环境 章节进行操作。运行 OpenOCD 时，需要提供与目标开发板相关的配置文件。构建项目后，ESP-IDF 会生成 `build/project_description.json` 文件，其中 `debug_arguments_openocd` 字段保存了默认的 OpenOCD 配置信息。请运行如下命令，以启动 OpenOCD（该命令适用于 Windows、Linux 和 macOS）：

    openocd -f board/esp32c2-ftdi.cfg

备注

上述命令中 `-f` 选项后跟的配置文件专用于 ESP32-C2 development board with ESP-Prog。基于具体使用的硬件，你可能需要选择不同的配置文件，具体内容请参阅 根据目标芯片配置 OpenOCD。

现在应该可以看到如下输出（此日志来自 ESP32-C2 development board with ESP-Prog）:

    user-name@computer-name:~/esp/esp-idf$ openocd -f board/esp32c2-ftdi.cfg
    Open On-Chip Debugger v0.11.0-esp32-20221026 (2022-10-26-14:48)
    Licensed under GNU GPL v2
    For bug reports, read
            http://openocd.org/doc/doxygen/bugs.html
    adapter speed: 20000 kHz

    Info : Listening on port 6666 for tcl connections
    Info : Listening on port 4444 for telnet connections
    Warn : libusb_detach_kernel_driver() failed with LIBUSB_ERROR_ACCESS, trying to continue anyway
    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: esp32c2.cpu tap/device found: 0x0000cc25 (mfg: 0x612 (Espressif Systems), part: 0x000c, ver: 0x0)
    Info : datacount=2 progbufsize=16
    Info : Examined RISC-V core; found 1 harts
    Info :  hart 0: XLEN=32, misa=0x40101104
    Info : starting gdb server for esp32c2 on 3333
    Info : Listening on port 3333 for gdb connections

- 如果出现指示权限问题的错误，请打开 `~/esp/openocd-esp32` 目录，参阅 OpenOCD README 文件中关于 “Permissions delegation” 的说明。

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

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

### 上传待调试的应用程序

按照正常步骤构建并上传 ESP32-C2 应用程序，具体请参阅 第五步：开始使用 ESP-IDF 吧 章节。

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

    openocd -f board/esp32c2-ftdi.cfg -c "program_esp filename.bin 0x10000 verify exit"

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

`program_esp <image_file> <offset> [verify] [reset] [exit] [compress] [encrypt] [no_clock_boost] [restore_clock] [skip_loaded]`

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

- `offset` - 镜像烧写到 flash 中的偏移地址

- `verify` - 烧写完成后校验 flash 中的内容（可选）

- `reset` - 烧写完成后重启目标（可选）

- `exit` - 烧写完成后退出 OpenOCD（可选）

- `compress` - 烧写开始前压缩镜像文件（可选）

- `encrypt` - 烧写到 flash 前加密二进制文件，与 `idf.py encrypted-flash` 功能相同（可选）

- `no_clock_boost` - 禁用在烧写前将目标时钟频率设置为其最大可能值（可选）。默认情况下禁用该选项，即默认启用时钟提升。

- `restore_clock` - 可选。烧写完成后将时钟频率恢复到初始值。默认情况下不启用。

- `skip_loaded` - 可选。如果二进制文件已加载，则跳过烧写。默认情况下不启用。

#### 替代方法：使用 program_esp_bins

为方便 ESP-IDF 项目的使用，OpenOCD 提供了一个替代命令 `program_esp_bins`，该命令可以通过读取 ESP-IDF 构建过程中生成的 `flasher_args.json` 文件中的构建配置，在单个命令中烧写多个二进制文件。

该方法特别有用，因为：

- 它会自动从构建输出中读取所有二进制文件及其 flash 地址

- 它会根据项目配置自动处理加密分区

- 它无需手动指定每个二进制文件（引导加载程序、分区表、应用程序等）的地址

基本用法：

    openocd -f board/esp32-wrover-kit-3.3v.cfg -c "program_esp_bins build flasher_args.json verify exit"

##### 命令格式

OpenOCD 烧写命令 `program_esp_bins` 格式如下：

`program_esp_bins <build_dir> <json_file> [verify] [reset] [exit] [compress] [no_clock_boost] [restore_clock] [skip_loaded]`

> - `build_dir` - 包含 `flasher_args.json` 文件的构建目录路径。

> - `json_file` - 包含 flash 配置的 JSON 文件名称（通常为 `flasher_args.json`）。

> - 其他可选参数与 `program_esp` 命令相同。详情请参阅 上传待调试的应用程序 章节。

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

## 启动调试器

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

关于调试器的使用方法，详见以下链接。

- 使用 Eclipse 调试

- 使用命令行调试

- 使用 VS Code 调试

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

## 调试范例

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

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

2. 设置和清除断点

3. 手动暂停目标

4. 单步执行代码

5. 查看并设置内存

6. 观察和设置程序变量

7. 设置条件断点

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

备注

调试 FreeRTOS 对象 目前仅适用于命令行调试。

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

## 从源码构建 OpenOCD

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

- Windows
- Linux
- macOS

本文档在演示中所使用的 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/esp32c2-ftdi.cfg

Windows 用户的示例如下:

    src\openocd -f board/esp32c2-ftdi.cfg

## 注意事项和补充内容

本节列出了上文中提到的所有注意事项和补充内容的链接。

- 注意事项和补充内容
  - 可用的断点和观察点
  - 关于断点的补充知识
  - flash 映射 vs 软件 flash 断点
  - “next” 命令无法跳过子程序的原因
  - OpenOCD 支持的编译时的选项
  - 支持 FreeRTOS
  - 优化 JTAG 的速度
  - 调试器的启动命令的含义
  - 根据目标芯片配置 OpenOCD
  - 复位 ESP32-C2
  - JTAG 管脚是否能用于其他功能
  - JTAG 与 flash 加密和安全引导
  - 报告 OpenOCD/GDB 的问题

## 相关文档

- 使用调试器

- 调试示例

- 注意事项和补充内容

- 应用层跟踪库

- ESP-Prog 调试板介绍

提供有关此文档的反馈