一、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
接收過程里會做這些事:
- 檢查程序是不是完整(比如校驗 CRC)
- 擦掉舊程序(把 App 區的 Flash 擦了)
- 把新程序一點點寫進去
- 寫完了,打個勾:“升級完成了!”
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(閃燈)測試跳轉是否成功