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 }
View Code

 里面的RCC_DeInit函数是STM32的标准库里面的函数,在stm32f4xx_rcc.h里面声明。

里面的 __set_PRIMASK 和 __set_MSP 两个函数定义在STM32官方库的 CMSIScore_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
" : : "r" (topOfMainStack) : "sp");
}
typedef void (*FuncPtr)(void);

当然我们使用keil时对应也要修改地址,一共两个地方:

(1)修改工程选项下的“Target”标签中的ROM起始地址和大小;

(2)修改工程选项下的“Debug”中J-link等刷机调试工具的设置对话框里面的“Flash Download”里的地址。

对应的APPLICATION和BOOTLOADER工程都要修改。

如果转载,请注明出处。https://www.cnblogs.com/ssdq/
原文地址:https://www.cnblogs.com/ssdq/p/13738205.html