3月18日注:修改USB最大包长度到1024(HS支持),USB初始化前增加等待100ms。
CMSIS-DAP Debugger 是 ARM 发布的面向 Cortex 系列 MCU 的开源(Apache 2.0协议)JTAG 与 SWD 调试器,现已被 Keil MDK 和 IAR EWARM 等 IDE 支持,用于包括主流的 STM32、NXP LPC、Freescale 等在内的多种 MCU 的程序下载与调试。
这里介绍一下 CMSIS-DAP 1.10 在 STM32F 上实现的高速 USB 2.0 调试器。
实际上这货还可以在 ARM DS-5 上调试 Cortex-A,不过这个超出本文讨论范围。
Keil MDK 工程和源代码(不包括 CMSIS 库已有部分)已上传至
https://code.csdn.net/K_O_Carnivist/cmsis_dap_stm32_hs/
用了 STM32F405RGT6。理论上只要支持 MDK Middleware 的、带 USB 的单片机都可以,包括更便宜的 STM32F205。
原理图省略了一些退耦电容。
STM32 与 USB3300 常规连接,公用一个 24MHz 晶振。几个 74LV1T125 做电平转换,其中 SWDIO/TMS 信号用 3 个引脚分别控制输入、输出和方向。
Keil MDK 5.17,需要 Pro License;
安装了如下 Software Pack:
Keil::STM32F4xx_DFP 2.6.0
Keil::MDK-Middleware 7.0.0
Keil::ARM_Compiler
ARM::CMSIS 4.5.0
这一步主要参考 http://www.keil.com/appnotes/files/apnt_268.pdf 及 USB Middleware 帮助文档。
菜单 Project - New μVision Project。
选个工程存放的位置。
选设备的地方找到 STM32F405RGTx。
Run-Time Environment 选中这几个:
CMSIS - CORE
CMSIS - RTOS (API) - Keil RTX
CMSIS Driver - USB Device (API) - High-speed
Device - Startup
Device - STM32Cube Framework (API) - Classic
Device - STM32Cube HAL - Common
Device - STM32Cube HAL - Cortex
Device - STM32Cube HAL - GPIO
Device - STM32Cube HAL - PWR
Device - STM32Cube HAL - RCC
USB - CORE
USB - Device = 1
USB - Device - HID = 1
一个简便方法是先把 USB - Device - HID 设成 1,然后按照左下角的提示把依赖的项目选上就好。
新建好的工程有这些内容:
在 Target 设置里面设置正确的晶振频率。
这一步配置 USB 相关的硬件初始化。
打开 RTE_Device.h 并点击编辑区域下方进入 Configuration Wizard 模式,选中 USB High-speed,并设置 USB 相关的引脚。
这一步配置 USB 相关的软件初始化。
打开 USBD_Config_0.c 并进入 Configuration Wizard 模式,修改 Device Settings 和 String Settings。主要是把 Max Endpoint 0 Packet Size 改成 64 Bytes。
打开 USBD_Config_HID_0.h 并进入 Configuration Wizard 模式,按下图修改。
这一步为 USB 配置 RTOS 的资源。
打开 startup_stm32f405xx.s 并进入 Configuration Wizard,把 Stack Size 改成 0x600。
打开 RTX_Conf_CM.c 并进入 Configuration Wizard:
将 RTOS Kernel Timer input clock frequency [Hz] 改为 168000000,
将 Number of concurrent running threads 改为 4,
将 Number of threads with user-provided stack size 改为 3,
将 Total stack size [bytes] for threads with user-provided stack size 改为 1536,
将 Timer Thread stack size [bytes] 改为 512,
其他设置参考下图。
注:在 Run-Time Environment 设置的地方把 USB 对应的链接打开,是 USB Middleware 的文档,可以查看到以上设置的详细说明。
右键点击 Project 栏的 Source Group 1,选择 Add New Item to Group ‘Source Group 1’…。
选择 User Code Template 里面的 ‘main’ module for STM32Cube。
会出现一个 main.c 模板。
这个 main.c 模板是针对 8MHz 晶振的,我们在 SystemClock_Config
函数里把 RCC_OscInitStruct.PLL.PLLM
改成 24,这样就可以用在 24MHz 晶振环境下。
直接编译并下载到板子上。
这中间还需要在 Target 设置的地方配置下载器,就不详述了。
进入 Debug 模式,在 Watch 窗口手动添加一个 SystemCoreClock。
在 main.c 的 SystemClock_Config();
这一行添加断点,并 Step Over,应该可以看到 SystemCoreClock 从 16M 变化到 168M,这说明时钟配置是正确的。
上面做的这些其实就是在 CMSIS 框架下,利用 MDK Middleware 从头建立 USB 工程的前半部分过程。
如果是一般的 USB 工程,后面步骤是继续利用 User Code Template 添加 USB 线程的文件(就像刚才添加 main.c 一样),就可以直接得到能运行的程序了。
但这次我们会从外部复制 CMSIS-DAP 的代码进来,其中包含 USB 线程部分。
CMSIS-DAP 源码在 CMSIS 那个 Software Pack 中,一般是放在 Keil 安装目录\ARM\Pack\ARM\CMSIS\4.5.0\CMSIS\DAP\Firmware
。
这里面有 5 个文件夹:Config
、 Examples
、 Include
、 Source
和 Template
。
复制 Config
里面的 DAP_config.h
到工程目录下,
复制 Template\MDK5
里面的 osObjects.h
和 USBD_User_HID_0.c
到工程目录下,前一个可能要覆盖已存在的文件。注意不要复制 main.c
,因为我们需要用到刚才的时钟配置函数。
将复制进来的 USBD_User_HID_0.c
和 DAP_config.h
添加到工程中的 Source Group 1
中。
在工程源文件中另外建一个 Group 叫 CMSIS DAP,将源码 Source
文件夹中的 DAP.c
、 JTAG_DP.c
、 SW_DP.c
和 SWO.c
四个文件添加进来。
Target 设置的 C/C++ 选项卡里添加两个 Include Paths:.
和 Keil 安装目录\ARM\Pack\ARM\CMSIS\4.5.0\CMSIS\DAP\Firmware\Include
。
最后直接在 Keil MDK 里修改 main.c
:
增加四个 include
:
#include "osObjects.h"
#include "rl_usb.h"
#include "DAP_config.h"
#include "DAP.h"
把 main
函数按如下修改:
int main(void)
{
HAL_Init(); // STM32F4xx HAL Library Initialization
SystemClock_Config(); // Configure the system clock to 168 MHz
DAP_Setup(); // DAP Setup
Delayms(100U); // Wait for 100ms
USBD_Initialize(0U); // USB Device Initialization
USBD_Connect(0U); // USB Device Connect
while (!USBD_Configured(0U)); // Wait for USB Device to configure
// Create HID Thread
HID0_ThreadId = osThreadCreate(osThread(HID0_Thread), NULL);
osThreadSetPriority(osThreadGetId(), osPriorityIdle);
// Infinite loop
while (1)
{
}
}
CMSIS-DAP 说明文档见 http://www.keil.com/pack/doc/CMSIS/DAP/html/index.html。
打开 DAP_config.h
(需要先把这个文件变成非只读)。
这个文件大体上分成四个部分,中间以大段注释分割:
CMSIS-DAP Debug Unit Information
部分定义了调试器的参数,
CMSIS-DAP Hardware I/O Pin Access
是 JTAG 和 SWD 接口的引脚操作函数,
CMSIS-DAP Hardware Status LEDs
是 LED 引脚操作函数,
CMSIS-DAP Initialization
是这些 IO 引脚的初始化函数。
这些代码都与具体的硬件有关,需要根据硬件情况来编写。
CMSIS-DAP Debug Unit Information
部分按如下设置修改:
项目 | 修改为 | 备注 |
---|---|---|
#include "device.h" |
`#include "stm32f4xx.h" |
|
CPU_CLOCK |
168000000 |
按实际设置 |
IO_PORT_WRITE_CYCLES |
2U |
|
DAP_SWD |
1 |
使能 SWD |
DAP_JTAG |
1 |
使能 JTAG |
DAP_JTAG_DEV_CNT |
8U |
|
DAP_DEFAULT_PORT |
1U |
默认是 SWD 方式 |
DAP_DEFAULT_SWJ_CLOCK |
1000000U |
默认 1MHz |
DAP_PACKET_SIZE |
1024U |
|
DAP_PACKET_COUNT |
4U |
|
SWO_UART |
0 |
暂时关闭 SWO,后面我们会再打开 |
SWO_MANCHESTER |
0 |
|
TARGET_DEVICE_FIXED |
0 |
͏
这时候如果整个工程重新编译的话,应该是没有错误的。可以尝试编译下载到板子上,然后复位 MCU,并连接 USB 接口。正常情况下系统会识别到这个 HID 设备,驱动程序安装成功后,Keil MDK 的调试器设置里面可以找到这个 CMSIS-DAP。
但现在还不能连接目标单片机进行下载调试,因为还没有添加 JTAG 和 SWD 引脚的操作程序。
继续编辑 DAP_config.h
。
自上向下分别需要编写这些函数的实现:
函数名 | 功能 |
---|---|
void PORT_JTAG_SETUP (void) |
配置 JTAG 模式时的引脚模式和方向等。 |
void PORT_SWD_SETUP (void) |
配置 SWD 模式时的引脚模式和方向等。 |
void PORT_OFF (void) |
关闭所有输出引脚,但硬件上我们没实现,所以这个函数空着就行。 |
uint32_t PIN_SWCLK_TCK_IN (void) |
返回 SWCLK_TCK 引脚的值。 |
void PIN_SWCLK_TCK_SET (void) |
SWCLK_TCK 引脚输出高电平。 |
void PIN_SWCLK_TCK_CLR (void) |
SWCLK_TCK 引脚输出低电平。 |
uint32_t PIN_SWDIO_TMS_IN (void) |
返回 SWDIO_TMS_I 引脚的值。 |
void PIN_SWDIO_TMS_SET (void) |
SWDIO_TMS_O 引脚输出高电平。 |
void PIN_SWDIO_TMS_CLR (void) |
SWDIO_TMS_O 引脚输出低电平。 |
uint32_t PIN_SWDIO_IN (void) |
返回 SWDIO_TMS_I 引脚的值。 |
void PIN_SWDIO_OUT (uint32_t bit) |
SWDIO_TMS_O 引脚按 bit 参数的值输出。 |
void PIN_SWDIO_OUT_ENABLE (void) |
SWDIO_TMS_nOE 引脚输出低电平。 |
void PIN_SWDIO_OUT_DISABLE (void) |
SWDIO_TMS_nOE 引脚输出高电平。 |
uint32_t PIN_TDI_IN (void) |
返回 0 就行。 |
void PIN_TDI_OUT (uint32_t bit) |
TDI 引脚按 bit 参数的值输出。 |
uint32_t PIN_TDO_IN (void) |
返回 TDO 引脚的值。 |
uint32_t PIN_nTRST_IN (void) |
返回 0 就行。 |
void PIN_nTRST_OUT (uint32_t bit) |
空着就行。 |
uint32_t PIN_nRESET_IN (void) |
返回 0 就行。 |
void PIN_nRESET_OUT (uint32_t bit) |
nRESET 引脚按 bit 参数的值输出。 |
void LED_CONNECTED_OUT (uint32_t bit) |
LED_CONNECTED 引脚按 bit 参数的值输出。 |
void LED_RUNNING_OUT (uint32_t bit) |
LED_RUNNING 引脚按 bit 参数的值输出。 |
void DAP_SETUP (void) |
所有用到的 GPIO 初始化,包括开启时钟、设置 GPIO 方向和速度等。 |
͏
这里有个细节需要小心。名为
PIN_xxxxx_OUT (uint32_t bit)
的几个函数在调用时,bit
参数的最低位应输出到引脚上。就是说这个参数可能不是0
或1
,比如是0x10
,那么引脚应该输出低电平。
这里最直接的做法是用 bit-band。由于 bit-band 只操作最低位,可以不受 bit
参数其他位的影响。另外一个指令就能完成一个引脚的读或写。
例如写入 SWDIO 的函数可以写成
static __forceinline void PIN_SWDIO_OUT (uint32_t bit) {
*((uint32_t *) 0x4240829C) = bit; // 0x42000000 + (0x020414 * 32) + (7 * 4)
}
其中 0x42000000
是外设 bit-banding 基地址,0x020414
是 GPIOB 输出寄存器的偏移,7 是 PB7 对应的第 7 位。
读取 SWDIO 的函数可以写成
static __forceinline uint32_t PIN_SWDIO_TMS_IN (void) {
return *((uint32_t *) 0x42408218); // 0x42000000 + (0x020410 * 32) + (6 * 4)
}
其中 0x42000000
是外设 bit-banding 基地址,0x020410
是 GPIOB 输入寄存器的偏移,6 是 PB6 对应的第 6 位。
整个 DAP_config.h 我上传到这里管理:
https://code.csdn.net/K_O_Carnivist/cmsis_dap_stm32_hs/tree/master/DAP_config.h
这些都写完后,一个最简单功能的 DAPLink 就完成了。编译并下载程序。
图中是我们自己的调试器检测到 SWD 上的一个 STM32F1。
后面会陆续补充 USB、SW-DP 测试的过程,和 CMSIS-DAP 更多功能的探索。
分割线
这篇博客修改过内容。之前是一个老版本的 CMSIS-DAP 调试器在 LPC11U35 上的实现,应该算是最好做的调试器了,这里保留原来的内容。
本文用尽量简单的方式实现一个CMSIS-DAP调试器,并在Keil MDK中使用。
硬件可参考LPC800-MAX开发板的调试器部分,下面是精简后的原理图。原理图继承原始资料的Apache 2.0开源协议。
图中的MCU为LPC11U35FHI33/501,这个后缀需要注意,其他比如401后缀的不能直接使用下面的程序。
这个MCU不算便宜,零买20来块钱吧。嫌国内不好买的话可以去什么e络盟、Mouser、Digikey之类的分销商。
直接使用LPC800-MAX的CMSIS-DAP固件:
https://developer.mbed.org/handbook/Firmware-LPC800-MAX
或者SWDAP固件:
https://developer.mbed.org/media/uploads/chris/0000_lpc11u35_cmsisdap.bin
或者IBDAP固件:
https://s3.amazonaws.com/armstart/Debug+Tools/IBDAP-LPC11U35/IBDAP-latest.bin
两个附件的区别是,前一个是ARM发布的程序主支,默认只开启SWD,没开JTAG;后一个是第三方发布的,默认开启了SWD和JTAG,但去掉了USB串口和U盘拖拽方式下载这两个功能,本文暂不使用这两个功能。
LPC11U35出厂自带ISP程序,插上USB之后会在电脑上生成一个U盘,把上面LPC800-MAX的固件BIN直接拷进去,然后重新连接USB线就行。
如果已经烧过程序了,可以通过USB上电时短接上面原理图的R?(BOOT),来运行自带ISP程序。
只介绍Keil MDK中的使用,建议版本4.60以上。
至少连接MCU的SWCLK和SWDIO,有的MCU比如LPC的还需要连RST。
驱动程序在
https://developer.mbed.org/handbook/Windows-serial-configuration
在Target Options的debug选项卡中,选择“CMSIS-DAP Debugger”,并在其中的Settings中按如下设置。
注意时钟速度不要太快,取消“Reset after Connect”的选项。
Flash Download里与其他调试器一样选择合适的flash算法,就可以下载程序了。