STM32 Bootloader:使用文件头加载并启动应用程序
文章目录
- 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 启动,也可以参考该结构扩展模块加载逻辑。