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

12 KiB
Raw Permalink Blame History

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: 复制文件

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

步骤2: 修改CMakeLists.txt

在您的项目CMakeLists.txt中添加

# 添加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:

// 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

#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起始地址

/* 原始配置 */
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 中,添加中断向量表偏移:

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 的开头添加:

#define VECT_TAB_OFFSET  0x8000  // 32KB偏移

int main(void) {
    // 设置中断向量表
    SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET;
    
    HAL_Init();
    // ...
}

方式二:独立工程集成

步骤1: 创建Bootloader工程

mkdir bootloader_project
cd bootloader_project

# 复制Bootloader模块
cp -r /path/to/bootloader/extensions/bootloader ./

步骤2: 创建Bootloader的main.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 开始:

MEMORY
{
RAM (xrw)      : ORIGIN = 0x20000000, LENGTH = 128K
FLASH (rx)      : ORIGIN = 0x08000000, LENGTH = 32K
}

步骤4: 创建应用程序工程

应用程序从 0x08008000 开始:

MEMORY
{
RAM (xrw)      : ORIGIN = 0x20000000, LENGTH = 128K
FLASH (rx)      : ORIGIN = 0x08008000, LENGTH = 992K
}

步骤5: 编译烧录顺序

# 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)

/* 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

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中设置

int main(void) {
    // 第一件事:设置中断向量表
    SCB->VTOR = 0x08008000;  // 应用程序起始地址
    
    // 然后初始化HAL
    HAL_Init();
    
    // ...
}

方法3: 使用宏定义

main.h 中定义:

#define APPLICATION_ADDRESS    0x08008000

// 在main函数开头
SCB->VTOR = APPLICATION_ADDRESS;

编译与烧录

编译Bootloader

cd bootloader_project
mkdir build && cd build
cmake .. -DMCU_FAMILY=stm32f4xx
make -j4

编译应用程序

cd application_project
mkdir build && cd build
cmake ..
make -j4

烧录顺序

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

# 烧录应用程序 (首次烧录)
st-flash write application.bin 0x08008000

方法2: 使用STM32CubeProgrammer

# 烧录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升级

# 使用上位机工具升级
./flash_tool --port COM3 --write application.bin

测试验证

基础功能测试

测试1: Bootloader启动测试

// 在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: 跳转测试

// 在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

解决:

# 在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. 使用调试器查看应用程序是否正常运行

调试代码:

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页大小配置

调试代码:

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);
    
    // 写入操作...
}

下一步

完成集成后,请阅读:


技术支持

如遇到问题,请:

  1. 查阅本文档的故障排查章节
  2. 查看 GitHub Issues
  3. 提交新的Issue附带
    • MCU型号
    • 完整的错误信息
    • 相关配置文件
    • 调试日志

祝您集成顺利!