1. 为什么选择STM32F103打造CMSIS-DAP仿真器
如果你经常玩嵌入式开发,肯定对J-Link和ST-Link不陌生。但你可能不知道,ARM官方早就开源了一个更强大的调试器方案——CMSIS-DAP。这个方案最大的优势就是完全开源,没有任何版权限制,而且性能足够应付日常开发需求。
STM32F103这颗芯片被选中不是没有原因的。首先它价格便宜,淘宝上核心板只要十几块钱;其次它自带USB全速接口,正好满足CMSIS-DAP的通信需求;最重要的是它的性能足够强大,72MHz主频完全hold住调试时的数据吞吐。我实测下来,用STM32F103做的DAP仿真器下载速度比某些山寨ST-Link还要快。
市面上很多知名厂商的调试器其实都是基于CMSIS-DAP魔改的。比如正点原子的离线下载器,还有GD32的GD-Link,核心都是这套协议栈。所以自己动手做一个,不仅能省下买调试器的钱,更重要的是能深入理解ARM调试架构的工作原理。
2. 硬件设计要点解析
2.1 最小系统设计
STM32F103的最小系统其实很简单,只需要几个基本元件:
- 一颗STM32F103C8T6(建议选LQFP48封装,手工焊接方便)
- 8MHz晶振和两个22pF负载电容
- 一个32.768kHz晶振(可选,用于RTC)
- 0.1uF和10uF的电源滤波电容
- 一个USB Type-B接口(或者Micro-USB)
电源部分要特别注意,USB的5V需要经过LDO降压到3.3V。我推荐使用AMS1117-3.3,实测非常稳定。如果追求低功耗,可以换成RT9193这类低压差稳压器。
2.2 调试接口设计
CMSIS-DAP支持SWD和JTAG两种调试协议,但实际使用中SWD就足够了,只需要4根线:
- SWDIO - 数据线(建议接PB14)
- SWCLK - 时钟线(建议接PB13)
- GND - 地线
- VCC - 目标板供电(可选)
为了增加实用性,我建议再加一个复位引脚(接PB0),这样可以通过DAP直接复位目标板。原理图上记得给SWDIO和SWCLK加上上拉电阻,通常4.7kΩ就够用。
3. 固件移植实战
3.1 开发环境搭建
首先需要准备好以下工具:
- Keil MDK(建议V5.25以上版本)
- STM32CubeMX(用于生成基础工程)
- CMSIS-DAP源码(在Keil安装目录的ARM/CMSIS/DAP文件夹下)
用CubeMX新建工程时,关键配置如下:
- 时钟树配置为72MHz,USB时钟必须是48MHz
- 开启USB Device,选择Custom HID模式
- 配置SWD接口对应的GPIO
- 开启USB中断和SWD相关定时器
3.2 核心代码移植
CMSIS-DAP的源码结构很清晰,主要需要移植以下几个文件:
- DAP_config.h:硬件相关配置
- DAP.c:核心协议处理
- SW_DP.c:SWD协议实现
- USBD_User_HID_0.c:USB通信接口
在DAP_config.h中,需要根据实际硬件修改GPIO定义。比如SWDIO和SWCLK的引脚配置:
#define PIN_SWDIO_OUT() HAL_GPIO_WritePin(GPIOB, GPIO_PIN_14, GPIO_PIN_SET) #define PIN_SWDIO_IN() HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_14) #define PIN_SWCLK_OUT() HAL_GPIO_WritePin(GPIOB, GPIO_PIN_13, GPIO_PIN_SET)USB描述符的修改也很关键,要确保报告描述符与DAP协议匹配。以下是修改后的HID报告描述符:
0x06, 0x00, 0xFF, // Usage Page (Vendor Defined) 0x09, 0x01, // Usage (Vendor Usage 1) 0xA1, 0x01, // Collection (Application) 0x15, 0x00, // Logical Minimum (0) 0x25, 0xFF, // Logical Maximum (255) 0x75, 0x08, // Report Size (8) 0x95, 0x40, // Report Count (64) 0x09, 0x01, // Usage (Vendor Usage 1) 0x81, 0x02, // Input (Data,Var,Abs) 0x95, 0x40, // Report Count (64) 0x09, 0x01, // Usage (Vendor Usage 1) 0x91, 0x02, // Output (Data,Var,Abs) 0xC0 // End Collection4. 功能验证与性能优化
4.1 基础功能测试
编译完成后,先用ST-Link把固件烧录到你的DIY调试器中。第一次连接电脑时,设备管理器应该会出现"HID-compliant device"。这时候打开Keil,在Debug选项里选择CMSIS-DAP调试器。
我建议先用一个简单的LED闪烁程序做测试,重点验证以下几点:
- 下载功能是否正常
- 断点调试是否可用
- 变量监控是否正常
- 单步执行是否流畅
如果遇到识别问题,可以检查USB枚举过程。用USBlyzer这类工具查看设备描述符是否正确。
4.2 性能调优技巧
默认配置下,DAP的SWD时钟是1MHz。对于STM32F103,完全可以提高到4MHz。修改DAP_config.h中的参数:
#define DAP_DEFAULT_SWJ_CLOCK 4000000U另一个优化点是增加USB缓冲区数量,减少通信延迟:
#define DAP_PACKET_COUNT 16U #define DAP_PACKET_SIZE 64U如果要做离线下载器,还需要添加Flash编程算法。以STM32F103为例,需要实现flash_erase和flash_program等函数,可以参考Keil安装目录下的Flash算法模板。
5. 进阶功能实现
5.1 虚拟串口功能
新版CMSIS-DAP支持虚拟串口功能,非常实用。实现方法是在USB描述符中添加CDC类接口,需要修改以下几个部分:
- 在CubeMX中启用CDC类
- 修改USB描述符,添加CDC接口
- 实现CDC的收发函数
- 在DAP协议中处理串口数据
实测下来,虚拟串口的最高波特率可以达到1Mbps,完全够用于调试输出。
5.2 离线下载功能
离线下载器的核心是把待烧录的固件存储在外部Flash或SD卡中。硬件上需要添加存储介质,软件上需要实现:
- 文件系统(FatFS是不错的选择)
- 固件解析(Hex或Bin格式)
- 批量编程接口
- 状态指示灯控制
我做的版本还加入了自动增量序列号功能,非常适合产线批量生产。通过按键选择不同固件,LED灯显示烧录状态,实测烧录一块板子只需3秒。
6. 常见问题排查
在开发过程中,我踩过不少坑,这里分享几个典型问题的解决方法:
问题1:Keil无法识别调试器
- 检查USB连接是否正常
- 确认设备管理器中出现HID设备
- 查看DAP固件是否正常启动(LED指示灯状态)
问题2:下载程序失败
- 检查目标板供电是否正常
- 确认SWD连线正确(特别是GND)
- 降低SWD时钟频率试试
- 检查目标芯片是否进入睡眠模式
问题3:调试时频繁断开
- 检查USB线质量(建议用带屏蔽的短线)
- 增加USB缓冲区大小
- 降低调试信息输出频率
如果遇到特别棘手的问题,可以尝试用逻辑分析仪抓取SWD波形,看看是哪个环节出了问题。我常用的采样率是16MHz,足够分析SWD协议。
7. 项目优化与扩展
完成基本功能后,可以考虑以下几个优化方向:
外壳设计用3D打印做个精致的外壳,可以参考J-Link的造型。我用的ABS材料,厚度1.5mm,既轻便又结实。
固件升级通过DFU模式实现固件升级,这样后续功能更新更方便。STM32自带DFU bootloader,只需要在代码中实现USB DFU类即可。
多协议支持除了SWD,还可以加入JTAG支持。虽然现在用JTAG的人越来越少,但有些老芯片还是需要的。硬件上只需要多接几根线,软件上要修改DAP协议处理部分。
性能测试用不同型号的ARM芯片测试下载速度,建立性能基准。我测试的结果是,对于STM32F4系列,1MB的固件大约需要8秒,比某些商业调试器还要快。