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>
STM32 Bootloader Extension
一个教学导向的、可移植的、生产就绪的Bootloader扩展模块
目录
项目简介
这是一个专为教学目的设计的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
-
复制移植模板
cp -r port/port_template port/your_mcu -
实现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) { /* ... */ } -
实现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) { /* ... */ } -
修改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: 检查以下几点:
- 应用程序的链接脚本起始地址是否正确设置为
APP_BASE_ADDR - 应用程序的中断向量表是否偏移
SCB->VTOR = APP_BASE_ADDR - 应用程序是否正确编译烧录
Q2: Flash写入失败?
A: 常见原因:
- Flash未解锁
- 写入地址未擦除
- 写入地址未对齐
- Flash页大小配置错误
Q3: 串口通信不稳定?
A: 建议:
- 降低波特率到 9600 或 57600
- 增加超时时间
BOOT_UART_TIMEOUT_MS - 添加硬件流控
- 检查串口线缆质量
Q4: 如何调试Bootloader?
A: 方法:
- 启用日志输出
BOOT_ENABLE_LOG = 1 - 设置日志级别
BOOT_LOG_LEVEL = BOOT_LOG_LEVEL_DEBUG - 使用串口打印调试信息
- 使用调试器单步调试
Q5: 如何确保固件安全性?
A: 建议:
- 启用AES-256加密
BOOT_ENABLE_AES = 1 - 密钥不要硬编码,从安全区域读取
- 使用固件签名验证
- 启用读保护 (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 文件。
贡献指南
欢迎贡献代码、报告问题或提出建议!
- Fork 本仓库
- 创建特性分支 (
git checkout -b feature/AmazingFeature) - 提交更改 (
git commit -m 'Add some AmazingFeature') - 推送到分支 (
git push origin feature/AmazingFeature) - 提交 Pull Request
联系方式
- 问题反馈: GitHub Issues
- 技术讨论: GitHub Discussions
致谢
感谢以下开源项目的启发:
- STM32 HAL库
- TinyAES库
- STM32CubeProgrammer
Happy Coding!
如果您觉得这个项目有帮助,请给一个 ⭐ Star 支持一下!
Description
Languages
C
78.3%
CMake
21.7%