1. Bootloader基础框架搭建
任务目标
本案例实现一个基于STM32F103系列MCU的最小Bootloader框架,包含三个核心能力:启动代码初始化、中断向量表重映射、以及从Bootloader跳转到应用程序。最终通过串口打印和LED翻转验证跳转是否成功。
环境依赖
- 硬件:STM32F103C8T6最小系统板(蓝丸),板载LED接PC13,USART1接PA9/PA10
- 软件:STM32CubeIDE 1.13+ 或 Keil MDK 5.30+,STM32标准外设库或HAL库均可
- 应用区起始地址:
0x08008000(Bootloader占用前32KB)
关键完整代码
// main.c - Bootloader主程序
#include "stm32f1xx_hal.h"
#define APP_ADDRESS 0x08008000U
#define APP_FLAG_ADDR 0x20000000U // RAM中跳转标志
typedef void (*pFunction)(void);
// 跳转标志写入(由应用层在复位前设置)
void SetJumpFlag(void) {
*(__IO uint32_t*)APP_FLAG_ADDR = 0xDEADBEEF;
}
// 跳转至应用程序
void JumpToApp(void) {
pFunction app_entry;
uint32_t app_stack = *(volatile uint32_t*)APP_ADDRESS;
// 检查栈顶地址合法性(RAM范围0x20000000-0x20010000)
if ((app_stack & 0x2FFE0000) != 0x20000000) {
Error_Handler();
}
// 设置MSP为应用栈顶
__set_MSP(app_stack);
// 获取复位向量并跳转
app_entry = (pFunction)(*(volatile uint32_t*)(APP_ADDRESS + 4));
app_entry();
}
int main(void) {
HAL_Init();
SystemClock_Config();
// 初始化LED和串口
LED_Init();
UART_Init();
// 检查跳转标志
if (*(__IO uint32_t*)APP_FLAG_ADDR == 0xDEADBEEF) {
// 清除标志并跳转
*(__IO uint32_t*)APP_FLAG_ADDR = 0;
HAL_UART_Transmit(&huart1, "Jump to APP...\r\n", 17, 100);
HAL_Delay(10);
JumpToApp();
}
// Bootloader主循环(无应用时运行)
while (1) {
HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
HAL_UART_Transmit(&huart1, "Bootloader running...\r\n", 24, 100);
HAL_Delay(500);
}
}
// system_stm32f1xx.c - 中断向量表重映射(关键片段)
// 在SystemInit()函数末尾添加:
void SystemInit(void) {
// ...原有代码...
// 若当前运行在Bootloader且需要重映射到APP
if ((*(volatile uint32_t*)APP_FLAG_ADDR) == 0xDEADBEEF) {
// 设置向量表偏移(仅适用于具有VTOR的Cortex-M3 r2p1+)
SCB->VTOR = APP_ADDRESS;
}
}
链接脚本配置
/* STM32F103C8Tx_FLASH.ld - Bootloader链接脚本关键修改 */
MEMORY
{
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 32K /* Bootloader占前32KB */
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 20K
}
运行与验证
- 编译并烧录Bootloader到0x08000000(默认烧录地址)
- 打开串口助手(115200-8-N-1),复位开发板,应周期性收到
Bootloader running... - 在应用工程中调用
SetJumpFlag()后执行软复位(NVIC_SystemReset),Bootloader检测到标志后跳转至0x08008000 - 跳转成功标志:串口输出
Jump to APP...后,LED翻转频率变化(应用区程序控制)
通过判定标准
- Bootloader独立运行时LED以2Hz翻转,串口持续输出提示信息
- 设置跳转标志并复位后,程序能进入应用区执行(应用区LED闪烁频率不同)
- 若应用区无效(栈顶地址非法),Bootloader不跳转并继续运行自身循环
常见问题
- 跳转后死机:检查应用工程中断向量表偏移是否设置为0x08008000,且编译链接地址正确
- 外设初始化冲突:跳转前需反初始化Bootloader使用的外设(HAL_UART_DeInit等),避免应用初始化失败
- VTOR不可用:Cortex-M3 r2p0及更早版本需在启动文件中手动复制向量表到RAM并重映射
上述SVG展示了Bootloader与应用程序在Flash中的分区布局,以及跳转时的关键执行步骤。Bootloader占用低地址区(含中断向量表),应用区从0x08008000开始,跳转时需重新定位栈指针和入口地址。