STM32使用bootloader的记录
将FLASH规划成三个区域:bootloader,userdata,application。
这里我们的bootloader主要用于IAP(In Application Program),区别于ISP,IAP是我们自己可以控制的区域,里面的逻辑都是我们自己去编写处理,而ISP是芯片出厂的时候直接固化在芯片内部的一小段启动引导代码,如果我们将STM32的启用引脚配置成“boot0=1,boot1=0”,那么系统就会进入ISP模式,此时我们使用ST官方提供的对应指令去执行刷机操作。
如果我们自定义一个IAP在FLASH里面,那么我们完全可以做到联网自动升级,这就需要我们在IAP里面执行联网、下载、写FLASH等操作了,也可以自定义刷机工具,将自己的系统固件通过IAP刷入,这对于售后服务点应该是一种很友好的处理方式。
分区规划
/* FLASH分区规划 +--------------------+ FLASH最大地址 | | | | | APPLICATION | (应用程序放这里) | | | | +--------------------+ | USER DATA | (用户数据放这里) +--------------------+ | | | BOOTLOADER | (IAP固件放这里) | | +--------------------+ 0x0800_0000, FLASH起始地址 user data区域可能会被经常写入数据,而写入数据一般是要先擦除的。 在没有其他外部存储的时候,折中的办法就是在FLASH上开辟一段固定的空间来使用。 之所以放在前面,是因为STM32的MCU一般前面部分的段比较小,擦除时会更快,而且用户数据量一般也不会太大。 */
这里记录下我自己实际使用的一些关键代码。
1 #define BOOLOADER_REGION_ADDR (0x08000000) 2 #define BOOLOADER_REGION_SIZE (1024 * 32) 3 4 #define USERDATA_REGION_ADDR (BOOLOADER_REGION_ADDR + BOOLOADER_REGION_SIZE) 5 #define USERDATA_REGION_SIZE (1024 * 16) 6 7 #define APPLICATION_REGIOIN_ADDR (USERDATA_REGION_ADDR + USERDATA_REGION_SIZE) 8 9 10 11 12 /* 13 BOOTLOADER.h 14 */ 15 static bool jump_to_application(void) 16 { 17 /* 18 参考连接: 19 https://www.cnblogs.com/foxclever/p/13173493.html 20 https://blog.csdn.net/weixin_38222172/article/details/103636362 21 https://www.cnblogs.com/smulngy/p/5700283.html 22 */ 23 uint32_t appStackAddr = *((volatile const uint32_t * const)APPLICATION_REGIOIN_ADDR); 24 25 /* 26 堆栈地址合法性检查 27 */ 28 if (SRAM_BASE_ADDRESS == (appStackAddr & 0x2FFE0000) && (0x00 == (appStackAddr & 0x03))) 29 { 30 RCC_DeInit(); 31 __set_PRIMASK(TRUE); /*禁用所有中断*/ 32 __set_MSP(appStackAddr); /*设置堆栈地址*/ 33 ((FuncPtr)(*((volatile const uint32_t * const)(mAppAddr + 4))))(); /*跳转*/ 34 35 return true; 36 } 37 else 38 { 39 return false; 40 } 41 } 42 43 int main(void) 44 { 45 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); 46 47 /*一些必要的处理逻辑*/ 48 49 /*跳转到APP区域*/ 50 if (!jump_to_application()) 51 { 52 while(1) 53 { 54 } 55 } 56 57 return 0; 58 } 59 60 61 /* 62 APPLICATION.c 63 */ 64 int main(void) 65 { 66 /* 67 1、在bootloader里面关闭了全局中断,所以这里要打开。 68 2、要重新配置中断向量表(如果在bootloader里面没用到中断,我觉得不配置也是可以的) 69 */ 70 NVIC_SetVectorTable(NVIC_VectTab_FLASH, APPLICATION_REGIOIN_ADDR); 71 __set_PRIMASK(FALSE); 72 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); 73 74 /*一些必要的处理逻辑*/ 75 76 return 0; 77 }
里面的RCC_DeInit函数是STM32的标准库里面的函数,在stm32f4xx_rcc.h里面声明。
里面的 __set_PRIMASK 和 __set_MSP 两个函数定义在STM32官方库的 CMSIS\core_cmFunc.h 里面。
__attribute__( ( always_inline ) ) __STATIC_INLINE void __set_PRIMASK(uint32_t priMask) { __ASM volatile ("MSR primask, %0" : : "r" (priMask) : "memory"); } __attribute__( ( always_inline ) ) __STATIC_INLINE void __set_MSP(uint32_t topOfMainStack) { __ASM volatile ("MSR msp, %0\n" : : "r" (topOfMainStack) : "sp"); }
typedef void (*FuncPtr)(void);
当然我们使用keil时对应也要修改地址,一共两个地方:
(1)修改工程选项下的“Target”标签中的ROM起始地址和大小;
(2)修改工程选项下的“Debug”中J-link等刷机调试工具的设置对话框里面的“Flash Download”里的地址。
对应的APPLICATION和BOOTLOADER工程都要修改。
如果转载,请注明出处。https://www.cnblogs.com/ssdq/