当前位置: 首页 > java >正文

什么是 Bootloader?怎么把它移植到 STM32 上?

一、Bootloader 是啥?它都干了些啥?

想象一下你的 MCU(比如 STM32)是一个小机器人,上电之后第一件事,它不会立马开始“干正事”(运行你的主程序),而是先去运行一个“开场引导程序”——这就是 Bootloader。

它主要负责下面这些事:

  • 启动最基础的硬件:比如时钟、串口、Flash 这些,像是“穿衣洗脸”。
  • 判断要不要升级程序:比如你按了个按钮、发了个串口命令,它就不跳到主程序,而是“停在门口”,准备接收新程序。
  • 接收并写入新程序:它能从串口、USB、CAN、SD 卡等接收固件,然后擦掉旧程序,把新程序烧进去。
  • 最后跳转到主程序:一切准备就绪,它就把控制权交给你写的主程序,让它正式运行。

通俗讲,它就像是**“程序界的门房”**,开门、分发信件(固件)、开灯、安排进屋(跳转),全由它负责。


二、Bootloader 跟主程序的位置是怎么安排的?

在 STM32 中,Flash 是按地址划分的。一般我们这样安排:

Bootloader 区域: 0x08000000 ~ 0x08003FFF
主程序区域(App): 0x08004000 ~ Flash 结尾

也就是说,Bootloader 占前面 16KB 的空间(你可以设更多),主程序从后面接着跑。它们不会互相干扰。

Bootloader 的典型流程就像这样:

int main(void)
{HAL_Init();                    // 初始化硬件SystemClock_Config();         // 配置时钟MX_USART2_UART_Init();        // 初始化串口if (check_upgrade_flag())     // 判断是否需要升级{enter_upgrade_mode();     // 进入升级模式}jump_to_application();        // 跳到主程序区运行
}

三、Bootloader 做事情的重点是啥?

1. 固件怎么接收?

它可以从很多“入口”接收程序,比如:

  • 串口(UART)
  • USB(DFU 模式)
  • CAN、I2C、SPI
  • SD 卡、外部 Flash

接收过程里会做这些事:

  1. 检查程序是不是完整(比如校验 CRC)
  2. 擦掉旧程序(把 App 区的 Flash 擦了)
  3. 把新程序一点点写进去
  4. 写完了,打个勾:“升级完成了!”

2. 怎么跳转到主程序?

最关键的是要设置好跳转地址和栈指针。示例代码如下:

#define APP_ADDR 0x08004000  // 主程序起始地址typedef void (*pFunction)(void);
pFunction JumpToApplication;
uint32_t JumpAddress;HAL_DeInit();               // 关闭外设
__disable_irq();            // 禁用中断JumpAddress = *(__IO uint32_t*)(APP_ADDR + 4);
JumpToApplication = (pFunction)JumpAddress;__set_MSP(*(__IO uint32_t*)APP_ADDR); // 设置栈
JumpToApplication();                  // 跳转!

要注意:

  • 0x08004000 第一个 4 字节是主程序的栈指针(MSP)
  • 第二个 4 字节是主程序的启动地址(Reset_Handler)
  • 跳转之前要把中断关掉、外设关掉,不然主程序容易“误会”你还没交接完

四、怎么把 Bootloader 移植到 STM32 上?

如果你自己写 Bootloader,要让它配合你的主程序跑起来,大概分这几步:

Step 1:规划 Flash 分布

比如我们规划:

  • Bootloader 占 0x08000000 ~ 0x08003FFF(16KB)
  • 主程序从 0x08004000 开始

这样你就得去你的 App 工程里修改启动地址,不然你主程序会被烧到 Bootloader 区,冲突了。

Step 2:写 Bootloader 的功能

你得实现:

  • 初始化串口
  • 收数据 + 校验
  • 擦除 Flash
  • 写入新固件
  • 跳转主程序

Step 3:改主程序的配置

  • 启动文件 .s 或 .ld 文件中,把起始地址改成 0x08004000
  • 设置中断向量表地址偏移:SCB->VTOR = 0x08004000;

不改这些,你的主程序可能跳转不了,也收不到中断。

Step 4:验证!

Bootloader 烧进去 → 用它烧主程序 → 看能不能正常跳转、运行

记得保留串口 printf 打印,出问题好排查。


五、移植过程中常见的“坑”和解决方案

问题原因
跳转失败中断没关 / 地址没设对 / VTOR 没设置
Flash 写失败没解锁 / 写保护 / 地址错误
主程序不跑启动文件地址没改 / 向量表没偏移
烧完程序没反应没跳转、程序错烧、校验失败

解决方法:

  • 多用串口打印调试信息
  • 多测试单步跳转和Flash写入
  • 主程序先写一个最小的 Blinky(闪灯)测试跳转是否成功
http://www.xdnf.cn/news/15171.html

相关文章:

  • 《人件》第六章 快乐地工作
  • Python-难点-uinttest
  • 秋招笔试考什么?如何针对性去练习?
  • w459客户管理系统
  • xml映射文件的方式操作mybatis
  • 多线程进阶——JUC的常见类
  • 跨系统开发代码换行符如何解决
  • docker-compose方式搭建lnmp环境——筑梦之路
  • 2025 XYD Summer Camp 7.10 筛法
  • Go语言生态成熟度分析:为何Go还无法像Java那样实现注解式框架?
  • 系统分析师-计算机系统-计算机系统概述存储系统
  • 《Java Web程序设计》实验报告二 学习使用HTML标签、表格、表单
  • 【学习笔记】Linux命令
  • 蓝牙BT UUID的含义以及使用方法案例说明
  • JavaScript加强篇——第七章 浏览器对象与存储要点
  • 《Java Web程序设计》实验报告四 Java Script前端应用和表单验证
  • OpenCL study - code02
  • docker网络与数据持久化
  • 大数据时代UI前端的智能化服务升级:基于用户情境的主动服务设计
  • Elasticsearch 的 `modules` 目录
  • 使用Matlab整车模型进行电动汽车能耗仿真测试方法
  • 【飞算JavaAI】一站式智能开发,驱动Java开发全流程革新
  • 鸿蒙的NDK开发初级入门篇
  • Apache Iceberg数据湖高级特性及性能调优
  • 如何使用postman做接口测试?
  • 《Spring 中上下文传递的那些事儿》Part 8:构建统一上下文框架设计与实现(实战篇)
  • 安全初级作业1
  • Linux中的git命令
  • 【LeetCode 热题 100】24. 两两交换链表中的节点——(解法一)迭代+哨兵
  • 设计模式 - 面向对象原则:SOLID最佳实践