OpenOCD 嵌入式调试完全指南:从零开始调试 GD32/STM32 单片机

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

解决

  1. 检查 USB 连接
  2. Linux 下可能需要 sudo:sudo openocd ...
  3. 添加 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

解决

  1. 检查 SWD 接线是否正确
  2. 检查目标板是否供电
  3. 尝试降低调试器速度:-c "adapter speed 500"
  4. 检查芯片是否处于休眠/低功耗模式

9.3 烧录失败

问题

复制代码
Error: Failed to erase flash

解决

  1. 检查芯片是否写保护
  2. 尝试先擦除:-c "flash erase_sector 0 0 last"
  3. 检查 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.elftarget remote :3333
查看寄存器 info registers
查看调用栈 backtrace
设置断点 break main
单步执行 step / next
继续运行 continue

OpenOCD 是嵌入式开发的必备工具,掌握它可以让你在没有商业 IDE 的情况下也能高效调试 MCU。

相关推荐
LCG元2 小时前
STM32实战:基于STM32F103的迷迭香智慧种植系统(自动补光+滴灌)
stm32·单片机·嵌入式硬件
SDAU200510 小时前
CH32V103C8T6的时钟操作
单片机·嵌入式硬件
不做无法实现的梦~11 小时前
SBUS 接收机到 STM32:为什么要做硬件反相、如何解析数据、如何接线与实现代码
stm32·单片机·嵌入式硬件
一路往蓝-Anbo11 小时前
第二章:隔离硬件 —— 利用 CMock 伪造 GPIO 与定时器
stm32·单片机·嵌入式硬件·软件工程·信息与通信·tdd
刘延林.12 小时前
esp32 s3+micpython快速验证ML307R 是否能正常连接4G
单片机·嵌入式硬件
不做无法实现的梦~18 小时前
86步进电机和DM860H驱动器的使用方法和记录
单片机·嵌入式硬件
Aaron158818 小时前
RFSOC+VU13P/VU9P+GPU多通道同步一体化解决方案
人工智能·嵌入式硬件·算法·matlab·fpga开发·硬件架构·基带工程
所见即所得1111119 小时前
stm32烧录过程中串口问题(串口被占用无法使用)
stm32·单片机·嵌入式硬件
Freak嵌入式19 小时前
WIZnet-EVB-Pico2开始,用MicroPython玩转以太网开发
arm开发·人工智能·python·嵌入式硬件·机器人·嵌入式·micropython