GD32 STM32 bootload IAP程序跳转实现

学习MCU不短时间了,第一次写MCU IAP程序跳转,折腾了不短时间,最终才搞明白程序的跳转.
参考文献:
用到的关键词:
分散加载/uboot/boot/booload/中断向量/IAP… …

这里是引用

		 https://www.jianshu.com/p/2eef44b1cfd3	<>
		 https://blog.csdn.net/tq384998430/article/details/81010002<<设计一款STM32的BootLoader>>
		 https://blog.csdn.net/baideweidao/article/details/82774808<>
		 http://news.eeworld.com.cn/mcu/2018/ic-news081940854.html<>
		 https://www.rt-thread.org/document/site/application-note/system/rtboot/an0028-rtboot/<>
		 https://blog.csdn.net/yangzhao0001/article/details/73293379<>		 
		 ...

由于我写的GD的32E230 ARM® Cortex®-M23核,与STM32有些库不太一样,根据参考文献自己写了段代码测试发现可以跳转,单独使用boot和app都没有问题,但一组合app就频繁重启,经过同事帮助下才找到问题根本.

MCU启动是从FLASH起始地址开始的;ARM® Cortex®-Mxx常见的FALSH起始地址0x08000000.
我们现在把bootload代码区放在0x08000000,根据需要划分4K~16K的空间,空间必须FLASH最小块的整倍数;剩下的用来放应用程序(APP)代码.
代码划分参考"百度"<<分散加载>>.
bootload跳转代码及注意:

#define APP_ADDRESS             (uint32_t)0x08004000
/* Private typedef -----------------------------------------------------------*/
typedef void (*pFunction)(void);            /*!< Function pointer definition */

void vJumpToApplication(void)
{
    uint32_t  JumpAddress = *(__IO uint32_t*)(APP_ADDRESS + 4);
    pFunction Jump_To_Application;
	
	if (((*(__IO uint32_t*)APP_ADDRESS) & 0x2FFE0000 ) == 0x20000000)  //ApplicationAddress为新程序的起始地址,检查栈顶地址是否合法,即栈顶地址是否为0x2000xxxx(内置SRAM)
	{
		usart_disable(USART0);	//这里是在跳转前关闭已经初始化的外设
		usart_disable(USART1);		
		rcu_deinit();		
		__set_MSP(*(__IO uint32_t*) APP_ADDRESS);            	//初始化APP堆栈指针(用户代码区的第一个字用于存放栈顶地址)
		SCB->VTOR = APP_ADDRESS;								//重定向中断向量表
			
		JumpAddress = *(__IO uint32_t*) (APP_ADDRESS + 4);   	//用户代码区第二个字存储为新程序起始地址(新程序复位向量指针)
		Jump_To_Application = (pFunction) JumpAddress;            
		Jump_To_Application();                                	//设置PC指针为新程序复位中断函数的地址
	}	
	else
	{
		printf("!!!!!!ERROR:APP_ADDRESS ERR!!!!!!!!!\n");
	}
}

注意:无意中参考到部分资料中说跳转前要屏蔽中断调用__set_PRIMASK(1),我就在这句话中上当.
在跳转前调用用屏蔽了中断,跳转后如果不及时恢复(正常情况不会有人去恢复)那么代码就会进不了中断造成异常.
正常情况下在跳转前需要关闭在bootload中打开的外设,初始化APP堆栈指针;中断向量表可选择是否重定向.
用户程序(APP)需要修改内容:
在main()第一行加入以下代码

SCB->VTOR = 0x08004000;

如果boolload和APP是分开烧写,就参考普通<<分散加载>>处理就可以了;现在我希望把bootload的代码以库或者镜像的方式直接加载在APP程序中,这样就不用合并两份代码:
链接文件

APP 0x08004000 0x0000C000  {    ; load region size_region
  app_update.bin 0x08004000 0x0000C000  {  ; load address = execution address
   *.o (RESET, +First)
   *(InRoot$$Sections)
   .ANY (+RO)
  }
  RW_IRAM1 0x20000000 0x00002000  {  ; RW data
   .ANY (+RW +ZI)
  }
}
//这个区域用来加载bootload镜像
UBOOT 0x08000000 0x00004000  {    ; load region size_region
  boot.bin 0x08000000 0x00004000  {  ; load address = execution address
   *(.boot)
  }
}

新建一个.S文件

	AREA 	|.boot|, DATA, READONLY 
	ALIGN   4
			
	EXPORT  __uboot_start_addr
__uboot_start_addr  	;Must set the top 

	INCBIN ../BootLoad/HJ-GD32E230-boot.img	;这里就是引用我们的bootload的镜像
		
	END

这里说明一下"__uboot_start_addr",这是用汇编声明的一变量,在这里本来是任何作用,那为什么还要声明呢?是因为如果只是这样将bootload加载到app程序中,bootload并不能被编译到应用程序中,这里就需要在app中调用一下这个变量,这样bootload镜像就能被正常加载,如:printf("%x",__uboot_start_addr);
如果各位大佬就更好的方法请不吝赐教.
bootload代码如果输出.bin或.img文件,使用以下.
C:\Keil_v5\ARM\ARMCC\bin\fromelf.exe --bin --output “ L @ L . i m g " " [email protected]" " L@L.img""[email protected]
GD32 STM32 bootload IAP程序跳转实现_第1张图片

你可能感兴趣的:(GD32 STM32 bootload IAP程序跳转实现)