# STM32 Bootloader Extension > 一个教学导向的、可移植的、生产就绪的Bootloader扩展模块 ![License](https://img.shields.io/badge/license-MIT-blue.svg) ![Platform](https://img.shields.io/badge/platform-STM32-orange.svg) ![Language](https://img.shields.io/badge/language-C-green.svg) --- ## 目录 - [项目简介](#项目简介) - [核心特性](#核心特性) - [快速开始](#快速开始) - [架构设计](#架构设计) - [学习路径](#学习路径) - [模块详解](#模块详解) - [配置指南](#配置指南) - [移植指南](#移植指南) - [上位机工具](#上位机工具) - [常见问题](#常见问题) - [贡献指南](#贡献指南) --- ## 项目简介 这是一个专为**教学目的**设计的STM32 Bootloader扩展模块,采用**分层架构**和**模块化设计**,让您: - 理解Bootloader的核心原理 - 掌握固件升级的完整流程 - 学习安全启动的设计思想 - 获得可直接用于生产环境的代码 ### 为什么需要Bootloader? ``` ┌─────────────────────────────────────────────────┐ │ 传统固件升级:需要拆卸设备、连接调试器 │ │ → 成本高、效率低、用户体验差 │ ├─────────────────────────────────────────────────┤ │ Bootloader升级:串口/USB直接更新固件 │ │ → 无需拆卸、远程升级、用户友好 │ └─────────────────────────────────────────────────┘ ``` ### 适用场景 - IoT设备远程固件更新 - 嵌入式产品现场升级 - 需要安全启动的设备 - 学习嵌入式Bootloader开发 --- ## 核心特性 | 特性 | 描述 | 状态 | |------|------|:----:| | 自定义协议 | 高效可靠的数据传输协议 | ✅ | | AES-256加密 | 固件传输全程加密保护 | ✅ | | CRC32校验 | 数据完整性验证 | ✅ | | 双Bank备份 | 安全升级,失败可回滚 | ✅ | | 版本管理 | 固件版本控制 | ✅ | | 模块化设计 | 易于理解和移植 | ✅ | | 跨MCU支持 | 通过BSP抽象层适配 | ✅ | --- ## 快速开始 ### 5分钟集成到您的项目 #### 步骤1: 复制扩展模块 ```bash # 将extensions目录复制到您的STM32项目根目录 cp -r extensions/ /path/to/your/project/ ``` #### 步骤2: 配置参数 编辑 `extensions/bootloader/include/bootloader_config.h`: ```c // 选择您的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 ```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`: ```ld /* 原始 */ FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K /* 修改为 */ FLASH (rx) : ORIGIN = 0x08008000, LENGTH = 992K ``` #### 步骤5: 编译并烧录 ```bash # 编译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](docs/INTEGRATION.md) | 详细集成指南 | 本地文档 | | [PORTING.md](docs/PORTING.md) | 移植到其他MCU | 本地文档 | | [协议设计文档](docs/PROTOCOL.md) | 自定义协议详解 | 本地文档 | | 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加密保护固件安全: ```c // 加密流程 固件.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` 文件: ```c /*============================================================================ * 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: 最小配置 (无加密) ```c #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: 生产配置 (安全最高) ```c #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](docs/PORTING.md) ### 快速移植到新MCU 1. **复制移植模板** ```bash cp -r port/port_template port/your_mcu ``` 2. **实现Flash操作接口** ```c // 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操作接口** ```c // 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** ```cmake set(MCU_FAMILY "your_mcu" CACHE STRING "MCU family") ``` --- ## 上位机工具 ### 命令行工具 ```bash # 查看帮助 ./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脚本 (简易版) ```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](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 --- ## 联系方式 - 问题反馈: [GitHub Issues](https://github.com/your-repo/issues) - 技术讨论: [GitHub Discussions](https://github.com/your-repo/discussions) --- ## 致谢 感谢以下开源项目的启发: - STM32 HAL库 - TinyAES库 - STM32CubeProgrammer --- **Happy Coding!** 如果您觉得这个项目有帮助,请给一个 ⭐ Star 支持一下!