STM32 Bootloader:使用文件头加载并启动应用程序

文章目录

  • [STM32 Bootloader:使用文件头加载并启动应用程序的完整解析](#STM32 Bootloader:使用文件头加载并启动应用程序的完整解析)
    • 一、系统整体流程
    • [二、镜像头结构 image\_header\_t](#二、镜像头结构 image_header_t)
    • [三、Bootloader 主函数流程](#三、Bootloader 主函数流程)
      • [1. 初始化 UART](#1. 初始化 UART)
      • [2. 调用启动函数](#2. 调用启动函数)
      • [3. 拷贝 APP 并跳转启动](#3. 拷贝 APP 并跳转启动)
    • [四、跳转执行 APP 的实现](#四、跳转执行 APP 的实现)
    • 五、总结与扩展思路

明白了,以下是去除表情后的正式技术文章版本:


STM32 Bootloader:使用文件头加载并启动应用程序的完整解析

在嵌入式系统中,Bootloader 是系统启动的第一段程序,它的主要职责是加载应用程序、校验完整性以及为远程升级提供支持。本文将结合一个基于 STM32 的 Bootloader 实例,详细讲解如何借助镜像头(Image Header)从 Flash 中加载并执行主应用程序。


一、系统整体流程

本文的 Bootloader 实现具有以下基本功能流程:

  1. 初始化 UART,输出启动信息;
  2. 从指定的 Flash 地址读取应用程序头部结构;
  3. 解析镜像头部,获取程序加载地址和大小;
  4. 将应用程序从 Flash 拷贝到 RAM;
  5. 设置中断向量表并跳转到应用程序入口地址。

流程图如下:

复制代码
启动 Bootloader
      ↓
读取 image_header_t
      ↓
解析 ih_load / ih_size
      ↓
Flash → RAM 拷贝程序数据
      ↓
配置向量表
      ↓
跳转执行 APP

二、镜像头结构 image_header_t

为了描述应用程序的信息,Bootloader 使用一个自定义的数据结构 image_header_t,包含如下字段:

c 复制代码
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 函数来转换大端字节序为当前平台字节序:

c 复制代码
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

c 复制代码
uart_init();
putstr("bootloader\r\n");

用于串口输出调试信息。

2. 调用启动函数

c 复制代码
unsigned int app_pos = 0x08040000;
relocate_and_start_app(app_pos);

指定 APP 存放在 Flash 的 0x08040000 位置。

3. 拷贝 APP 并跳转启动

relocate_and_start_app 是整个 Bootloader 的核心函数,负责:

  • 解析头部信息;
  • 读取加载地址和大小;
  • 拷贝程序数据到目标 RAM 区域;
  • 设置向量表基地址;
  • 跳转到新的应用入口。
c 复制代码
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:

c 复制代码
void copy_app(int *from, int *to, int len) {
    for (int i = 0; i < len/4+1; i++) {
        to[i] = from[i];
    }
}

四、跳转执行 APP 的实现

assembly 复制代码
start_app PROC
    EXPORT start_app

    ; 设置向量表地址
    ldr r3, =0xE000ED08  ; VTOR 寄存器地址
    str r0, [r3]         ; 写入新的向量表地址

    ldr sp, [r0]         ; 设置新栈顶
    ldr r1, [r0, #4]     ; 获取复位向量(入口地址)
    BX r1                ; 跳转执行应用

    ENDP

这段汇编设置了新的中断向量表,并将控制权转移到应用程序。


五、总结与扩展思路

该 Bootloader 实现了基础但关键的功能:从 Flash 加载带有文件头的应用程序,并跳转执行。这种结构使得:

  • 多固件管理更加方便;
  • 支持版本号校验、CRC 校验;
  • 可进一步扩展支持压缩、加密等功能;
  • 便于在线升级(IAP)系统实现。

后续可扩展的方向:

  1. 加入头部校验(如 CRC)确保数据完整性;
  2. 支持多应用启动(例如主应用 + 备份应用);
  3. 添加通信接口,如通过串口、USB、以太网接收新固件;
  4. 使用加密技术保护固件安全性。

如需进一步学习如何构建符合自己需求的 Bootloader,可结合具体芯片手册及启动流程,调整 向量表地址RAM 空间划分启动模式 等参数。

如果你希望支持更多启动方式,例如从 SD 卡、串口或外部 Flash 启动,也可以参考该结构扩展模块加载逻辑。

相关推荐
无敌贵点大王3 小时前
RTThread学习记录11——RT-Thread 设备模型吃透:UART/ADC/PWM/PIN 到底有什么区别?
c语言·stm32·学习·链表
恶魔泡泡糖7 小时前
stm32F103C8T6标准库串口接收之中断方式2
stm32·单片机·嵌入式硬件
充哥单片机设计7 小时前
【STM32开源项目】智能小区充电桩
stm32·单片机·嵌入式硬件·毕业设计·小区充电桩·智能小区充电桩
充哥单片机设计9 小时前
【STM32开源项目】智能语音台灯
stm32·单片机·嵌入式硬件·毕业设计·单片机设计·智能语音台灯
Brilliantwxx11 小时前
【STM32】 SPI阻塞式通信与HAL源码 (源码分析)
stm32·单片机·嵌入式硬件
WWJA王文举12 小时前
Bootloader、App 和升级分区之间是什么关系?
stm32·freertos·嵌入式开发·在线升级
LCG元13 小时前
STM32F103 NTC 热敏电阻测温实战:分压网络设计、Steinhart-Hart 标定与 ADC 采样优化实测
stm32·单片机·嵌入式硬件
怀民民民14 小时前
嵌入式软件学习路线与项目实践记录:STM32、FreeRTOS、Linux 与 OpenMV
stm32·freertos·嵌入式软件·嵌入式linux·openmv
辰域电子15 小时前
STM32项目开源:实验室消防预警控制系统(代码 + 原理图 + 仿真)
stm32·单片机·嵌入式硬件·开源·proteus
ysu_03141 天前
TinyML 模型部署:从 Edge Impulse 到 STM32F103
驱动开发·stm32·嵌入式硬件·mcu·硬件架构·硬件工程·dsp开发