rovina d2b8bd7940 Initial commit: STM32 Bootloader extension module
Add a production-ready, educational bootloader extension for STM32 MCUs.

Core features:
- Custom binary protocol with CRC16/CRC32 verification
- AES-256 encryption for firmware security
- Dual-bank firmware management with rollback support
- Version management and firmware validation
- Modular architecture with BSP abstraction layer

Project structure:
- include/: Header files (bootloader.h, bsp_flash.h, bsp_uart.h)
- src/: Core implementation (bootloader, protocol, crypto, firmware manager)
- port/: MCU-specific adaptation layer (STM32F4xx)
- docs/: Documentation (integration guide, porting guide)

Supported platforms:
- STM32F4xx (primary)
- STM32F1xx (via porting)

Quick start:
1. Copy extension module to project
2. Configure bootloader_config.h
3. Modify linker script for APP_BASE_ADDR
4. Build and flash bootloader to 0x08000000

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-02 15:03:51 +08:00

STM32 Bootloader Extension

一个教学导向的、可移植的、生产就绪的Bootloader扩展模块

License Platform Language


目录


项目简介

这是一个专为教学目的设计的STM32 Bootloader扩展模块采用分层架构模块化设计,让您:

  • 理解Bootloader的核心原理
  • 掌握固件升级的完整流程
  • 学习安全启动的设计思想
  • 获得可直接用于生产环境的代码

为什么需要Bootloader

┌─────────────────────────────────────────────────┐
│  传统固件升级:需要拆卸设备、连接调试器        │
│  → 成本高、效率低、用户体验差                   │
├─────────────────────────────────────────────────┤
│  Bootloader升级串口/USB直接更新固件          │
│  → 无需拆卸、远程升级、用户友好                 │
└─────────────────────────────────────────────────┘

适用场景

  • IoT设备远程固件更新
  • 嵌入式产品现场升级
  • 需要安全启动的设备
  • 学习嵌入式Bootloader开发

核心特性

特性 描述 状态
自定义协议 高效可靠的数据传输协议
AES-256加密 固件传输全程加密保护
CRC32校验 数据完整性验证
双Bank备份 安全升级,失败可回滚
版本管理 固件版本控制
模块化设计 易于理解和移植
跨MCU支持 通过BSP抽象层适配

快速开始

5分钟集成到您的项目

步骤1: 复制扩展模块

# 将extensions目录复制到您的STM32项目根目录
cp -r extensions/ /path/to/your/project/

步骤2: 配置参数

编辑 extensions/bootloader/include/bootloader_config.h:

// 选择您的MCU系列
#define MCU_FAMILY_STM32F4XX   1
#define MCU_FAMILY_STM32F1XX   0

// 配置Flash布局
#define BOOTLOADER_SIZE_KB     32
#define APP_BASE_ADDR          0x08008000
#define BANK1_ADDR             0x08008000
#define BANK2_ADDR             0x08038000

// 配置串口参数
#define BOOT_UART_BAUDRATE     115200

步骤3: 修改main.c

#include "bootloader.h"

int main(void) {
    HAL_Init();
    SystemClock_Config();
    
    // === Bootloader入口 ===
    bootloader_init();
    if (bootloader_check_enter()) {
        // 进入Bootloader模式
        while (bootloader_get_state() != BOOT_STATE_JUMP_APP) {
            bootloader_process();
        }
    }
    // =====================
    
    // 您的应用代码...
    MX_GPIO_Init();
    MX_USART1_UART_Init();
    
    while (1) {
        // 主循环
    }
}

步骤4: 修改链接脚本

将应用程序的起始地址修改为 APP_BASE_ADDR:

/* 原始 */
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K

/* 修改为 */
FLASH (rx) : ORIGIN = 0x08008000, LENGTH = 992K

步骤5: 编译并烧录

# 编译Bootloader
cd extensions/bootloader
mkdir build && cd build
cmake .. -DMCU_FAMILY=stm32f4xx
make

# 烧录Bootloader到0x08000000
st-flash write bootloader.bin 0x08000000

架构设计

分层架构图

┌─────────────────────────────────────────────────────────┐
│                    应用层 (Application)                  │
│                    main.c / 用户代码                     │
├─────────────────────────────────────────────────────────┤
│                  API层 (bootloader.h)                   │
│         统一对外接口,屏蔽内部实现细节                    │
├─────────────────────────────────────────────────────────┤
│                  功能模块层 (MCU无关)                    │
│  ┌────────────┬────────────┬────────────┬───────────┐ │
│  │  Protocol  │ AES Crypto │  CRC Check │ Firmware  │ │
│  │  Handler   │   Engine   │   Module    │ Manager  │ │
│  └────────────┴────────────┴────────────┴───────────┘ │
├─────────────────────────────────────────────────────────┤
│                BSP抽象层 (bsp_*.h)                      │
│         定义硬件操作接口,实现解耦合                      │
├─────────────────────────────────────────────────────────┤
│                 移植适配层 (MCU相关)                     │
│  ┌──────────────┬──────────────┬──────────────┐       │
│  │  STM32F4xx   │  STM32F1xx   │   Others     │       │
│  │ flash_port   │ flash_port   │ flash_port    │       │
│  │ uart_port    │ uart_port    │ uart_port     │       │
│  └──────────────┴──────────────┴──────────────┘       │
└─────────────────────────────────────────────────────────┘

数据流图

上位机                           Bootloader                       应用
  │                                  │                            │
  │  ①加密固件                       │                            │
  ├─────────────────────────────────>│                            │
  │                                  │                            │
  │  ②发送数据包                     │                            │
  ├─────────────────────────────────>│                            │
  │                                  │ ③解密、校验               │
  │                                  ├──────┐                     │
  │                                  │      │                     │
  │                                  │<─────┘                     │
  │                                  │                            │
  │                                  │ ④写入Flash                 │
  │                                  ├──────┐                     │
  │                                  │      │                     │
  │                                  │<─────┘                     │
  │                                  │                            │
  │  ⑤应答确认                       │                            │
  │<─────────────────────────────────┤                            │
  │                                  │                            │
  │                                  │ ⑥跳转执行                  │
  │                                  ├───────────────────────────>│
  │                                  │                            │

Flash内存布局

STM32F407ZGTx (1MB Flash)

┌──────────────┬──────────────────┬─────────────────────┐
│ 地址范围      │ 用途             │ 大小                │
├──────────────┼──────────────────┼─────────────────────┤
│ 0x08000000   │ Bootloader       │ 32KB               │
│    ~         │ 启动引导程序      │ 包含加密/校验模块   │
│ 0x08007FFF   │                  │                    │
├──────────────┼──────────────────┼─────────────────────┤
│ 0x08008000   │ Bank1 - App      │ 192KB              │
│    ~         │ 主固件存储区      │ 当前运行版本        │
│ 0x08037FFF   │                  │                    │
├──────────────┼──────────────────┼─────────────────────┤
│ 0x08038000   │ Bank2 - Backup   │ 192KB              │
│    ~         │ 备份固件区        │ 升级临时存储        │
│ 0x08067FFF   │                  │ 回滚备份            │
├──────────────┼──────────────────┼─────────────────────┤
│ 0x08068000   │ Reserved         │ 608KB              │
│    ~         │ 预留空间          │ 可用于文件系统      │
│ 0x080FFFFF   │                  │                    │
└──────────────┴──────────────────┴─────────────────────┘

学习路径

推荐学习顺序

第1阶段理解基础概念
├── 阅读本文档了解Bootloader原理
├── 理解Flash内存布局
└── 学习启动流程和中断向量表

第2阶段搭建开发环境
├── 集成Bootloader到您的项目
├── 配置串口通信
└── 编译并烧录测试

第3阶段深入核心模块
├── protocol.c - 理解通信协议设计
├── bsp_flash.c - 掌握Flash操作
├── aes_crypto.c - 学习加密实现
└── firmware_mgr.c - 理解固件管理

第4阶段实践与扩展
├── 移植到其他MCU平台
├── 添加自定义功能
└── 开发上位机工具

第5阶段生产部署
├── 安全性加固
├── 稳定性测试
└── 现场升级测试

学习资源

资源 说明 链接
INTEGRATION.md 详细集成指南 本地文档
PORTING.md 移植到其他MCU 本地文档
协议设计文档 自定义协议详解 本地文档
STM32参考手册 Flash操作说明 ST官网
AES加密教程 加密算法原理 网络资源

模块详解

1. 协议模块 (protocol.c)

自定义二进制协议,高效可靠:

帧结构:
┌──────┬──────┬──────┬────────┬──────┬──────┐
│ HEAD │ CMD  │ LEN  │  DATA  │ CRC16│ TAIL │
│ 0xAA │ 1字节│ 2字节│ N字节  │ 2字节│ 0x55 │
└──────┴──────┴──────┴────────┴──────┴──────┘

支持命令:
- CMD_HANDSHAKE      (0x01): 握手建立连接
- CMD_ERASE_FLASH    (0x02): 擦除Flash扇区
- CMD_WRITE_DATA     (0x03): 写入数据包
- CMD_VERIFY_FIRM    (0x04): 校验固件
- CMD_JUMP_APP       (0x05): 跳转应用
- CMD_GET_VERSION    (0x06): 查询版本
- CMD_SWITCH_BANK    (0x07): 切换Bank

设计亮点:

  • 简洁高效仅7字节开销
  • CRC16校验保证数据完整性
  • 支持应答重传机制
  • 超时自动恢复

2. 加密模块 (aes_crypto.c)

AES-256加密保护固件安全

// 加密流程
固件.bin  AES-256加密  加密固件.bin  传输

// 解密流程Bootloader中
接收数据  AES-256解密  验证  写入Flash

安全特性:

  • 256位密钥长度
  • CBC模式加密
  • 随机IV向量
  • 密钥不存储在代码中

3. 固件管理模块 (firmware_mgr.c)

完整的固件生命周期管理:

┌─────────────────────────────────────────┐
│           固件升级流程                   │
├─────────────────────────────────────────┤
│ 1. 接收加密固件                         │
│    ↓                                    │
│ 2. AES-256解密                          │
│    ↓                                    │
│ 3. CRC32完整性校验                      │
│    ↓                                    │
│ 4. 写入Bank2临时区                      │
│    ↓                                    │
│ 5. 验证写入数据                         │
│    ↓                                    │
│ 6. 复制到Bank1主区                      │
│    ↓                                    │
│ 7. 更新版本信息                         │
│    ↓                                    │
│ 8. 重启并跳转                           │
└─────────────────────────────────────────┘

错误恢复:

  • 写入失败 → 保留原固件
  • 校验失败 → 自动重传
  • 升级中断 → Bank切换恢复

4. 双Bank管理

安全的固件备份机制:

正常升级流程:
Bank1[App v1.0] ──→ 接收新固件 → Bank2[v2.0]
                                         ↓
                              验证通过复制到Bank1
                                         ↓
                       Bank1[v2.0] ← Bank2[备份]

异常恢复流程:
Bank1[App v2.0] ──→ 运行异常 → 从Bank2恢复
                                         ↓
                              Bank1[v1.0] ← Bank2[v1.0]

配置指南

完整配置参数

编辑 bootloader_config.h 文件:

/*============================================================================
 *                          MCU平台配置
 *============================================================================*/
#define MCU_FAMILY_STM32F4XX   1   // STM32F4系列
#define MCU_FAMILY_STM32F1XX   0   // STM32F1系列

/*============================================================================
 *                          Flash布局配置
 *============================================================================*/
// Bootloader占用空间 (KB)
#define BOOTLOADER_SIZE_KB      32

// Flash基地址 (不要修改)
#define FLASH_BASE_ADDR         0x08000000

// 应用程序基地址
#define APP_BASE_ADDR           (FLASH_BASE_ADDR + BOOTLOADER_SIZE_KB * 1024)

// 双Bank配置
#define BANK1_ADDR              0x08008000  // Bank1起始地址
#define BANK2_ADDR              0x08038000  // Bank2起始地址
#define APP_SIZE_MAX            (192 * 1024) // 单个Bank最大192KB

// 版本信息存储区
#define VERSION_INFO_ADDR       0x08007C00  // 最后1KB用于存储版本信息

/*============================================================================
 *                          串口通信配置
 *============================================================================*/
#define BOOT_UART_BAUDRATE      115200      // 串口波特率
#define BOOT_UART_TIMEOUT_MS    3000        // 接收超时 (毫秒)
#define BOOT_UART_BUFFER_SIZE   2048        // 接收缓冲区大小

/*============================================================================
 *                          协议配置
 *============================================================================*/
#define PROTOCOL_MAX_DATA_LEN   1024        // 单包最大数据长度
#define PROTOCOL_RETRY_COUNT    3           // 重试次数
#define PROTOCOL_RETRY_DELAY_MS 100         // 重试间隔 (毫秒)

/*============================================================================
 *                          功能开关
 *============================================================================*/
#define BOOT_ENABLE_AES         1   // 启用AES加密
#define BOOT_ENABLE_CRC         1   // 启用CRC校验
#define BOOT_ENABLE_DUAL_BANK   1   // 启用双Bank备份
#define BOOT_ENABLE_VERSION_MGR 1   // 启用版本管理
#define BOOT_ENABLE_LOG         1   // 启用日志输出

/*============================================================================
 *                          安全配置
 *============================================================================*/
#define BOOT_AES_KEY_SIZE       256         // AES密钥长度 (128/256)
#define BOOT_AES_IV_SIZE        16          // IV向量长度

// AES密钥 (实际应用中应从安全区域读取)
#define BOOT_AES_KEY            {0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, \
                                 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c, \
                                 0x76, 0x2e, 0x71, 0x60, 0xf3, 0x8b, 0x4d, 0xa5, \
                                 0x6a, 0x78, 0x4d, 0x90, 0x45, 0x19, 0x0c, 0xfe}

/*============================================================================
 *                          触发方式配置
 *============================================================================*/
#define BOOT_TRIGGER_TIMEOUT_MS 3000    // 启动时等待命令超时 (毫秒)
// 按键触发 (可选)
// #define BOOT_TRIGGER_PIN        GPIO_PIN_0
// #define BOOT_TRIGGER_PORT       GPIOA
// #define BOOT_TRIGGER_ACTIVE     0       // 0: 低电平触发, 1: 高电平触发

/*============================================================================
 *                          日志配置
 *============================================================================*/
#if BOOT_ENABLE_LOG
#define BOOT_LOG_LEVEL_DEBUG    0
#define BOOT_LOG_LEVEL_INFO     1
#define BOOT_LOG_LEVEL_WARNING  2
#define BOOT_LOG_LEVEL_ERROR    3
#define BOOT_LOG_LEVEL          BOOT_LOG_LEVEL_INFO
#endif

/*============================================================================
 *                          调试配置
 *============================================================================*/
#define BOOT_DEBUG_MODE         0   // 调试模式 (生产环境关闭)

配置示例

示例1: 最小配置 (无加密)

#define BOOT_ENABLE_AES         0   // 关闭加密
#define BOOT_ENABLE_CRC         1   // 仅CRC校验
#define BOOT_ENABLE_DUAL_BANK   0   // 单Bank模式
#define BOOT_ENABLE_VERSION_MGR  0   // 不管理版本

示例2: 生产配置 (安全最高)

#define BOOT_ENABLE_AES         1   // 启用AES-256加密
#define BOOT_ENABLE_CRC         1   // 启用CRC校验
#define BOOT_ENABLE_DUAL_BANK   1   // 双Bank备份
#define BOOT_ENABLE_VERSION_MGR  1   // 版本管理
#define BOOT_ENABLE_LOG         0   // 关闭日志

移植指南

详细移植步骤请参考 PORTING.md

快速移植到新MCU

  1. 复制移植模板

    cp -r port/port_template port/your_mcu
    
  2. 实现Flash操作接口

    // flash_port.c
    int flash_port_init(void) { /* ... */ }
    int flash_port_erase(uint32_t addr, uint32_t size) { /* ... */ }
    int flash_port_write(uint32_t addr, const uint8_t *data, uint32_t len) { /* ... */ }
    int flash_port_read(uint32_t addr, uint8_t *data, uint32_t len) { /* ... */ }
    
  3. 实现UART操作接口

    // uart_port.c
    int uart_port_init(uint32_t baudrate) { /* ... */ }
    int uart_port_send(const uint8_t *data, uint32_t len) { /* ... */ }
    int uart_port_recv(uint8_t *data, uint32_t len, uint32_t timeout) { /* ... */ }
    
  4. 修改CMakeLists.txt

    set(MCU_FAMILY "your_mcu" CACHE STRING "MCU family")
    

上位机工具

命令行工具

# 查看帮助
./flash_tool --help

# 连接设备
./flash_tool --port COM3 --baud 115200

# 烧录固件
./flash_tool --port COM3 --write firmware.bin

# 查看版本
./flash_tool --port COM3 --version

# 擦除Flash
./flash_tool --port COM3 --erase

# 切换Bank
./flash_tool --port COM3 --switch-bank

# 加密固件
./flash_tool --encrypt firmware.bin firmware_enc.bin

Python脚本 (简易版)

import serial
import struct

def send_firmware(port, baudrate, firmware_path):
    ser = serial.Serial(port, baudrate, timeout=3)
    
    # 发送握手
    handshake = bytes([0xAA, 0x01, 0x00, 0x00, 0x55])
    ser.write(handshake)
    
    # 读取固件
    with open(firmware_path, 'rb') as f:
        firmware = f.read()
    
    # 发送数据包...
    # (详细实现见 tools/flash_tool)
    
    ser.close()

if __name__ == '__main__':
    send_firmware('COM3', 115200, 'firmware.bin')

常见问题

Q1: Bootloader启动后无法跳转到应用?

A: 检查以下几点:

  1. 应用程序的链接脚本起始地址是否正确设置为 APP_BASE_ADDR
  2. 应用程序的中断向量表是否偏移 SCB->VTOR = APP_BASE_ADDR
  3. 应用程序是否正确编译烧录

Q2: Flash写入失败?

A: 常见原因:

  1. Flash未解锁
  2. 写入地址未擦除
  3. 写入地址未对齐
  4. Flash页大小配置错误

Q3: 串口通信不稳定?

A: 建议:

  1. 降低波特率到 9600 或 57600
  2. 增加超时时间 BOOT_UART_TIMEOUT_MS
  3. 添加硬件流控
  4. 检查串口线缆质量

Q4: 如何调试Bootloader?

A: 方法:

  1. 启用日志输出 BOOT_ENABLE_LOG = 1
  2. 设置日志级别 BOOT_LOG_LEVEL = BOOT_LOG_LEVEL_DEBUG
  3. 使用串口打印调试信息
  4. 使用调试器单步调试

Q5: 如何确保固件安全性?

A: 建议:

  1. 启用AES-256加密 BOOT_ENABLE_AES = 1
  2. 密钥不要硬编码,从安全区域读取
  3. 使用固件签名验证
  4. 启用读保护 (RDP)

性能指标

指标 数值
Bootloader大小 ~16KB (启用所有功能)
最小程序大小 ~4KB (仅基础功能)
RAM占用 ~2KB
192KB固件升级时间 ~15秒 @115200
支持最大固件大小 192KB (单Bank)
可靠性 CRC校验 + 重传机制

版本历史

版本 日期 说明
v1.0.0 2026-01 初始版本,基础功能
v1.1.0 TBD 添加AES加密支持
v1.2.0 TBD 添加双Bank支持
v2.0.0 TBD 重构架构支持多MCU

许可证

本项目采用 MIT 许可证,详见 LICENSE 文件。


贡献指南

欢迎贡献代码、报告问题或提出建议!

  1. Fork 本仓库
  2. 创建特性分支 (git checkout -b feature/AmazingFeature)
  3. 提交更改 (git commit -m 'Add some AmazingFeature')
  4. 推送到分支 (git push origin feature/AmazingFeature)
  5. 提交 Pull Request

联系方式


致谢

感谢以下开源项目的启发:

  • STM32 HAL库
  • TinyAES库
  • STM32CubeProgrammer

Happy Coding!

如果您觉得这个项目有帮助,请给一个 Star 支持一下!

Description
No description provided
Readme 103 KiB
Languages
C 78.3%
CMake 21.7%