
基于STM32F103自制CMSIS-DAP下载器.docx
19页基于STM32F103自制CMSIS-DAP下载器 [导读]市面上针对Cortex-M处理器的下载器,有很多是基于CMSIS-DAP演变而来,比如:e-Link、GD-Link等 之前给大家分享过自制ST-Link的教程,今天继续为大家分享一篇:基于STM32F103C8,自制CMSIS-DAP下载器关注+星标公众号,不错过精彩内容编排 |strongerHuang公众号 |strongerHuang市面上针对Cortex-M处理器的下载器,有很多是基于CMSIS-DAP演变而来,比如:e-Link、GD-Link等之前给大家分享过自制ST-Link的教程,今天继续为大家分享一篇:基于STM32F103C8,自制CMSIS-DAP下载器关于CMSIS-DAPCMSIS-DAP是支持访问CoreSight 调试访问端口(DAP)的固件规范和实现,以及各种Cortex处理器提供CoreSight调试和跟踪地址:https://arm-software.github.io/CMSIS_5/DAP/html/index.htmlCMSIS-DAP固件作为源代码提供,并且可以完全配置为新的调试单元。
这里相关的更多内容,可以参看我之前分享过的一篇文章:Cortex-M软件接口标准CMSIS那些重要内容CMSIS-DAP固件CMSIS-DAP固件Arm以源码形式提供,不存在版权问题(因为针对Arm Cortex处理器,他们还希望更多人使用)1.固件版本 目前有两个版本: 版本1配置使用USB HID作为与主机PC的接口 版本2配置使用WinUSB作为与主机PC的接口,并提供高速SWO跟踪流2.源码位置 目前源码提供在Keil MDK V5版本,安装好Keil MDK,你在安装目录下就能找到源码C:\Keil_v5\ARM\Packs\ARM\CMSIS\5.7.0\CMSIS\DAP\Firmware(目前MDK V5.33,CMSIS版本为5.7.0)3.源码描述从文件目录可以看出,官方源码提供了一些模板和例子目前只提供了LPC处理器的例子,如果你有这个处理器对应的板卡,可以直接使用该源码做一个下载调试器下面就针对于LPC这个例子进行“改装”)配置利用STM32CubeMX图形化配置工具,帮助用户选择单片机引脚的功能,并自动生成外设初始化代码配置了USB、SPI1和USART1,并选择了USB的Custom HID middleware模式。
GPIOB10到GPIO15被配置为JTAG调试需要的引脚GPIOC13用于驱动单片机上的LED灯ST公司也开发了他们自己的JTAG调试器——STLink当然它并不是必要的,你也可以使用J-Link或者其他种类的调试器STLink的驱动和程序可以在ST官网上下载在网站里还有一个基于Eclipse开发环境开发的IDE,STM32CubeMX也被包含其中我选择的IDE是基于CodeBlocks的Embitz,IDE中的arm_none_eabi_gcc版本是5.4.1在我完成我的CMSIS-DAP之前,我必须使用STLink来调试我的代码现在我在使用新做出来的CMSIS-DAP结合OpenOCD进行日常的开发从CMSIS-DAP的源码开始源码可以在官网下载:也可以直接在Keil MDK安装目录下获取:C:\Keil_v5\ARM\Packs\ARM\CMSIS\5.7.0\CMSIS\DAP将从示例V1的头文件 DAP_config.h 开始分析选择LPC-Link-II V1作为我的参考是因为它是通过USB HID实现的(V2是通过WinUSB实现)我分析的第一个文件是DAP_Config.h。
第一个关键位置如下: #ifdef _RTE_#include "RTE_Components.h"#include CMSIS_device_header#else#include "device.h" #endif不用RTE的相关文件,创建我自己的device.h我将参数CPU_CLOCK重定义为72000000(72MHz)根据文件里的注释,参数DAP_PACKET_SIZE必须重新定义为64U我把SWO_UART改为0,这让我的工作轻松不少参数TIMESTAMP_CLOCK也要重定义为72000000LPC-Link-II使用Cortex-M3 的 DWT模块实现时间戳(TIMESTAMP),这也是为什么我想在CubeMX中尝试配置STM32F103的DWT最后我自己写了一小段代码来实现这个功能(在device.c中):CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;/** * On Cortex-M7 core there is a LAR register in DWT domain. * Any time we need to setup DWT registers, we MUST write * 0xC5ACCE55 into LAR first. LAR means Lock Access Register. */DWT->CYCCNT = 0;DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;我定义的引脚和NXP LPCxx的完全不同。
我为STM32F103重写了所有的引脚的操作代码在DAP_Config.h这个文件中还有一些奇怪的地方,比如:// SWCLK/TCK I/O pin ------------------------------------- /** SWCLK/TCK I/O pin: Get Input.\return Current status of the SWCLK/TCK DAP hardware I/O pin.*/__STATIC_FORCEINLINE uint32_t PIN_SWCLK_TCK_IN (void) { return ((LPC_GPIO_PORT->PIN[PIN_SWCLK_TCK_PORT]>> PIN_SWCLK_TCK_BIT) & 1U);}我不明白为什么DAP的代码里需要读取SWCLK/TCK引脚的电平,这个引脚明明是被配置为推挽输出来产生时钟信号输送给JTAG从机的从上面列出来的代码可以看出,它是希望返回当前引脚的电平值,我的实现方式稍微有点不同:__STATIC_FORCEINLINE uint32_t PIN_SWCLK_TCK_IN (void) { return (uint32_t)(JTAG_TCK_GPIO_Port->ODR & JTAG_TCK_Pin ? 1:0);}我返回的是当前引脚的输出值。
我不确定这是否正确在整个代码中,这句话只被DAP.c中的一个叫DAP_SWJ_Pins的函数调用了两次我猜测DAP_SWJ_Pins这个函数是用来测试IO口是否工作正常的另一个奇怪的地方是PIN_nRESET_OUT:/** nRESET I/O pin: Set Output.\param bit target device hardware reset pin status: - 0: issue a device hardware reset. - 1: release device hardware reset.*/__STATIC_FORCEINLINE void PIN_nRESET_OUT (uint32_t bit) { if (bit) { LPC_GPIO_PORT->DIR[PIN_nRESET_PORT] &= ~(1U < 我的代码如下:__STATIC_FORCEINLINE void PIN_nRESET_OUT (uint32_t bit) { GPIO_InitTypeDef GPIO_InitStruct = {0}; if ((bit & 1U) == 1) { JTAG_nRESET_GPIO_Port->BSRR = JTAG_nRESET_Pin; GPIO_InitStruct.Pin = JTAG_nRESET_Pin; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(JTAG_nRESET_GPIO_Port, &GPIO_InitStruct); } else { JTAG_nRESET_GPIO_Port->BRR = JTAG_nRESET_Pin; GPIO_InitStruct.Pin = JTAG_nRESET_Pin; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(JTAG_nRESET_GPIO_Port, &GPIO_InitStruct); }}给你一个特殊的提示: 你可能在一些地方看见我写了if(...)之类的代码,像下面这样: if ((bit & 1U) == 1) { ... } else { ... }我使用参数bit的最低位是因为有时候这个bit既不是0也不是1,它可能是2或者其他奇怪的值,所以不要把你的代码写成这样: if (bit) { ... } else { ... }这会出问题的! osObjects.h#ifndef __osObjects_h__#define __osObjects_h__ #include "cmsis_os2.h" #ifdef osObjectsExternalextern osThreadId_t DAP_ThreadId;#elseextern osThread。
