OpenOCD 嵌入式调试完全指南:从零开始调试 GD32/STM32 单片机
本文档详细介绍 OpenOCD 的功能、使用方法及实际调试流程,适合首次接触嵌入式调试的开发者。
一、OpenOCD 是什么?
OpenOCD(Open On-Chip Debugger)是一个开源的片上调试工具,用于通过 JTAG/SWD 接口调试嵌入式微控制器。
1.1 它能做什么?
| 功能 | 说明 |
|---|---|
| 烧录固件 | 将编译好的 ELF/HEX/BIN 文件写入芯片 Flash |
| 在线调试 | 配合 GDB 实现断点、单步、查看寄存器、查看内存等 |
| 擦除 Flash | 擦除芯片 Flash 内容 |
| 读取寄存器 | 查看 CPU 寄存器、外设寄存器状态 |
| 内存读写 | 直接读写芯片 RAM/Flash 内容 |
| 实时查看 | 连接目标芯片,实时监控运行状态 |
1.2 什么时候用它?
| 场景 | 说明 |
|---|---|
| 首次烧录程序 | 将编译好的固件烧录到芯片中 |
| 程序不运行 | 查看程序卡在哪里,分析寄存器状态 |
| 硬件异常 | 查看是否触发了 HardFault,分析原因 |
| 内存泄漏 | 查看内存使用情况 |
| 调试中断问题 | 查看中断向量表、中断优先级配置 |
1.3 与 Keil/IAR 的区别
| 特性 | Keil/IAR | OpenOCD + GDB |
|---|---|---|
| 价格 | 商业软件(昂贵) | 完全免费开源 |
| 平台 | Windows 为主 | Linux/Windows/macOS |
| 芯片支持 | 特定芯片 | 几乎所有 ARM MCU |
| 调试方式 | IDE 集成 | 命令行 + GDB |
| CI/CD | 难集成 | 易于自动化 |
二、硬件准备
2.1 所需设备
| 设备 | 说明 |
|---|---|
| 目标开发板 | GD32F470ZGT6(或 STM32F4xx 系列) |
| 调试器 | CMSIS-DAP 调试器(推荐)、J-Link、ST-Link |
| 连接线 | SWD 接线:GND、3.3V、SWDIO、SWCLK |
| USB 线 | 连接调试器到电脑 |
2.2 接线方式(SWD 模式)
调试器 (CMSIS-DAP) 开发板 (GD32F470)
┌─────────────┐ ┌─────────────┐
│ GND │────────────│ GND │
│ 3.3V │────────────│ 3.3V │ (可选,开发板有电源时不接)
│ SWDIO │────────────│ PA13/SWDIO │
│ SWCLK │────────────│ PA14/SWCLK │
│ RST │────────────│ NRST │ (可选)
└─────────────┘ └─────────────┘
2.3 JTAG 模式(备选)
调试器 开发板
┌─────────────┐ ┌─────────────┐
│ GND │──────────│ GND │
│ TCK │──────────│ TCK │
│ TMS │──────────│ TMS │
│ TDI │──────────│ TDI │
│ TDO │──────────│ TDO │
│ nRST │──────────│ NRST │
└─────────────┘ └─────────────┘
三、安装 OpenOCD
3.1 Linux (Ubuntu/Debian)
bash
sudo apt update
sudo apt install openocd
3.2 Windows
方法 1:MSYS2
bash
# 安装 MSYS2
pacman -S mingw-w64-x86_64-openocd
方法 2:预编译包
从 OpenOCD 官网 下载 Windows 版本,解压后添加到 PATH。
3.3 macOS
bash
brew install open-ocd
3.4 验证安装
bash
openocd --version
输出示例:
Open On-Chip Debugger 0.11.0
四、首次连接调试器
4.1 连接调试器
将 CMSIS-DAP 调试器通过 USB 连接到电脑。
4.2 检查设备识别
Linux:
bash
# 查看 USB 设备
lsusb | grep -i cmsis
输出示例:
Bus 001 Device 005: ID 0d28:0204 OpenTech CMSIS-DAP
Windows:
使用 Zadig 工具安装 WinUSB 驱动(如果系统未自动识别)。
4.3 测试连接
bash
# Linux
openocd -f interface/cmsis-dap.cfg -c "exit"
# 如果设备名不匹配
openocd -f interface/cmsis-dap.cfg -c "adapter speed 1000" -c "exit"
成功连接输出:
Info : CMSIS-DAP: SWD supported
Info : CMSIS-DAP: Atomic commands supported
Info : CMSIS-DAP: Test domain timer supported
Info : CMSIS-DAP: FW Version = 2.1.0
Info : SWCLK/TCK = 1 SWDIO/TMS = 1
Info : clock speed 1000 kHz
Info : cmsis-dap: hardware revision 0
五、烧录固件(最常用的功能)
5.1 准备工作
假设你已经编译好了 ELF 文件:
build/gd32f470-template.elf
5.2 一键烧录命令
bash
openocd -f interface/cmsis-dap.cfg -f target/gd32f4xx.cfg \
-c "program build/gd32f470-template.elf verify reset exit"
命令解析:
| 参数 | 说明 |
|---|---|
-f interface/cmsis-dap.cfg |
指定调试器类型 |
-f target/gd32f4xx.cfg |
指定目标芯片 |
program |
烧录指定的 ELF 文件 |
verify |
烧录后验证内容是否正确 |
reset |
烧录完成后复位芯片 |
exit |
烧录完成后退出 OpenOCD |
5.3 烧录 BIN/HEX 文件
bash
# 烧录 BIN 文件(需要指定起始地址)
openocd -f interface/cmsis-dap.cfg -f target/gd32f4xx.cfg \
-c "program build/gd32f470-template.bin 0x08000000 verify reset exit"
# 烧录 HEX 文件
openocd -f interface/cmsis-dap.cfg -f target/gd32f4xx.cfg \
-c "program build/gd32f470-template.hex verify reset exit"
5.4 完整烧录脚本
创建一个 flash.sh 脚本:
bash
#!/bin/bash
# flash.sh - 一键烧录脚本
ELF_FILE="build/gd32f470-template.elf"
if [ ! -f "$ELF_FILE" ]; then
echo "Error: ELF file not found: $ELF_FILE"
echo "Please compile first: make"
exit 1
fi
echo "=== Flashing firmware ==="
openocd -f interface/cmsis-dap.cfg -f target/gd32f4xx.cfg \
-c "program $ELF_FILE verify reset exit" 2>&1 | grep -E "Info|Error|Verified"
echo "=== Done ==="
使用:
bash
chmod +x flash.sh
sudo ./flash.sh
5.5 烧录成功输出示例
Info : flash size probed value 2048
Info : GD32 flash has 2 sectors of 16K, 4 sectors of 64K, 1 sectors of 128K, 2 sectors of 256K
** Programming Started **
Info : device id = 0x12345678
Info : flash size = 2048 KiB
** Programming Finished **
** Verify Started **
** Verified OK **
** Resetting Target **
六、在线调试(进阶功能)
6.1 启动 OpenOCD GDB Server
bash
openocd -f interface/cmsis-dap.cfg -f target/gd32f4xx.cfg
此时 OpenOCD 会在 3333 端口 启动 GDB Server,终端会显示:
Info : Listening on port 3333 for gdb connections
Info : Listening on port 6666 for tcl connections
Info : Listening on port 4444 for telnet connections
不要关闭这个终端! 它现在是调试服务器。
6.2 连接 GDB 调试器
打开新终端,进入工程目录:
bash
arm-none-eabi-gdb build/gd32f470-template.elf
进入 GDB 后:
gdb
# 连接到 OpenOCD
(gdb) target remote :3333
# 复位并暂停
(gdb) monitor reset halt
# 查看 CPU 寄存器
(gdb) info registers
# 查看当前执行位置
(gdb) info frame
# 查看内存内容
(gdb) x/16x 0x20000000
# 设置断点
(gdb) break main
# 继续运行
(gdb) continue
# 单步执行
(gdb) step
(gdb) next
# 查看函数调用栈
(gdb) backtrace
# 退出
(gdb) quit
6.3 常用 GDB 命令速查
| 命令 | 缩写 | 说明 |
|---|---|---|
target remote :3333 |
- | 连接 OpenOCD |
break main |
b main |
在 main 函数设置断点 |
break main.c:50 |
b main.c:50 |
在指定行设置断点 |
continue |
c |
继续运行 |
step |
s |
单步步入 |
next |
n |
单步步过 |
finish |
fin |
执行完当前函数 |
print var |
p var |
打印变量值 |
display var |
disp var |
每次暂停时自动显示变量 |
info registers |
info reg |
查看所有寄存器 |
info breakpoints |
info b |
查看所有断点 |
delete 1 |
del 1 |
删除 1 号断点 |
x/16x addr |
- | 查看内存 16 个字 |
backtrace |
bt |
查看调用栈 |
quit |
q |
退出 GDB |
七、实用调试技巧
7.1 查看程序卡在哪里
程序烧录后不运行,想看卡在哪里:
bash
# 终端 1:启动 OpenOCD
openocd -f interface/cmsis-dap.cfg -f target/gd32f4xx.cfg
# 终端 2:连接 GDB
arm-none-eabi-gdb build/gd32f470-template.elf
(gdb) target remote :3333
(gdb) monitor reset halt
(gdb) info registers pc
(gdb) info registers sp
(gdb) list *$pc
list *$pc 会显示当前 PC(程序计数器)指向的代码行。
7.2 查看 HardFault 原因
程序进入 HardFault 中断,分析原因:
gdb
# 在 HardFault 处设置断点
(gdb) break HardFault_Handler
# 运行到 HardFault
(gdb) continue
# 查看 HardFault 状态寄存器
(gdb) p/x *(unsigned int*)0xE000ED28
(gdb) p/x *(unsigned int*)0xE000ED2C
(gdb) p/x *(unsigned int*)0xE000ED30
# 查看栈信息
(gdb) info registers sp
(gdb) x/32x $sp
7.3 查看和修改 Flash 内容
gdb
# 查看 Flash 起始地址内容
(gdb) x/32x 0x08000000
# 查看向量表
(gdb) x/16x 0x08000000
# 修改内存(谨慎使用!)
(gdb) set *(unsigned int*)0x20000000 = 0x12345678
7.4 Telnet 控制台
OpenOCD 提供 Telnet 接口(端口 4444),可以直接发送命令:
bash
telnet localhost 4444
> reset halt
> mdw 0x20000000 16
> reg
> flash info 0
> exit
八、不同芯片的目标配置文件
8.1 GD32 系列
| 芯片系列 | 配置文件 |
|---|---|
| GD32F4xx | target/gd32f4xx.cfg |
| GD32F3xx | target/gd32f3x.cfg |
| GD32F1xx | target/stm32f1x.cfg (兼容) |
8.2 STM32 系列
| 芯片系列 | 配置文件 |
|---|---|
| STM32F4xx | target/stm32f4x.cfg |
| STM32F1xx | target/stm32f1x.cfg |
| STM32H7xx | target/stm32h7x.cfg |
8.3 其他 ARM MCU
| 芯片 | 配置文件 |
|---|---|
| NXP LPC | target/lpc2000.cfg |
| TI Tiva | target/ti-cm4.cfg |
| Raspberry Pi Pico | target/rp2040.cfg |
九、常见问题排查
9.1 找不到调试器
问题:
Error: unable to find CMSIS-DAP device
解决:
- 检查 USB 连接
- Linux 下可能需要 sudo:
sudo openocd ... - 添加 udev 规则:
bash
# /etc/udev/rules.d/99-cmsis-dap.rules
SUBSYSTEM=="usb", ATTR{idVendor}=="0d28", ATTR{idProduct}=="0204", MODE="0666"
bash
sudo udevadm control --reload-rules
sudo udevadm trigger
9.2 连接目标芯片失败
问题:
Error: Could not initialize the debug port
解决:
- 检查 SWD 接线是否正确
- 检查目标板是否供电
- 尝试降低调试器速度:
-c "adapter speed 500" - 检查芯片是否处于休眠/低功耗模式
9.3 烧录失败
问题:
Error: Failed to erase flash
解决:
- 检查芯片是否写保护
- 尝试先擦除:
-c "flash erase_sector 0 0 last" - 检查 Flash 地址是否正确
9.4 烧录后程序不运行
问题:烧录成功但 LED 不亮,程序不运行
解决:
gdb
# 连接 GDB 查看程序状态
arm-none-eabi-gdb build/gd32f470-template.elf
(gdb) target remote :3333
(gdb) monitor reset halt
(gdb) info registers pc
(gdb) list *$pc
十、进阶配置
10.1 自定义 OpenOCD 配置
创建自定义配置文件 my_board.cfg:
tcl
# 调试器配置
source [find interface/cmsis-dap.cfg]
# 调试器速度
adapter speed 2000
# 目标芯片配置
source [find target/gd32f4xx.cfg]
# 启用硬件断点
set WORKAREASIZE 0x10000
# 复位配置
reset_config srst_only srst_nogate connect_assert_srst
使用:
bash
openocd -f my_board.cfg
10.2 VS Code 集成
安装 Cortex-Debug 插件,配置 .vscode/launch.json:
json
{
"version": "0.2.0",
"configurations": [
{
"name": "Cortex Debug",
"cwd": "${workspaceFolder}",
"executable": "build/gd32f470-template.elf",
"request": "launch",
"type": "cortex-debug",
"runToEntryPoint": "main",
"servertype": "openocd",
"configFiles": [
"interface/cmsis-dap.cfg",
"target/gd32f4xx.cfg"
],
"gdbPath": "arm-none-eabi-gdb"
}
]
}
10.3 自动化烧录与调试
创建 Makefile 目标:
makefile
flash:
openocd -f interface/cmsis-dap.cfg -f target/gd32f4xx.cfg \
-c "program build/gd32f470-template.elf verify reset exit"
debug:
openocd -f interface/cmsis-dap.cfg -f target/gd32f4xx.cfg &
sleep 2
arm-none-eabi-gdb build/gd32f470-template.elf \
-ex "target remote :3333" \
-ex "monitor reset halt" \
-ex "break main" \
-ex "continue"
使用:
bash
make flash
make debug
十一、总结
| 任务 | 命令 |
|---|---|
| 烧录固件 | openocd -f interface/cmsis-dap.cfg -f target/gd32f4xx.cfg -c "program xxx.elf verify reset exit" |
| 启动调试服务器 | openocd -f interface/cmsis-dap.cfg -f target/gd32f4xx.cfg |
| 连接 GDB | arm-none-eabi-gdb xxx.elf → target remote :3333 |
| 查看寄存器 | info registers |
| 查看调用栈 | backtrace |
| 设置断点 | break main |
| 单步执行 | step / next |
| 继续运行 | continue |
OpenOCD 是嵌入式开发的必备工具,掌握它可以让你在没有商业 IDE 的情况下也能高效调试 MCU。