BootLoader-仅跳转
2025/10/20大约 3 分钟
BootLoader-仅跳转
硬件:
- stm32f407(嘉立创天空星)
- HC-05蓝牙模块
软件: - 暂时使用python简陋演示功能
为什么要有bootloader
- 类似于电脑的boot,可以让我们很方便的去重装系统,可以用u盘重装系统,可以在线重装系统等
- 可以把一些固定参数放到bootloader里,比如屏幕亮度,初始参数等等,可以专注于APP的开发
前置知识
单片机组成
电脑组成
stm32内部
stm32启动流程原理
参考:
- STM32F407 探索者开发指南V1.2.pdf
- STM32F4xx参考手册_V4(中文版).pdf
flash和sram的位置
嵌入式SRAM是被映射在$0x2000 0000$上的
嵌入式flash是被映射在$0x0800 0000$
启动流程图

问题
为什么要找MSP?

为什么要找复位中断向量?

为什么可以根据boot引脚电平的不同到指定位置寻找MSP和复位中断向量?

因为芯片上电后cpu会先去到0x00000000和0x00000004寻找MSP和复位中断向量表的地址;
系统上电先去判断boot0和boot1引脚,根据引脚电平的不同,把不同的地址映射到0x00000000,比如boot0为0,那么就把0x08000000映射到0x00000000,这样cpu就会去flash寻找MSP和中断向量表的地址;如果boot0和boot1都为1, 那么就把0x20000000映射到0x00000000,这样cpu就会去sram里去寻找MSP和中断向量表的地址
简单跳转代码
优化大小
使用O3优化可以减小boot大小
获取二进制文件
fromelf --bin -o "$L@L.bin" "#L
Boot
新建一个正常点灯程序,命名为boot,0x08000000为下载位置,0x8000为下载的大小
// app的程序在芯片flash的位置
#define APP_ADDRESS 0x08008000U
typedef void (*pFunction)(void);
void JumpToApplication(void) {
// 1. 检查应用程序地址是否有效
// 应用程序的栈顶地址位于其起始地址的第一个字
if (((*(__IO uint32_t*)APP_ADDRESS) & 0x2FFE0000) == 0x20000000) {
// 2. 禁用所有中断(防止 Bootloader 中断干扰 App)
__disable_irq();
// 3. 关闭 SysTick、清除挂起的中断(干净的执行环境)
SysTick->CTRL = 0;
SysTick->LOAD = 0;
SysTick->VAL = 0;
for (uint32_t i = 0; i < 8; i++) {
NVIC->ICER[i] = 0xFFFFFFFF; // 禁用所有中断
NVIC->ICPR[i] = 0xFFFFFFFF; // 清除挂起标志
}
// 2. 将中断向量表重定向到应用程序地址
SCB->VTOR = APP_ADDRESS;
// 3. 获取应用程序的栈顶地址和复位处理函数地址
pFunction app_reset_handler = (pFunction)(*(__IO uint32_t*)(APP_ADDRESS + 4));
__set_MSP(*(__IO uint32_t*)APP_ADDRESS);
// 4.重新使能中断
__enable_irq();
// 5. 跳转到应用程序
app_reset_handler();
}else{
// 没有识别到app
}
}
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
JumpToApplication();
/* USER CODE END 2 */
while (1)
{
HAL_Delay(100);
HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_2);
}
}APP
正常新建一个点灯程序用来测试,命名为app,在target选项卡更改烧录位置:
烧录app后,如下操作验证:
