1. 什么是Bootloader
Bootloader是硬件启动的引导程序,是运行操作系统的前提。在操作系统内核或用户应用程序运行之前运行的一段小代码。对硬件进行相应的初始化和设定,最终为操作系统准备好环境。
2. Bootloader的特点
Bootloader不属于操作系统,一般采用汇编语言和C语言开发。需要针对特定的硬件平台编写。在移植过程时,首先为开发板移植Bootloader。Bootloader不但依赖于CPU的体系架构,而且依赖于嵌入式系统板级设备的配置。
3. STM32中bootloader的内存分配
stm32默认的是从0x08000000开始启动程序,所以bootloader也存在于这个地址,大小可以设置。如下图举例分配 48K的大小空间给Bootloader
还有一种分配方式:镜像的备份 Firmware ---> Application Bak ---> SysRest ----> Bootloader -----> Check if new Firmware -----> Move App Bak to App area
这种方式需要更大的存储空间,如果MCU内置FLASH 不够备份Firmware则需要外置Flash,将Firmware备份在外置FLASH。
根据实际MCU的Flash的大小和固件的大小来分配空间。一般可以把固件信息(app固件的StartAddr, EndAddr, FirmwareSize, CRC等)存放在Free Spae.
bootloader的作用一般是用作更新APP,和初始化后设定跳转到对应的APP。如果APP不加更新功能的话也可以直接将APP写入到0x08000000这个地址里。更新程序就是数据包的接收、校验、写入,全部写入完成后检查APP的启动向量为合格就可以跳转到APP里。
4. Bootloader的跳转简单实现
4.1 Bootloader
我基于STM32Cube配置的外设,IDE用的STM32SW4,STM32F103RCT6。
在实现IAP功能前,先实现跳转。这里先不涉及固件更新。
/*FLASH : 0x8000000 --- 0x8040000 Total Size: 256K
*RAM : 0x20000000 --- 0x2000C000 Total Size: 48K
*Bootloader: 0x8000000 --- 0x8008000 Total Size: 32K
1 /* Includes ------------------------------------------------------------------*/
2 #include "main.h"
3 #include "stm32f1xx_hal.h"
4 #include "usart.h"
5 #include "gpio.h"
6
7 /* USER CODE BEGIN Includes */
8 #include "stdio.h"
9 /* USER CODE END Includes */
10
11 /* USER CODE BEGIN PFP */
12 /* Private function prototypes -----------------------------------------------*/
13 pFunction jump2app;
14 void (*jump2app)();
15 /* USER CODE END PFP */
16
17
18
19 /* USER CODE BEGIN 0 */
20 #ifdef __GNUC__
21 #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
22 #else
23 #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
24 #endif
25
26 /*retargets the C library printf function to the USART*/
27 PUTCHAR_PROTOTYPE
28 {
29 HAL_UART_Transmit(&huart1,(uint8_t*)&ch, 1, 0xFFFF);
30 return ch;
31 }
32
33 //FLASH : 0x8000000 --- 0x8040000 Total Size: 256K
34 //RAM : 0x20000000 --- 0x2000C000 Total Size: 48K
35 //Bootloader : 0x8000000 --- 0x8008000 Total Size: 32K
36 37 #define ApplicationAddress 0x8008000
38
39
40 void iap_load_app(uint32_t appAddr)
41 {
42 printf("first word : 0x%xn",(*(uint32_t*)appAddr));
43 if (((*(__IO uint32_t*)ApplicationAddress) & 0x2FFE0000 ) == 0x20000000)
44 {
45 printf("IAP load APP!!!n");
46
47 __disable_irq();
48
49 jump2app = (void (*)())*(__IO uint32_t*) (appAddr + 4);
50
51 __set_MSP(*(__IO uint32_t*) appAddr);
52
53 jump2app();
54 }
55 }
56 /* USER CODE END 0 */
57
58 /**
59 * @brief The application entry point.
60 *
61 * @retval None
62 */
63 int main(void)
64 {
65 /* USER CODE BEGIN 1 */
66
67 /* USER CODE END 1 */
68
69 /* MCU Configuration----------------------------------------------------------*/
70
71 /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
72 HAL_Init();
73
74 /* USER CODE BEGIN Init */
75
76 /* USER CODE END Init */
77
78 /* Configure the system clock */
79 SystemClock_Config();
80
81 /* USER CODE BEGIN SysInit */
82
83 /* USER CODE END SysInit */
84
85 /* Initialize all configured peripherals */
86 MX_GPIO_Init();
87 MX_USART1_UART_Init();
88 /* USER CODE BEGIN 2 */
89
90 /* USER CODE END 2 */
91
92 /* Infinite loop */
93 /* USER CODE BEGIN WHILE */
94 while (1)
95 {
96 printf("I am bootloader,jump to app after 5 seconds!n");
97
98 HAL_Delay(1000);
99
100 printf("1rn");
101
102 HAL_Delay(1000);
103
104 printf("2rn");
105
106 HAL_Delay(1000);
107
108 printf("3rn");
109
110 HAL_Delay(1000);
111
112 printf("4rn");
113
114 HAL_Delay(1000);
115
116 printf("ready to jump!n");
117
118 iap_load_app(ApplicationAddress);
119 /* USER CODE END WHILE */
120
121 /* USER CODE BEGIN 3 */
122
123 }
124 /* USER CODE END 3 */
125
126 }
修改ld文件 STM32F103RCTx_Flash.ld
编译烧录。首先将STM32F103RCT6的FLASH全部擦除如下图,然后用STM32SW4烧录Bootloader
调试Bootloader如下图
4.2 Application
APP主要是修改ld文件,Bootloader分配了 32Kb, 剩余224K的先全分配给App, 实现简单跳转。
int main(void)
{
//NVIC_SetVectorTable(NVIC_VectTab_FLASH,0x2000);
/* USER CODE BEGIN 1 */
SCB->VTOR = ((uint32_t)0x8000000) | (0x8000 & (uint32_t)0x1FFFFF80);
/* USER CODE END 1 */
/* MCU Configuration----------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
__enable_irq();
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
printf("I am new APP !nr");
HAL_Delay(1000);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
再将APP烧录,Reset