3、调试环境搭建:JTAG/SWD调试器选型、OpenOCD配置实战、GDB连接目标板
调试环境,说白了就是你和硬件之间的「翻译官」。没有它,你只能靠LED闪烁猜问题,有了它,你能直接看到CPU在干什么。这一节,我把自己这些年踩过的坑、积累的经验都倒出来,帮你把调试环境一次搭好。
3.1 调试器选型:JTAG vs SWD,别选错了
先搞清楚一个基本概念:JTAG和SWD是两种不同的调试协议。JTAG用了5根线(TMS、TCK、TDI、TDO、nTRST),SWD只需要2根(SWDIO、SWCLK)。
我个人习惯,只要目标芯片支持SWD,我就优先用SWD。为什么?
- 引脚少:2根线就能搞定,PCB布线省事
- 速度快:SWD在高速模式下比JTAG更稳定
- 兼容性好:大部分Cortex-M系列都支持
但有一种情况你必须用JTAG——调试FPGA或者某些老旧的ARM7/ARM9芯片。我在项目中遇到过一块NXP的LPC2378,死活连不上SWD,最后翻数据手册才发现它只支持JTAG。
调试器选型速查表
| 调试器型号 | 支持协议 | 最高速度 | 适用场景 |
|---|---|---|---|
| J-Link EDU | JTAG/SWD | 15 MHz | 个人学习、小项目 |
| ST-Link/V2 | SWD | 4 MHz | STM32系列专用 |
| CMSIS-DAP | SWD | 10 MHz | 开源方案,性价比高 |
| FT2232H | JTAG/SWD | 30 MHz | FPGA调试、高速场景 |
我的建议:如果你刚开始做Bootloader开发,买个J-Link EDU或者CMSIS-DAP就够了。别一上来就上几千块的调试器,没必要。
3.2 OpenOCD配置实战:从零开始
OpenOCD是个好东西,但配置起来确实有点绕。我第一次用的时候,光看文档就看了半天,最后还是靠试错才跑起来。
先装好OpenOCD。Linux下直接apt-get,Windows下下载预编译包。装好后,你需要两个配置文件:一个是接口配置文件(告诉OpenOCD你用的什么调试器),一个是目标配置文件(告诉OpenOCD你调试的是什么芯片)。
3.2.1 接口配置文件
以我常用的CMSIS-DAP为例,创建一个 cmsis-dap.cfg:
# 接口配置:CMSIS-DAP
adapter driver cmsis-dap
transport select swd
adapter speed 1000 # 1 MHz,稳定第一
这里有个坑:速度别设太高。我曾经图快设了10 MHz,结果调试器动不动就断开连接。后来老老实实降到1 MHz,稳如老狗。
3.2.2 目标配置文件
以STM32F407为例,创建 stm32f407.cfg:
# 目标配置:STM32F407
source [find target/stm32f4x.cfg]
# 设置复位方式
reset_config srst_only srst_nogate
# 配置Flash写入参数
set FLASH_SIZE 0x100000 # 1MB
set WORKAREASIZE 0x10000 # 64KB
注意:复位配置一定要和硬件匹配。如果你的板子上没有硬件复位引脚,就别用 srst_only,否则OpenOCD会一直报错。
3.2.3 启动OpenOCD
把两个配置文件放在同一个目录下,然后执行:
openocd -f cmsis-dap.cfg -f stm32f407.cfg
看到 Info : Listening on port 3333 for gdb connections 就说明成功了。嗯,这里要注意,如果卡在 Error: unable to find a matching CMSIS-DAP device,八成是驱动没装好,或者USB线有问题。
3.3 GDB连接目标板:真正开始调试
OpenOCD跑起来之后,GDB连接就简单了。打开另一个终端,输入:
arm-none-eabi-gdb your_bootloader.elf
(gdb) target remote localhost:3333
(gdb) monitor reset halt
(gdb) load
(gdb) continue
这几条命令的意思:
target remote:连接到OpenOCD监听的3333端口monitor reset halt:复位并暂停CPUload:把固件烧进去continue:开始运行
我个人习惯在GDB里加一个 .gdbinit 文件,省得每次敲一堆命令:
# .gdbinit
target remote localhost:3333
monitor reset halt
load
break main
continue
这样每次启动GDB,它自动连上、烧录、停在main函数入口。省事多了。
调试常用GDB命令
| 命令 | 作用 | 我常用的场景 |
|---|---|---|
| break *0x08000000 | 在指定地址设断点 | 检查Bootloader入口是否跳转正确 |
| info registers | 查看寄存器值 | 检查PC指针是否跑飞 |
| monitor flash write_image | 直接写Flash | 绕过Bootloader烧录测试 |
| x/16x 0x20000000 | 查看内存内容 | 检查RAM里的数据对不对 |
3.4 避坑指南:我踩过的那些雷
调试环境搭建看起来简单,但实际操作中问题不少。我把自己遇到过的典型问题列出来,你遇到了可以直接对照排查。
- 连接不上目标板:先检查接线,SWDIO和SWCLK有没有接反。我犯过这种低级错误,查了半小时才发现。
- OpenOCD报错 "no device found":八成是驱动问题。Windows下用Zadig工具把调试器驱动换成WinUSB。
- GDB连上后一运行就死:检查复位配置。有些板子需要
reset_config trst_and_srst。 - 烧录速度极慢:把
adapter speed调高一点,但别超过芯片支持的上限。
一个小技巧:如果你用的是J-Link,可以用 JLinkExe 先测试一下连接是否正常。输入 connect,选好芯片型号,如果能识别到IDCODE,说明硬件没问题。
调试环境搭好了,后面的事情就顺了。下一节我们会讲如何用这个环境去定位Bootloader中的典型异常——比如跳转失败、看门狗复位、Flash写入错误。到时候你会发现,今天花时间搭环境,绝对值。