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 启动,也可以参考该结构扩展模块加载逻辑。

相关推荐
咸蛋-超人19 小时前
聊一聊 - STM32的堆和栈空间怎么分配
stm32·单片机·嵌入式硬件
raindrops.21 小时前
STM32之LL库使用(二)
stm32·单片机·嵌入式硬件
橘色的喵1 天前
嵌入式二级 Bootloader (SBL) 的设计与实现:基于裸机环境的安全固件管理
安全·bootloader·二级boot
单片机系统设计1 天前
基于STM32的水质检测系统
网络·stm32·单片机·嵌入式硬件·毕业设计·水质检测
Y1rong1 天前
STM32之IIC
stm32·单片机
光子物联单片机1 天前
STM32传感器模块编程实践(十七)DIY智能电子门锁套件模型
c语言·stm32·单片机·嵌入式硬件·mcu
raindrops.1 天前
STM32之LL库使用(一)
stm32·单片机·嵌入式硬件
麻辣长颈鹿Sir1 天前
STM32出现FLASH擦除失败异常现象分析及解决方法
stm32·单片机·嵌入式硬件·flash写入失败·stm32g070·类内构造函数定义域异常
码咔吧咔1 天前
STM32 MCU 的引脚分类
stm32·单片机·嵌入式硬件
意法半导体STM321 天前
【文末送NUCLEO-G431RB】一文说明白STM32G4双Bank启动与升级 LAT1596
前端·数据库·stm32·单片机·嵌入式硬件·mcu·stm32开发