当前位置:   article > 正文

自制脱机烧录器(二)_离线swd烧录器

离线swd烧录器

(二)SWD协议移植


前言

IO口模拟的SWD时序,我参考的是这位大神的文章。基于CMSIS-DAP,实现通过DAP读写目标芯片的内存、内核寄存器,这部分功能已经由ARM公司的CMSIS-DAP代码实现。我把主要移植到STM32G070RB上,把标准库改成了HAL库。


一、将下载算法加载到目标芯片SRAM

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)
  • 1

那么,我们只要把编程算法(一段在目标芯片上执行的代码,里面有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
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82

以上是下载步骤,在FLASH初始化中把下载算法加载到目标的SRAM,然后通过SWD的擦除,写入函数进行编程,下载完成后对目标芯片进行复位。

二、SWD的移植

1.改变移植芯片的主频

在这里插入图片描述
首先将源文件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,剩下的都搞成一样。

2.更改SWD下载引脚

在这里插入图片描述
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文件,不过还好,生成是一次行的。最后将介绍若何使用上位机传输程序。
上位机操作(三)

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/正经夜光杯/article/detail/925895
推荐阅读
相关标签
  

闽ICP备14008679号