赞
踩
(二)SWD协议移植
IO口模拟的SWD时序,我参考的是这位大神的文章。基于CMSIS-DAP,实现通过DAP读写目标芯片的内存、内核寄存器,这部分功能已经由ARM公司的CMSIS-DAP代码实现。我把主要移植到STM32G070RB上,把标准库改成了HAL库。
uint8_t swd_flash_syscall_exec(const program_syscall_t *sysCallParam, uint32_t entry, uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t arg4)
那么,我们只要把编程算法(一段在目标芯片上执行的代码,里面有Flash_Erase、Flash_Write两个函数)通过SWD写入目标芯片的SRAM,然后再通过SWD调用目标芯片SRAM里面的Flash_Erase、Flash_Write两个函数,不就能实现通过SWD给目标芯片编程了吗?
/*-------------------------------------------------*/ /*函数名:SWD下载 */ /*参 数:无 */ /*返回值:返回1下载成功,返回0下载失败 */ /*-------------------------------------------------*/ uint8_t Program_Target(void) { if(swd_init_debug()) //初始化下载端口 { //初始化 if(user_target_flash_init(Flash_Start_Addr,Fire_Info.Fire_ver) != ERROR_SUCCESS) //初始化目标MCU的FLASH { printf("FLASH Init Error!\r\n"); return 0; } //擦除 for(uint32_t addr = 0; addr < Fire_Info.Firelen[SelectFlash]; addr += 1024) //擦除MCU的目标FLASH { if(user_target_flash_erase_sector(0x08000000 + addr,Fire_Info.Fire_ver) != ERROR_SUCCESS) { printf("Erase FLASH Error!\r\n"); return 0; } } if(Fire_Info.Firelen[SelectFlash] %1024 != 0){ //判断是否还有不满1扇区1024字节的数据,如果有进入if擦除 if( user_target_flash_erase_sector(0x08000000 + (Fire_Info.Firelen[SelectFlash]/1024)*1024,Fire_Info.Fire_ver) != ERROR_SUCCESS) { printf("Erase FLASH Error!\r\n"); return 0; } } #if DEBUG_INFO // 读取擦除后的FLASH for(uint32_t addr = 0; addr < Fire_Info.Firelen[SelectFlash]; addr += 1024) { if(swd_read_memory(0x08000000 + addr, readbuff, 1024) == ERROR_SUCCESS){ printf("Read FLASH Error!\r\n"); return 0; } for(uint32_t i = 0; i < 1024; i++) printf("%02X ", readbuff[i]); printf("\r\n\r\n\r\n"); } #endif /*DEBUG_INFO*/ //将程序下载到目标MCU for(uint32_t addr = 0; addr < Fire_Info.Firelen[SelectFlash]; addr += 1024) { W25QXX_Read(DataSta.databuff,FLASH_CAP * SelectFlash + addr,1024); //从W25Q32中读取程序 if(user_target_flash_program_page(0x08000000 + addr, DataSta.databuff, 1024,Fire_Info.Fire_ver) != ERROR_SUCCESS){ //下载到目标MCU printf("Program FLASH1 Error!\r\n"); return 0; } } //再次读取MCU观察程序是否正确 for(uint32_t addr = 0; addr < Fire_Info.Firelen[SelectFlash]; addr += 1024) { if(swd_read_memory(0x08000000 + addr, readbuff, 1024) == ERROR_SUCCESS){ printf("Read FLASH Error!\r\n"); return 0; } #if DEBUG_INFO for(uint32_t i = 0; i < 1024; i++) printf("%02X ", readbuff[i]); printf("\r\n\r\n\r\n"); #endif /*DEBUG_INFO*/ } #if DEBUG_INFO if(Fire_Info.Firelen[SelectFlash] %1024 != 0){ if(swd_read_memory(0x08000000 +(Fire_Info.Firelen[SelectFlash]/1024)*1024, readbuff, Fire_Info.Firelen[SelectFlash]%1024) == ERROR_SUCCESS) { printf("Read FLASH Error!\r\n"); return 0; } for(uint32_t j = 0; j < Fire_Info.Firelen[SelectFlash]%1024; j++) printf("%02X ",DataSta.databuff[j]); } #endif /*DEBUG_INFO*/ swd_set_target_reset(0);//复位运行 } else{ printf("SWD Init Error!\r\n"); return 0; } return 1; //成功返回1 }
以上是下载步骤,在FLASH初始化中把下载算法加载到目标的SRAM,然后通过SWD的擦除,写入函数进行编程,下载完成后对目标芯片进行复位。
首先将源文件SW_DP.c,DAP.c,SWD_flash.c,SWD_host.c,error.c加入到工程中,然后将头文件DAP.h,DAP_config.h,error.h,SWD_flash.h,SWD_host.h,也加入到工程中,然后打开DAP_config.h文件,如下图所示:
CPU_CLOCK对应的是你移植芯片的主频,是多少就改成多少,我用的是STM32G070RB主频是64M,剩下的都搞成一样。
GPIOC的GPIO_PIN_0对应的是SWDIO,GPIOC的GPIO_PIN_1对应的是SWCLK,这个自己想换成什么引脚都可以。如果是移植到标准库可能要改的东西多点,SWD协议目前已经移植完毕,这部分主要是DAP已经开源了。
既然下载程序需要目标芯片的下载算法,而每个芯片的算法都不一样,所以我们该怎么得到下载算法呢?我们知道,Keil针对每一颗芯片都有一个Flash编程算法,这个算法存在一个后缀为.FLM的文件里面,要是我们能把.FLM文件里面的算法内容抽取出来给我们用,那不就完美了吗其实这个功能也已经有国外大神给实现了,GitHub上的FlashAlgo项目里面有个flash_algo.py文件,它就是用来实现这个功能的,我已经把常用芯片的算法已经提取出来了放到这里下载算法
自己去提取想要的算法只需要把.FLM文件放在和FlashAlgo放在同一路径下,双击FlashAlgo即可生成对应的芯片.c文件下载算法
整个编程烧写过程占用了目标芯片4K SRAM,其中SRAM起始地址为0x20000000,栈顶指向4K SRAM的末尾,,编程算法占用4K SRAM的前1K,,待烧写数据占用4K SRAM的中间2K,,静态变量和栈共用4K SRAM的最后1K这种设计对绝大多数Cortex-M芯片是没有问题的,所以对于有些比较特殊的芯片,,需要先修改一下flash_algo.py和c_blob.tmpl,然后再生成算法文件对应的.c文件,不过还好,生成是一次行的。最后将介绍若何使用上位机传输程序。
上位机操作(三)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。