Files
bootloader/docs/INTEGRATION.md
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

643 lines
12 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Bootloader集成指南
本文档详细介绍如何将Bootloader扩展模块集成到您的STM32项目中。
---
## 目录
- [前置要求](#前置要求)
- [集成方式](#集成方式)
- [详细步骤](#详细步骤)
- [配置参数](#配置参数)
- [链接脚本修改](#链接脚本修改)
- [中断向量表](#中断向量表)
- [编译与烧录](#编译与烧录)
- [测试验证](#测试验证)
- [故障排查](#故障排查)
---
## 前置要求
### 硬件要求
- STM32系列MCU (本模块主要针对STM32F4系列)
- 至少一个UART接口
- 足够的Flash空间:
- Bootloader: 16KB ~ 32KB
- 应用程序: 取决于您的需求
### 软件要求
- ARM GCC工具链
- CMake 3.10+ (可选)
- STM32CubeMX (用于生成初始化代码)
- 串口调试工具
### 开发环境
- Windows: STM32CubeIDE / Keil MDK / IAR
- Linux: VSCode + CMake + ARM GCC
- macOS: VSCode + CMake + ARM GCC
---
## 集成方式
### 方式一:嵌入式集成(推荐新手)
Bootloader与应用程序共用一个工程通过条件编译切换。
**优点:**
- 配置简单
- 易于调试
- 适合学习
**缺点:**
- 需要重新编译整个工程
- 不够灵活
### 方式二:独立工程集成(推荐生产)
Bootloader和应用程序分别作为独立工程。
**优点:**
- 独立开发
- 灵活部署
- 适合生产
**缺点:**
- 需要管理两个工程
- 配置相对复杂
---
## 详细步骤
### 方式一:嵌入式集成
#### 步骤1: 复制文件
```bash
# 复制整个extensions目录到您的项目根目录
cp -r extensions/ /path/to/your/project/
```
#### 步骤2: 修改CMakeLists.txt
在您的项目CMakeLists.txt中添加
```cmake
# 添加Bootloader模块
add_subdirectory(extensions/bootloader)
# 链接Bootloader库
target_link_libraries(${PROJECT_NAME}.elf bootloader)
# 包含头文件
target_include_directories(${PROJECT_NAME}.elf PRIVATE
extensions/bootloader/include
)
```
#### 步骤3: 配置bootloader_config.h
编辑 `extensions/bootloader/include/bootloader_config.h`:
```c
// MCU配置
#define MCU_FAMILY_STM32F4XX 1
// Flash布局
#define BOOTLOADER_SIZE_KB 32
#define APP_BASE_ADDR 0x08008000
// 功能开关
#define BOOT_ENABLE_AES 1
#define BOOT_ENABLE_CRC 1
#define BOOT_ENABLE_DUAL_BANK 1
```
#### 步骤4: 修改main.c
```c
#include "main.h"
#include "bootloader.h"
int main(void) {
// HAL初始化
HAL_Init();
SystemClock_Config();
// === Bootloader入口 ===
bootloader_init();
// 检查是否进入Bootloader模式
if (bootloader_check_enter()) {
// Bootloader主循环
while (1) {
bootloader_process();
// 检查是否需要跳转
if (bootloader_get_state() == BOOT_STATE_JUMP_APP) {
bootloader_jump_to_app(APP_BASE_ADDR);
}
}
}
// =====================
// 应用程序初始化
MX_GPIO_Init();
MX_USART1_UART_Init();
// ... 其他初始化
// 应用程序主循环
while (1) {
// 您的应用代码
}
}
```
#### 步骤5: 修改链接脚本
找到您的链接脚本 (例如 `STM32F407XX_FLASH.ld`)修改Flash起始地址
```ld
/* 原始配置 */
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K
}
/* 修改为 (为Bootloader预留32KB) */
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
FLASH (rx) : ORIGIN = 0x08008000, LENGTH = 992K
}
```
#### 步骤6: 修改中断向量表
在应用程序的 `system_stm32f4xx.c` 中,添加中断向量表偏移:
```c
void SystemInit(void) {
// ... 原有代码
// 设置中断向量表偏移
#ifdef VECT_TAB_SRAM
SCB->VTOR = RAMDTCM_BASE | VECT_TAB_OFFSET;
#else
SCB->VTOR = FLASH_BASE | 0x8000; // 0x8000 = 32KB偏移
#endif
}
```
或者在 `main.c` 的开头添加:
```c
#define VECT_TAB_OFFSET 0x8000 // 32KB偏移
int main(void) {
// 设置中断向量表
SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET;
HAL_Init();
// ...
}
```
---
### 方式二:独立工程集成
#### 步骤1: 创建Bootloader工程
```bash
mkdir bootloader_project
cd bootloader_project
# 复制Bootloader模块
cp -r /path/to/bootloader/extensions/bootloader ./
```
#### 步骤2: 创建Bootloader的main.c
```c
#include "bootloader.h"
int main(void) {
HAL_Init();
SystemClock_Config();
// 初始化Bootloader
bootloader_init();
// Bootloader主循环
while (1) {
bootloader_process();
if (bootloader_get_state() == BOOT_STATE_JUMP_APP) {
// 检查应用程序是否存在
if (bootloader_check_app_valid(APP_BASE_ADDR)) {
bootloader_jump_to_app(APP_BASE_ADDR);
}
}
}
}
```
#### 步骤3: 配置Bootloader链接脚本
Bootloader从 0x08000000 开始:
```ld
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 32K
}
```
#### 步骤4: 创建应用程序工程
应用程序从 0x08008000 开始:
```ld
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
FLASH (rx) : ORIGIN = 0x08008000, LENGTH = 992K
}
```
#### 步骤5: 编译烧录顺序
```bash
# 1. 编译Bootloader
cd bootloader_project
make
# 烧录到 0x08000000
st-flash write bootloader.bin 0x08000000
# 2. 编译应用程序
cd application_project
make
# 通过Bootloader升级或直接烧录到 0x08008000
```
---
## 配置参数
### 必须配置的参数
| 参数 | 说明 | 示例值 |
|------|------|--------|
| MCU_FAMILY_* | MCU系列 | STM32F4XX |
| BOOTLOADER_SIZE_KB | Bootloader大小 | 32 |
| APP_BASE_ADDR | 应用起始地址 | 0x08008000 |
| BOOT_UART_BAUDRATE | 串口波特率 | 115200 |
### 可选配置的参数
| 参数 | 说明 | 默认值 |
|------|------|--------|
| BOOT_ENABLE_AES | 启用AES加密 | 1 |
| BOOT_ENABLE_CRC | 启用CRC校验 | 1 |
| BOOT_ENABLE_DUAL_BANK | 启用双Bank | 1 |
| BOOT_ENABLE_VERSION_MGR | 启用版本管理 | 1 |
| BOOT_TRIGGER_TIMEOUT_MS | 启动等待超时 | 3000 |
---
## 链接脚本修改
### 完整示例 (STM32F407ZGTx)
```ld
/* Entry Point */
ENTRY(Reset_Handler)
/* Highest address of the user mode stack */
_estack = ORIGIN(RAM) + LENGTH(RAM);
/* Specify the memory areas */
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
CCMRAM (xrw) : ORIGIN = 0x10000000, LENGTH = 64K
/* 根据您的需求选择其一 */
/* 方式1: 应用程序链接脚本 (从32KB开始) */
FLASH (rx) : ORIGIN = 0x08008000, LENGTH = 992K
/* 方式2: Bootloader链接脚本 (从0开始) */
/* FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 32K */
}
/* 中断向量表偏移 (仅应用程序需要) */
_isr_vector = ORIGIN(FLASH);
```
### 注意事项
1. **Bootloader工程**: Flash起始地址 = 0x08000000
2. **应用程序工程**: Flash起始地址 = 0x08000000 + Bootloader大小
3. **不要重叠**: 确保Bootloader和应用程序的Flash区域不重叠
---
## 中断向量表
### 为什么需要修改?
STM32上电后从 0x08000000 读取中断向量表。如果应用程序不在 0x08000000必须重定向中断向量表。
### 修改方法
#### 方法1: 修改system_stm32f4xx.c
```c
void SystemInit(void) {
// ... 原有代码
/* Configure the Vector Table location -------------------------------------*/
#define VECT_TAB_OFFSET 0x8000 /* 32KB offset for bootloader */
#ifdef VECT_TAB_SRAM
SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET;
#else
SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET;
#endif
}
```
#### 方法2: 在main.c中设置
```c
int main(void) {
// 第一件事:设置中断向量表
SCB->VTOR = 0x08008000; // 应用程序起始地址
// 然后初始化HAL
HAL_Init();
// ...
}
```
#### 方法3: 使用宏定义
`main.h` 中定义:
```c
#define APPLICATION_ADDRESS 0x08008000
// 在main函数开头
SCB->VTOR = APPLICATION_ADDRESS;
```
---
## 编译与烧录
### 编译Bootloader
```bash
cd bootloader_project
mkdir build && cd build
cmake .. -DMCU_FAMILY=stm32f4xx
make -j4
```
### 编译应用程序
```bash
cd application_project
mkdir build && cd build
cmake ..
make -j4
```
### 烧录顺序
#### 方法1: 使用ST-Link
```bash
# 烧录Bootloader
st-flash write bootloader.bin 0x08000000
# 烧录应用程序 (首次烧录)
st-flash write application.bin 0x08008000
```
#### 方法2: 使用STM32CubeProgrammer
```bash
# 烧录Bootloader
STM32_Programmer_CLI -c port=SWD -w bootloader.bin 0x08000000 -v
# 烧录应用程序
STM32_Programmer_CLI -c port=SWD -w application.bin 0x08008000 -v
```
#### 方法3: 通过Bootloader升级
```bash
# 使用上位机工具升级
./flash_tool --port COM3 --write application.bin
```
---
## 测试验证
### 基础功能测试
#### 测试1: Bootloader启动测试
```c
// 在bootloader.c中添加调试输出
void bootloader_init(void) {
// 初始化串口
bsp_uart_init(BOOT_UART_BAUDRATE);
printf("Bootloader v1.0.0\r\n");
printf("Waiting for command...\r\n");
// ...
}
```
**预期结果:** 串口输出Bootloader版本信息
#### 测试2: 跳转测试
```c
// 在main.c中添加
bootloader_jump_to_app(APP_BASE_ADDR);
// 在应用程序main.c开头添加
printf("Application started!\r\n");
```
**预期结果:** 成功跳转到应用程序并输出信息
#### 测试3: 通信测试
使用串口调试工具发送握手命令:
```
发送: AA 01 00 00 55 (握手命令)
预期: 接收到应答
```
### 完整功能测试
#### 测试清单
- [ ] Bootloader正常启动
- [ ] 串口通信正常
- [ ] 握手命令成功
- [ ] Flash擦除成功
- [ ] 固件写入成功
- [ ] CRC校验通过
- [ ] AES解密正确
- [ ] 跳转应用程序成功
- [ ] 应用程序正常运行
- [ ] 双Bank切换成功
- [ ] 版本管理正常
---
## 故障排查
### 问题1: 编译错误 - 找不到头文件
**症状:**
```
fatal error: bootloader.h: No such file or directory
```
**解决:**
```cmake
# 在CMakeLists.txt中添加包含路径
target_include_directories(${PROJECT_NAME} PRIVATE
extensions/bootloader/include
)
```
### 问题2: 链接错误 - 重复定义
**症状:**
```
multiple definition of `main'
```
**解决:**
检查是否有多个main函数确保只有一个main入口。
### 问题3: 运行时错误 - 无法启动
**症状:**
程序不运行或立即崩溃
**排查步骤:**
1. 检查Flash布局是否正确
2. 检查中断向量表是否正确设置
3. 使用调试器检查PC指针位置
4. 检查堆栈大小是否足够
### 问题4: 跳转失败
**症状:**
跳转到应用程序后无响应
**排查步骤:**
1. 确认应用程序起始地址正确
2. 检查中断向量表是否偏移
3. 检查应用程序是否正确烧录
4. 使用调试器查看应用程序是否正常运行
**调试代码:**
```c
void bootloader_jump_to_app(uint32_t app_addr) {
// 检查应用程序是否存在
uint32_t app_stack = *((uint32_t*)app_addr);
uint32_t app_entry = *((uint32_t*)(app_addr + 4));
printf("App stack: 0x%08X\r\n", app_stack);
printf("App entry: 0x%08X\r\n", app_entry);
// 检查栈指针是否在RAM范围内
if (app_stack < 0x20000000 || app_stack > 0x20000000 + 128*1024) {
printf("Invalid stack pointer!\r\n");
return;
}
// 禁用所有中断
__disable_irq();
// 跳转
typedef void (*app_entry_t)(void);
app_entry_t entry = (app_entry_t)app_entry;
entry();
}
```
### 问题5: Flash写入失败
**症状:**
Flash写入返回错误
**排查步骤:**
1. 确认Flash已解锁
2. 确认写入地址已擦除
3. 确认地址对齐
4. 检查Flash页大小配置
**调试代码:**
```c
int flash_port_write(uint32_t addr, const uint8_t *data, uint32_t len) {
printf("Writing to 0x%08X, len=%d\r\n", addr, len);
// 检查Flash状态
FLASH_TypeDef *flash = FLASH;
printf("Flash SR: 0x%08X\r\n", flash->SR);
// 写入操作...
}
```
---
## 下一步
完成集成后,请阅读:
- [协议文档](PROTOCOL.md) - 了解通信协议细节
- [移植指南](PORTING.md) - 移植到其他MCU平台
- [上位机工具](../tools/flash_tool/README.md) - 使用烧写工具
---
## 技术支持
如遇到问题,请:
1. 查阅本文档的故障排查章节
2. 查看 [GitHub Issues](https://github.com/your-repo/issues)
3. 提交新的Issue附带
- MCU型号
- 完整的错误信息
- 相关配置文件
- 调试日志
---
**祝您集成顺利!**