4. OpenOCD 安装与配置:Windows/Linux/macOS 下的实战准备
OpenOCD 这个工具,说白了就是咱们调试 ARM 芯片的“翻译官”。它把 GDB 的调试命令,翻译成 JTAG/SWD 协议能听懂的电信号。我刚开始用的时候,光安装就折腾了半天,后来发现其实就是几个关键点没搞明白。这一章,咱们就把安装和配置彻底说清楚。
4.1 跨平台安装:三种系统,一个套路
OpenOCD 的安装方式,不同系统差别挺大。我个人的习惯是:能用包管理器就别自己编译,除非你要改源码。
Windows 安装
Windows 下最简单的方式是下载预编译的二进制包。我推荐去 Sysprogs 或者 GNU MCU Eclipse 的页面下载。注意,别下错了版本,要选带 -win32 或 -win64 的。
- 解压到
C:\openocd这样的路径(别带中文和空格)。 - 把
C:\openocd\bin添加到系统环境变量PATH里。 - 打开 CMD,输入
openocd --version,看到版本号就说明成了。
zadig.exe 这个工具就能搞定。
Linux 安装
Linux 就省心多了。Ubuntu/Debian 系直接:
sudo apt-get install openocd
Fedora/RHEL 系:
sudo dnf install openocd
Arch Linux:
sudo pacman -S openocd
不过要注意,系统源里的版本可能比较老。如果你需要最新的功能(比如支持 RISC-V),那就得自己编译了。我个人建议,生产环境用源码编译,开发环境用包管理器,省时间。
macOS 安装
macOS 用 Homebrew 最方便:
brew install openocd
如果你用的是 M1/M2 芯片的 Mac,记得确认 Homebrew 是 ARM 版本的。我有个同事没注意这个,装完发现跑的是 x86 模拟模式,性能差了不少。
openocd --list-interfaces 和 openocd --list-targets,看看支持的调试器和芯片列表。这能帮你确认安装是否完整。
4.2 配置文件结构:OpenOCD 的“灵魂”
OpenOCD 的配置文件,其实就是 TCL 脚本。你想想看,它要驱动不同的调试器,连接不同的芯片,没有一套灵活的配置机制怎么行?
配置文件的结构,我总结成一句话:先配接口(interface),再配目标(target),最后配板级(board)。
你看这个图,OpenOCD 启动时,会先读主配置文件(通常是 openocd.cfg),然后通过 source 命令加载接口配置和目标配置。最后,板级配置会把它们整合在一起。
4.3 interface 配置:告诉 OpenOCD 你用啥调试器
接口配置,就是告诉 OpenOCD 你的调试器是什么型号,用哪种协议(JTAG 还是 SWD),以及怎么跟它通信。
常见的接口配置片段长这样:
# 使用 FTDI 调试器
interface ftdi
ftdi_vid_pid 0x0403 0x6010
ftdi_layout_init 0x0018 0x001b
ftdi_layout_signal nTRST -data 0x0010
ftdi_layout_signal nSRST -data 0x0020
# 或者用 J-Link
interface jlink
jlink_serial 123456789
transport select swd
这里有几个关键点:
- interface:指定驱动类型,常见的有
ftdi、jlink、stlink、cmsis-dap。 - vid_pid:USB 设备的 VID 和 PID。我遇到过好几次,淘宝买的便宜调试器 VID/PID 跟标准的不一样,得用
lsusb查一下再填。 - transport:选择
jtag还是swd。SWD 只需要两根线,适合引脚少的板子。
tcl/interface/ 目录里找个类似的改,别从零开始写。
4.4 target 配置:告诉 OpenOCD 你调试啥芯片
目标配置,就是告诉 OpenOCD 芯片的内核类型、内存映射、复位方式等。这部分最复杂,也最容易出错。
以 STM32F407 为例,target 配置的核心部分:
# 选择内核
set CHIPNAME stm32f4x
set ENDIAN little
# 创建目标
target create $_CHIPNAME.cpu cortex_m -endian $_ENDIAN -chain-position $_CHIPNAME.dap
# 配置工作区(用于下载算法)
$_CHIPNAME.cpu configure -work-area-phys 0x20000000 -work-area-size 0x10000
# 配置复位方式
reset_config srst_only srst_nogate
# 配置 Flash 支持
flash bank $_CHIPNAME.flash stm32f2x 0x08000000 0x1000000 2 4 $_CHIPNAME.cpu
这里我解释几个容易懵的参数:
| 参数 | 含义 | 常见坑 |
|---|---|---|
cortex_m |
内核类型,M3/M4/M7 都用这个 | 如果是 Cortex-A 系列,得用 cortex_a |
-chain-position |
JTAG 链上的位置 | 多核芯片这里容易搞错,我曾经调 i.MX6 时在这卡了两天 |
work-area |
下载算法用的 RAM 区域 | 大小别设太大,留点给程序本身用 |
flash bank |
Flash 控制器类型和地址 | 不同系列的 Flash 驱动不一样,比如 STM32F1 用 stm32f1x |
tcl/target/ 目录里复制一个最接近的改。
4.5 实战:从零写一个完整的配置文件
光说不练假把式。咱们以 STM32F103C8T6 + J-Link 为例,写一个完整的配置:
# openocd.cfg
# 接口配置
source [find interface/jlink.cfg]
transport select swd
# 目标配置
source [find target/stm32f1x.cfg]
# 板级配置(可选)
# 这里可以加一些板子特有的初始化,比如使能某个 GPIO
# init_board 过程会在目标创建后自动调用
# 速度配置
adapter speed 4000
# 复位配置
reset_config srst_only
启动命令也很简单:
openocd -f openocd.cfg
如果一切正常,你会看到类似这样的输出:
Info : Listening on port 3333 for gdb connections
Info : Listening on port 6666 for tcl connections
Info : Listening on port 4444 for telnet connections
看到这三个端口,就说明 OpenOCD 已经跑起来了。这时候你可以用 GDB 连上去,开始真正的调试工作。
-d 3 参数打开调试日志:openocd -f openocd.cfg -d 3。日志里会告诉你哪一步出错了,是找不到调试器,还是 JTAG 链扫描失败。我 90% 的问题都是靠这个解决的。