0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

基于STM32自制CMSIS-DAP下载器

strongerHuang 来源:strongerHuang 2023-12-19 09:12 次阅读

市面上针对Cortex-M处理器下载器,有很多是基于CMSIS-DAP演变而来,比如:e-Link、GD-Link等。

之前给大家分享过自制ST-Link的教程,今天继续为大家分享一篇:基于STM32F103C8,自制CMSIS-DAP下载器。

关于CMSIS-DAP

CMSIS-DAP是支持访问

CMSIS-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_v5ARMPacksARMCMSIS5.7.0CMSISDAPFirmware

(目前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_v5ARMPacksARMCMSIS5.7.0CMSISDAP

将从示例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也要重定义为72000000。LPC-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. eturn 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 <<PIN_nRESET_BIT); LPC_GPIO_PORT->CLR[PIN_nRESET_OE_PORT] = (1U <<PIN_nRESET_OE_BIT); } else { LPC_GPIO_PORT->SET[PIN_nRESET_OE_PORT] = (1U <<PIN_nRESET_OE_BIT); LPC_GPIO_PORT->DIR[PIN_nRESET_PORT] |= (1U <<PIN_nRESET_BIT); } }
		为猜测release的意思可能是将nRESET引脚重新配置为一个失能的引脚。我的代码如下:

	
		__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 osObjectsExternal extern osThreadId_t DAP_ThreadId; #else extern osThreadId_t DAP_ThreadId; osThreadId_t DAP_ThreadId; #endif extern void DAP_Thread (void *argument); extern void app_main (void *argument); #endif /* __osObjects_h__ */
		这是一个很简单的头文件。但它引用了另一个叫做cmsis_os2.h的头文件,这是CMSIS库的一部分,但我没有没有从CMSIS库中复制到我的工程中,因为并不是其中所有的内容我都需要。我选择写一个“假”的cmsis_os2.h头文件而不是直接使用原有的头文件。这里还有另一个叫做DAP.h的头文件,它属于DAP的核心模块,在这里面引用了cmsis_compiler.h文件,这也是CMSIS库的一部分。毫无疑问,我也写了一个“假”的cmsis_compiler.h。分析到现在,我需要创建三个头文件(device.h&cmsis_os2.h&cmsis_compiler.h)来实现我的DAP工程。
		接下来我会对main.cUSBD_User_HID_0.c做一些一些简单的介绍。
  • main.c
我在尽可能地精简我下载下来的这些源文件,所以我也没有要示例工程中的rl_usb.h文件。于是我还需要一个头文件来定义一些关于USB通信的函数和参数。这里有一些来自CMSIS RTOS库的函数,其中最重要的一个是osThreadNew,在我的工程中我把它实现如下:

	
		osThreadId_t osThreadNew(void (*func)(void *), void * n, void * ctx) { (void)n; (*func)(ctx); return 0; }
		我直接“跳转”到本需要被创建的线程函数中,这就意味着main.c中的osKernelGetState&osKernelStart&osDelay三个函数永远不会被执行。下一个重要的函数是USBD_Configured,我将在使用STM32CubeMX生成初始化代码那一节解释这个函数。
  • USBD_User_HID_0.c
我移除了RTEUSBUSBD_Config_HID_0.h并在我自己的rl_usb.h中重新定义了USBD_HID0_OUT_REPORT_MAX_SZ&USBD_HID0_IN_REPORT_MAX_SZ两个参数。 USB HID通信的核心是由两个接口中断函数管理的两个循环队列:

	
		int32_t USBD_HID0_GetReport (uint8_t rtype, uint8_t req, uint8_t rid, uint8_t *buf) { (void)rid; switch (rtype) { case HID_REPORT_INPUT: ... break; } return (0); }

	
		bool USBD_HID0_SetReport (uint8_t rtype, uint8_t req, uint8_t rid, const uint8_t *buf, int32_t len) { (void)req; (void)rid; switch (rtype) { case HID_REPORT_OUTPUT: ... break; } return true; }上位机向DAP发送OUTPUT REPORT报文后,DAP会调用USBD_HID0_SetReport函数,该参数的输入形参rtype必须为HID_REPORT_OUTPUT。当DAP成功向上位机发送INPUT REPORT报文时,函数USB_HID0_GetReport被调用,该函数的输入形参rtype必须为HID_REPORT_INPUT,并且形参req必须为USBD_HID_REQ_EP_INT。这意味着我们所有的报文必须通过64B数据包大小的USB中断端点传输。
		线程DAP_Thread只是一个命令判断选择器。在这个函数中有一个很重要的语句:

	USBD_HID_GetReportTrigger(0U, 0U, USB_Response[n], DAP_PACKET_SIZE);
		我们必须实现一个叫做USBD_HID_GetReportTrigger的函数来想上位机发送INPUT REPORT

使用STM32CubeMX生成初始化代码

在我的单片机上有一个8MHz的晶振,所以我选择HSE为时钟信号源。PLLMul配置为x9,得到72MHz的PLLCLK,提供给CPU和AHB/APB2总线,提供给APB1总线的PCLK1配置为36MHz。USB预分频配置为1.5分频,得到48MHz的USB时钟。SPI1配置为Full-Duplex Master,舍去NSS信号,USART1配置为Asynchronous。USB设备进一步配置为Custom HID ClassUSBD_CUSTOMHID_OUTREPORT_BUF_SIZE设置为64 Bytes。

注意: 我没有修改设备的VID和PID。但我猜测有些上位机软件会检测这两个ID
如果你发现你的软件不能识别我这个CMSIS-DAP,或许你需要恰当的VID和PID。可以试试示例代码中的VID/PID,它在一个叫做USBD_Config_0.c的文件中,我的工程中没有这个文件。

有STM32CubeMX生成的代码需要一些修改。在usbd_customhid.h中,CUSTOM_HID_EPIN_SIZECUSTOM_HID_EPOUT_SIZE必须设置为0x40U。我把CUSTOM_HID_FS_BINTERVAL改为0x01来尝试提升HID的通信速度。

_USBD_CUSTOM_HID_Itf结构体中,我新增了一个成员:

	typedef struct _USBD_CUSTOM_HID_Itf { uint8_t *pReport; int8_t (* Init)(void); int8_t (* DeInit)(void); int8_t (* OutEvent)(uint8_t event_idx, uint8_t state); /* I add an extra interface func below. Zach Lee */ int8_t (* InEvent)(uint8_t event_idx, uint8_t state); } USBD_CUSTOM_HID_ItfTypeDef;INPUT REPORT报文成功发给上位机时,InEvent函数应当被调用,所以usbd_customhid.c中的USBD_CUSTOM_HID_DataIn函数需要修改如下:

	static uint8_t USBD_CUSTOM_HID_DataIn(USBD_HandleTypeDef *pdev, uint8_t epnum) { /* Ensure that the FIFO is empty before a new transfer, this condition could be caused by a new transfer before the end of the previous transfer */ USBD_CUSTOM_HID_HandleTypeDef *hhid = (USBD_CUSTOM_HID_HandleTypeDef *)pdev->pClassData; hhid->state = CUSTOM_HID_IDLE; /* I add a new interface func in the structure USBD_CUSTOM_HID_ItfTypeDef. Zach Lee */ ((USBD_CUSTOM_HID_ItfTypeDef *)pdev->pUserData)->InEvent(hhid->Report_buf[0], hhid->Report_buf[1]); return USBD_OK; }
		设备描述符CUSTOM_HID_ReportDesc_FS被定义在usbd_suctom_hid_if.c中,我定义了一个简单的描述符:

	/** Usb HID report descriptor. */ __ALIGN_BEGIN static uint8_t CUSTOM_HID_ReportDesc_FS[USBD_CUSTOM_HID_REPORT_DESC_SIZE] __ALIGN_END = { /* USER CODE BEGIN 0 */ /* A minimal Report Desc with INPUT/OUTPUT/FEATURE report. Zach Lee */ 0x06,0x00,0xFF, /* Usage Page (vendor defined) ($FF00) global */ 0x09,0x01, /* Usage (vendor defined) ($01) local */ 0xA1,0x01, /* Collection (Application) */ 0x15,0x00, /* LOGICAL_MINIMUM (0) */ 0x25,0xFF, /* LOGICAL_MAXIMUM (255) */ 0x75,0x08, /* REPORT_SIZE (8bit) */ // Input Report 0x95,64, /* Report Length (64 REPORT_SIZE) */ 0x09,0x01, /* USAGE (Vendor Usage 1) */ 0x81,0x02, /* Input(data,var,absolute) */ // Output Report 0x95,64, /* Report Length (64 REPORT_SIZE) */ 0x09,0x01, /* USAGE (Vendor Usage 1) */ 0x91,0x02, /* Output(data,var,absolute) */ // Feature Report 0x95,64, /* Report Length (64 REPORT_SIZE) */ 0x09,0x01, /* USAGE (Vendor Usage 1) */ 0xB1,0x02, /* Feature(data,var,absolute) */ /* USER CODE END 0 */ 0xC0 /* END_COLLECTION */ };
		可能Feature Report在CMSIS-DAP中不是必要的,就留着它吧。
		我在这个C文件中还实现了一个新的接口函数CUSTOM_HID_InEvent_FS

	static int8_t CUSTOM_HID_InEvent_FS(uint8_t event_idx, uint8_t state); /* An extra interface func. */ USBD_CUSTOM_HID_ItfTypeDef USBD_CustomHID_fops_FS = { CUSTOM_HID_ReportDesc_FS, CUSTOM_HID_Init_FS, CUSTOM_HID_DeInit_FS, CUSTOM_HID_OutEvent_FS, /* I add an extra interface func below. Zach Lee */ CUSTOM_HID_InEvent_FS };

	extern void USBD_OutEvent(void); /* Implemented in file "device.h" */ static int8_t CUSTOM_HID_OutEvent_FS(uint8_t event_idx, uint8_t state) { /* USER CODE BEGIN 6 */ USBD_OutEvent(); /* OUTPUT REPORT was received. Zach Lee */ return (USBD_OK); /* USER CODE END 6 */ } extern void USBD_InEvent(void); /* Implemented in file "device.h" */ static int8_t CUSTOM_HID_InEvent_FS(uint8_t event_idx, uint8_t state) { /* USER CODE BEGIN extra */ USBD_InEvent(); /* INPUT REPORT has been sent. Zach Lee */ return (USBD_OK); /* USER CODE END extra */ }CUSTOM_HID_Init_FSCUSTOM_HID_DeInit_FS两个函数被实现为使能/失能DAP功能:

	extern void USBD_HID0_Initialize (void); static int8_t CUSTOM_HID_Init_FS(void) { /* USER CODE BEGIN 4 */ USBD_HID0_Initialize(); /* Initialize USB communication of DAP. Zach Lee */ return (USBD_OK); /* USER CODE END 4 */ } extern void USBD_HID0_Uninitialize (void); static int8_t CUSTOM_HID_DeInit_FS(void) { /* USER CODE BEGIN 5 */ USBD_HID0_Uninitialize(); /* Uninitialize. Zach Lee */ return (USBD_OK); /* USER CODE END 5 */ }
		

编写将所有源代码关联起来的桥梁

为了移除CMSIS RTOS,我写了一些函数来模拟RTOS:


	/** * Replace CMSIS RTOS api */ static volatile int osFlags; /* Use "volatile" to prevent GCC optimizing the code. */ void osKernelInitialize(void) { osFlags = 0; return; } int osThreadFlagsWait(int mask, int b, int c) { (void)b; (void)c; int ret; while((osFlags&mask) == 0) { ; } ret = osFlags; osFlags &= ~mask; return ret; } void osThreadFlagsSet(int tid, int f) { (void)tid; osFlags |= f; return; }
		函数USBD_ConfiguredUSBD_HID_GetReportTrigger实现如下:

	intUSBD_Configured(int n){  (void)n;  return(hUsbDeviceFS.dev_state == USBD_STATE_CONFIGURED ?1:0);}

	void USBD_HID_GetReportTrigger(int a, int b, void * report, int len) { (void)a; (void)b; if (USBD_OK != USBD_CUSTOM_HID_SendReport(&hUsbDeviceFS, report, len)) { ; } return; }
		函数USBD_CUSTOM_HID_SendReport是由STM32CubeMX生成的,它被定义在usbd_customhid.c中,我自己的事件句柄如下:

	
		bool USBD_HID0_SetReport (uint8_t rtype, uint8_t req, uint8_t rid, const uint8_t *buf, int32_t len); void USBD_OutEvent(void) { USBD_CUSTOM_HID_HandleTypeDef *hhid = (USBD_CUSTOM_HID_HandleTypeDef *)hUsbDeviceFS.pClassData; USBD_HID0_SetReport(HID_REPORT_OUTPUT, 0, 0, hhid->Report_buf, USBD_CUSTOMHID_OUTREPORT_BUF_SIZE); } int32_t USBD_HID0_GetReport (uint8_t rtype, uint8_t req, uint8_t rid, uint8_t *buf); void USBD_InEvent(void) { int32_t len; USBD_CUSTOM_HID_HandleTypeDef *hhid = (USBD_CUSTOM_HID_HandleTypeDef *)hUsbDeviceFS.pClassData; if ((len=USBD_HID0_GetReport(HID_REPORT_INPUT, USBD_HID_REQ_EP_INT, 0, hhid->Report_buf)) > 0) { USBD_HID_GetReportTrigger(0, 0, hhid->Report_buf, len); } }
注意: 在DAP.h中,这里有个名为PIN_DELAY_SLOW的函数,它原本的实现是这样的:

	
		__STATIC_FORCEINLINE void PIN_DELAY_SLOW (uint32_t delay) { uint32_t count; count = delay; while (--count); }
这里的空循环while (–count);会被GCC优化。我在StackOverflow中找到了一个好点子,它能正常工作但不是太合适,你有更好的方法吗?

	
		__STATIC_FORCEINLINE void PIN_DELAY_SLOW (uint32_t delay) { uint32_t count; count = delay; while (--count) { /** * Empty loop will be totally omitted by GCC. * Search "How to prevent GCC from optimizing out a busy wait loop?" @ StackOverflow. * This solution isn't portable. Zach Lee */ __ASM(""); } }
至此,相关源码就介绍完毕。
审核编辑:汤梓红

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 处理器
    +关注

    关注

    68

    文章

    19259

    浏览量

    229651
  • STM32
    +关注

    关注

    2270

    文章

    10895

    浏览量

    355730
  • 下载器
    +关注

    关注

    1

    文章

    62

    浏览量

    12831
  • Cortex-M
    +关注

    关注

    2

    文章

    229

    浏览量

    29752

原文标题:基于STM32自制CMSIS-DAP下载器

文章出处:【微信号:strongerHuang,微信公众号:strongerHuang】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    STM32CubeMX生成的STM32F1工程,使用CMSIS-DAP下载下载一次之后就无法下载了,为什么?

    使用STM32CubeMX生成的STM32F1工程,在使用CMSIS-DAP下载下载一次之后,
    发表于 04-08 06:29

    在linux下使用openocd时cmsis-dap下载速度奇慢的原因?

    在linux下使用openocd时 cmsis-dap下载速度奇慢的问题
    发表于 04-25 07:21

    CMSIS-DAP Mini仿真器用户手册

    CMSIS-DAP Mini仿真器用户手册相关阅读:【仿真,不只有J—Link】CMSIS-DAP调试标准解读https://bbs.elecfans.com/jishu_576894_1_1.html
    发表于 04-27 15:22

    CMSIS-DAP Mini仿真申请】CMSIS-DAP Mini仿真评估

    申请理由:就职于全球知名半导体公司的MCU部门,负责Cortex M系列MCU的SDK支持与开发,每一款MCU的SDK支持都需要评估各个调试的支持情况。所以会一直使用各种调试进行测试。项目描述:已有与新的ARM cortex M系列MCU采用
    发表于 05-25 11:33

    CMSIS-DAP Mini仿真试用体验】+第一篇 ☞CMSIS-DAP Mini仿真开箱大揭秘

    `今天中午收到了CMSIS-DAP Mini仿真,赶紧就迫不及待的上传开箱贴了:整个外包装。挺简约的,再来几张特写:总得给我的感觉就是塑料外壳做的很简陋,感觉材料不是很好,但是优点是体积小巧,这个我喜欢。整个外观就介绍这么多,接下来就要试用
    发表于 06-17 23:14

    CMSIS-DAP Mini仿真试用体验】+第六篇 ☞CMSIS-DAP Mini仿真下载移植PM检测从51到STM32

    ,对了还有串口,再来一张特写:串口线连接电脑,模拟PM传感的串口数据输出。看看以前用51做的:原帖子的连接这个虽然粗糙些,但是芯片高级啊,程序稍微复杂些。至此,CMSIS-DAP的试用算是告一段落了,后续要逐渐过渡下,从51先升级到S
    发表于 07-15 09:27

    CMSIS-DAP Mini仿真试用体验】CANNON蓝牙板调试下载与试用总结

    CMSIS-DAP。再次下载,正常工作。在用KEIL 时还碰到了 一个问题,这个问题坛友也在问。我当时遇到这个问题,然后用IAR连接调试调试之后,再换了KEIL就没有再复现,所以有点不确定是不是KEIL上述
    发表于 07-18 22:17

    CMSIS-DAP Mini仿真试用体验】+第七篇 ☞CMSIS-DAP Mini仿真增补贴

    CMSIS-DAP和我写的1602程序冲突了。前一段时间,发的STM32驱动1602的程序的异常现象,CMSIS-DAP Mini仿真下载
    发表于 07-24 19:37

    如何去实现一种基于STM32F103的CMSIS-DAP下载设计呢

    如何去实现一种基于STM32F103的CMSIS-DAP下载设计呢?有哪些设计步骤?
    发表于 01-26 06:15

    为什么STM32F1无法使用CMSIS-DAP下载进行二次下载

    1. 问题描述使用STM32CubeMX生成的 STM32F1 工程,在使用 CMSIS-DAP 下载
    发表于 02-10 07:39

    自己制作一款CMSIS-DAP调试

    CMSIS-DAP调试是一款开源调试,网上也有很多制作资料,我也是根据这些资料,自己制作了一款CMSIS-DAP调试,目前使用没发现什
    发表于 02-28 11:20

    浅析RT-Thread用CMSIS-DAP调试会导致SIGSEGV hardfault的问题

    : STM32H743-ATK-APOLLO调试工具: (Jlink V11) vs (fireDAP 野火高速调试)重现步骤1、使用在线 BSP创建新项目:2、查看默认下载配置如下(CMS
    发表于 07-07 14:51

    CMSIS-DAP的LPC-Link2问题求解

    我有一个带有闪存 CMSIS-DAP 脚本的 LPC-Link2 板,但是当开始使用 openOCD 进行调试时,我收到一个错误:“错误:CMSIS-DAP 命令 CMD_INFO 失败”。可能是
    发表于 03-16 06:47

    CMSIS-DAP Mini仿真-用户手册

    CMSIS-DAP Mini仿真-用户手册
    发表于 11-22 19:12 11次下载

    基于STM32F103自制CMSIS-DAP下载

    关注+星标公众号,不错过精彩内容编排 |strongerHuang微信公众号 |strongerHuang市面上针对Cortex-M处理下载,有很多是基于CMSIS-DAP演变.
    发表于 12-01 15:21 44次下载
    基于<b class='flag-5'>STM32</b>F103<b class='flag-5'>自制</b><b class='flag-5'>CMSIS-DAP</b><b class='flag-5'>下载</b><b class='flag-5'>器</b>