第三章 OpenOCD配置文件结构:接口、目标、板级与CFI闪存
好,咱们进入第三章。这一章我打算把OpenOCD的配置文件结构彻底讲透。很多初学者拿到OpenOCD,第一反应就是找个现成的配置文件,改两下就跑。结果呢?连不上、报错、不知道哪里出了问题。
我个人习惯是,先搞清楚OpenOCD到底在加载什么。说白了,它的配置文件就四大块:接口配置、目标配置、板级配置,还有CFI闪存配置。咱们一个一个来拆。
核心观点:OpenOCD的配置文件不是随便拼凑的,它遵循严格的层级结构。理解这个结构,你才能写出稳定可靠的调试环境。
3.1 接口配置文件(interface)
接口配置文件,顾名思义,就是告诉OpenOCD你用的是哪种调试器。是J-Link?ST-Link?还是FT2232自己做的调试器?
我记得刚入行那会儿,公司有个项目用的是FT2232H做的调试器,结果我拿了个ST-Link的配置去跑,折腾了一下午没连上。后来才发现,接口配置错了,JTAG信号根本对不上。
接口配置文件里主要定义这几样东西:
- 传输协议:JTAG还是SWD?现在ARM芯片基本都用SWD,但老一些的芯片还是JTAG。
- 适配器驱动:比如
ftdi、jlink、stlink等。 - 信号映射:TDI、TDO、TCK、TMS这些引脚怎么接的。
- 速度设置:
adapter speed命令,单位是kHz。
我的经验:速度别一上来就设太高。我一般先设1000kHz,能连上再慢慢往上加。有些板子布线不好,高频下信号反射严重,反而连不上。
来看一个典型的FTDI接口配置:
# interface/ftdi.cfg
adapter driver ftdi
ftdi vid_pid 0x0403 0x6010
ftdi layout_init 0x0018 0x001b
ftdi layout_signal nTRST -data 0x0010
ftdi layout_signal nSRST -data 0x0020
adapter speed 1000
transport select jtag
这里 ftdi layout_init 后面两个十六进制数,分别对应GPIO的初始状态和方向。我第一次看到这个也是一脸懵,后来查了FT2232H的数据手册才搞明白。说白了,就是告诉OpenOCD哪些引脚是输出,哪些是输入,初始电平是什么。
3.2 目标配置文件(target)
目标配置文件定义的是你调试的芯片内核。是Cortex-M3?M4?还是RISC-V?不同的内核,调试逻辑不一样。
目标配置文件里最重要的几个命令:
| 命令 | 作用 | 示例 |
|---|---|---|
set CHIPNAME |
定义芯片名称 | set CHIPNAME stm32f4 |
set ENDIAN |
设置字节序 | set ENDIAN little |
target create |
创建目标 | target create $_TARGETNAME cortex_m -endian $_ENDIAN -chain-position $_CHIPNAME.cpu |
$_TARGETNAME configure |
配置目标参数 | $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size 0x10000 |
我曾经遇到过一个坑:有个客户用的芯片是Cortex-M0,但我配置里写的是cortex_m3。结果OpenOCD能连上,但单步调试时总跳飞。后来查了半天,发现是内核类型写错了。M0和M3的调试逻辑有细微差别,不能混用。
来看一个STM32F4的目标配置:
# target/stm32f4x.cfg
set CHIPNAME stm32f4
set ENDIAN little
if { [info exists CHIPNAME] } {
set _CHIPNAME $CHIPNAME
} else {
set _CHIPNAME stm32f4
}
if { [info exists ENDIAN] } {
set _ENDIAN $ENDIAN
} else {
set _ENDIAN little
}
# 创建目标
target create $_CHIPNAME.cpu cortex_m -endian $_ENDIAN -chain-position $_CHIPNAME.cpu
# 配置工作区
$_CHIPNAME.cpu configure -work-area-phys 0x20000000 -work-area-size 0x10000
# 配置复位
$_CHIPNAME.cpu configure -event reset-init {
# 初始化代码
}
注意:工作区地址一定要选对。我见过有人把工作区设在Flash地址上,结果调试时写数据把程序给覆盖了。工作区一般用SRAM,比如STM32F4就是0x20000000开始的。
3.3 板级配置文件(board)
板级配置文件,说白了就是把接口配置和目标配置整合到一起,再加上板子特有的东西,比如外部Flash、LED、按键这些。
我个人习惯是,如果只是调试核心板,直接用接口+目标两个文件就够了。但如果是完整的开发板,最好用板级配置文件,因为它能帮你把板子上的外设都初始化好。
板级配置文件里常见的内容:
- source命令:引用接口和目标配置文件
- 复位配置:比如使用硬件复位还是软件复位
- Flash配置:内部Flash或外部Flash的编程算法
- 板级初始化:比如配置时钟、GPIO等
来看一个STM32F4 Discovery板的配置:
# board/stm32f4discovery.cfg
source [find interface/stlink-v2.cfg]
source [find target/stm32f4x.cfg]
# 复位配置
reset_config srst_only srst_nogate
# 内部Flash配置
flash bank $_CHIPNAME.flash stm32f2x 0x08000000 0x1000000 0 0 $_CHIPNAME.cpu
# 板级初始化
$_CHIPNAME.cpu configure -event reset-init {
# 使能HSE时钟
mww 0x40023800 0x00000180
# 配置GPIO
mww 0x40023830 0x00000004
}
这里有个细节:reset_config srst_only srst_nogate 是什么意思?我曾经也困惑过。srst_only表示只用系统复位,不用JTAG复位。srst_nogate表示复位信号不经过门控,直接拉低。不同的板子,复位电路设计不一样,这个配置得根据实际硬件来。
3.4 CFI闪存配置
CFI(Common Flash Interface)是NOR Flash的一种标准接口。如果你的板子上有外部NOR Flash,就需要配置CFI。
说实话,现在用NOR Flash的项目不多了,大部分都用NAND或者eMMC。但有些工业控制板、通信设备还在用NOR Flash,因为它的可靠性高、读取速度快。
CFI配置的核心命令是 flash bank:
# CFI NOR Flash配置示例
flash bank cfi_flash cfi 0x60000000 0x2000000 2 4 $_TARGETNAME
参数说明:
| 参数 | 含义 | 示例值 |
|---|---|---|
| bank名称 | Flash bank的名字 | cfi_flash |
| 驱动类型 | 固定为cfi | cfi |
| 基地址 | Flash在内存中的映射地址 | 0x60000000 |
| 大小 | Flash的总大小(字节) | 0x2000000(32MB) |
| 总线宽度 | 数据总线宽度(字节) | 2(16位) |
| 页大小 | 编程页大小(KB) | 4 |
| 目标 | 关联的目标 | $_TARGETNAME |
避坑指南:我曾经在一个项目里,CFI Flash怎么都擦除不了。后来用逻辑分析仪抓波形,发现是总线宽度配错了。芯片是16位的,我配成了8位。OpenOCD发出去的地址和命令都不对,Flash当然不响应。
CFI配置还有一个好处:OpenOCD会自动读取Flash的CFI信息,验证配置是否正确。如果基地址或总线宽度不对,OpenOCD会报错:
Error: CFI query failed at 0x60000000
Error: auto_probe failed
看到这个错误,先检查基地址和总线宽度。我一般会先读一下芯片手册,确认Flash的映射地址和总线宽度,再填到配置里。
3.5 配置文件的加载顺序
最后说一个容易忽略的点:配置文件的加载顺序。
OpenOCD加载配置文件的顺序是:接口 → 目标 → 板级 → CFI。这个顺序不能乱,因为后面的配置可能依赖前面的。
比如板级配置文件里 source 了接口和目标文件,那它就必须在最后加载。如果你先加载板级文件,再加载接口文件,OpenOCD会报错说找不到适配器。
正确的启动命令:
openocd -f interface/stlink-v2.cfg -f target/stm32f4x.cfg -f board/stm32f4discovery.cfg
或者直接用板级文件,它会自动引用接口和目标:
openocd -f board/stm32f4discovery.cfg
总结一下:接口配置管硬件连接,目标配置管芯片内核,板级配置管板子整合,CFI配置管外部Flash。四者各司其职,组合起来就是一个完整的调试环境。