文章目錄
- STM32 Bootloader:使用文件頭加載并啟動應用程序的完整解析
- 一、系統整體流程
- 二、鏡像頭結構 image\_header\_t
- 三、Bootloader 主函數流程
- 1. 初始化 UART
- 2. 調用啟動函數
- 3. 拷貝 APP 并跳轉啟動
- 四、跳轉執行 APP 的實現
- 五、總結與擴展思路
明白了,以下是去除表情后的正式技術文章版本:
STM32 Bootloader:使用文件頭加載并啟動應用程序的完整解析
在嵌入式系統中,Bootloader 是系統啟動的第一段程序,它的主要職責是加載應用程序、校驗完整性以及為遠程升級提供支持。本文將結合一個基于 STM32 的 Bootloader 實例,詳細講解如何借助鏡像頭(Image Header)從 Flash 中加載并執行主應用程序。
一、系統整體流程
本文的 Bootloader 實現具有以下基本功能流程:
- 初始化 UART,輸出啟動信息;
- 從指定的 Flash 地址讀取應用程序頭部結構;
- 解析鏡像頭部,獲取程序加載地址和大小;
- 將應用程序從 Flash 拷貝到 RAM;
- 設置中斷向量表并跳轉到應用程序入口地址。
流程圖如下:
啟動 Bootloader↓
讀取 image_header_t↓
解析 ih_load / ih_size↓
Flash → RAM 拷貝程序數據↓
配置向量表↓
跳轉執行 APP
二、鏡像頭結構 image_header_t
為了描述應用程序的信息,Bootloader 使用一個自定義的數據結構 image_header_t
,包含如下字段:
typedef struct image_header {__be32 ih_magic; // 魔數,用于識別合法鏡像__be32 ih_hcrc; // 頭部 CRC 校驗值__be32 ih_time; // 鏡像生成時間戳__be32 ih_size; // 應用程序大小(單位:字節)__be32 ih_load; // 應用加載地址__be32 ih_ep; // 程序入口地址__be32 ih_dcrc; // 數據部分 CRC 校驗uint8_t ih_os; // 操作系統標識uint8_t ih_arch; // CPU 架構uint8_t ih_type; // 鏡像類型uint8_t ih_comp; // 壓縮類型uint8_t ih_name[32]; // 鏡像名稱
} image_header_t;
為了確保頭部字段正確讀取,還實現了 be32_to_cpu
函數來轉換大端字節序為當前平臺字節序:
unsigned int be32_to_cpu(unsigned int x) {unsigned char *p = (unsigned char *)&x;return (p[0] << 24) + (p[1] << 16) + (p[2] << 8) + p[3];
}
三、Bootloader 主函數流程
1. 初始化 UART
uart_init();
putstr("bootloader\r\n");
用于串口輸出調試信息。
2. 調用啟動函數
unsigned int app_pos = 0x08040000;
relocate_and_start_app(app_pos);
指定 APP 存放在 Flash 的 0x08040000
位置。
3. 拷貝 APP 并跳轉啟動
relocate_and_start_app
是整個 Bootloader 的核心函數,負責:
- 解析頭部信息;
- 讀取加載地址和大小;
- 拷貝程序數據到目標 RAM 區域;
- 設置向量表基地址;
- 跳轉到新的應用入口。
void relocate_and_start_app(unsigned int pos) {image_header_t *head = (image_header_t *)pos;unsigned int load = be32_to_cpu(head->ih_load);unsigned int size = be32_to_cpu(head->ih_size);unsigned int new_pos = pos + sizeof(image_header_t);putstr("load = "); puthex(load); putstr("\r\n");putstr("size = "); puthex(size); putstr("\r\n");copy_app((int *)new_pos, (int *)load, size);start_app(new_pos); // 跳轉執行
}
copy_app
函數用于將應用程序從 Flash 拷貝到 RAM:
void copy_app(int *from, int *to, int len) {for (int i = 0; i < len/4+1; i++) {to[i] = from[i];}
}
四、跳轉執行 APP 的實現
start_app PROCEXPORT start_app; 設置向量表地址ldr r3, =0xE000ED08 ; VTOR 寄存器地址str r0, [r3] ; 寫入新的向量表地址ldr sp, [r0] ; 設置新棧頂ldr r1, [r0, #4] ; 獲取復位向量(入口地址)BX r1 ; 跳轉執行應用ENDP
這段匯編設置了新的中斷向量表,并將控制權轉移到應用程序。
五、總結與擴展思路
該 Bootloader 實現了基礎但關鍵的功能:從 Flash 加載帶有文件頭的應用程序,并跳轉執行。這種結構使得:
- 多固件管理更加方便;
- 支持版本號校驗、CRC 校驗;
- 可進一步擴展支持壓縮、加密等功能;
- 便于在線升級(IAP)系統實現。
后續可擴展的方向:
- 加入頭部校驗(如 CRC)確保數據完整性;
- 支持多應用啟動(例如主應用 + 備份應用);
- 添加通信接口,如通過串口、USB、以太網接收新固件;
- 使用加密技術保護固件安全性。
如需進一步學習如何構建符合自己需求的 Bootloader,可結合具體芯片手冊及啟動流程,調整 向量表地址
、RAM 空間劃分
和 啟動模式
等參數。
如果你希望支持更多啟動方式,例如從 SD 卡、串口或外部 Flash 啟動,也可以參考該結構擴展模塊加載邏輯。