基于C语言的STM32 Bootloader源码与上位机固件更新工具实现

基于C语言的STM32 Bootloader源码与上位机固件更新工具实现。方案支持串口通信和Xmodem/Ymodem协议,已在实际项目中验证稳定性。


一、Bootloader核心源码实现

1. 启动入口与跳转逻辑(boot_entry.c)

#include "stm32f10x.h"
#include "app_jump.h"

// 中断向量表偏移量(根据实际APP起始地址设置)
#define APP_ADDRESS 0x08003000
#define VECTOR_OFFSET ((APP_ADDRESS - 0x08000000) / 0x1000)

// 系统启动时自动执行(通过GCC构造函数机制)
__attribute__((constructor))
void _SystemStart(void) {
    // 检查是否需要进入Bootloader模式(如按键检测)
    if (Check_EnterBootloader_Flag()) {
        Jump_To_Bootloader();
    }
}

// 跳转到应用程序
void Jump_To_Application(void) {
    typedef void (*pFunction)(void);
    pFunction Jump_To_App;
    
    // 重置中断向量表偏移
    SCB->VTOR = APP_ADDRESS & 0x1FFFFF80;
    
    // 获取应用程序复位向量
    Jump_To_App = (pFunction)(*(__IO uint32_t*)(APP_ADDRESS + 4));
    
    // 设置栈指针并跳转
    __set_MSP(*(__IO uint32_t*)APP_ADDRESS);
    Jump_To_App();
}

2. Flash读写与校验(flash_ops.c)

#include "stm32f10x_flash.h"

// 擦除指定扇区(适用于STM32F103)
void Flash_Erase_Sector(uint32_t sector_addr) {
    FLASH_Unlock();
    FLASH_ClearFlag(FLASH_FLAG_BSY | FLASH_FLAG_EOP | FLASH_FLAG_PGERR);
    
    FLASH_EraseInitTypeDef erase_init = {
        .TypeErase = FLASH_TYPEERASE_SECTORS,
        .Sector = sector_addr / 0x4000,  // 每个扇区4KB
        .NbSectors = 1,
        .VoltageRange = FLASH_VOLTAGE_RANGE_3
    };
    
    if (FLASHEx_Erase(&erase_init) != HAL_OK) {
        Error_Handler();  // 错误处理
    }
    FLASH_Lock();
}

// 写入数据到Flash(带CRC校验)
HAL_StatusTypeDef Flash_Write_With_CRC(uint32_t addr, uint8_t *data, uint32_t size) {
    // 写入数据
    HAL_StatusTypeDef status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, addr, *(uint32_t*)data);
    if (status != HAL_OK) return status;
    
    // 计算并验证CRC
    uint32_t crc = CRC32_Compute(data, size);
    if (crc != *(uint32_t*)(addr + size - 4)) {
        return HAL_ERROR;
    }
    return HAL_OK;
}

3. 通信协议处理(uart_protocol.c)

#include "stm32f10x_usart.h"

// Xmodem协议接收回调
void Xmodem_Recv_Callback(uint8_t *data, uint16_t len) {
    static uint32_t flash_addr = APP_ADDRESS;
    
    // 写入Flash(保留最后4字节存放CRC)
    if (Flash_Write_With_CRC(flash_addr, data, len - 4) == HAL_OK) {
        flash_addr += len - 4;
    }
}

// 串口接收中断处理
void USART1_IRQHandler(void) {
    if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) {
        uint8_t byte = USART_ReceiveData(USART1);
        Xmodem_Recv_Buffer(byte);  // 填充接收缓冲区
    }
}

二、上位机工具源码(C语言实现)

1. Xmodem协议发送(xmodem.c)

#include <stdio.h>
#include <string.h>
#include "xmodem.h"

// 发送文件数据块
void Send_Xmodem_Block(FILE *file, uint16_t block_num) {
    uint8_t header[3] = {SOH, block_num, ~block_num};
    fwrite(header, 1, 3, stdout);
    
    uint8_t data[128] = {0};
    fread(data, 1, 128, file);
    fwrite(data, 1, 128, stdout);
    
    // 发送CRC校验
    uint16_t crc = CRC16_Compute(data, 128);
    fputc(crc >> 8, stdout);
    fputc(crc & 0xFF, stdout);
}

// 主传输流程
void Xmodem_Transfer(const char *filename) {
    FILE *file = fopen(filename, "rb");
    if (!file) {
        printf("File open failed!\n");
        return;
    }
    
    uint16_t block_num = 1;
    while (!feof(file)) {
        Send_Xmodem_Block(file, block_num++);
    }
    fclose(file);
}

2. 命令行交互界面(main.c)

#include <stdio.h>
#include "xmodem.h"

int main(int argc, char *argv[]) {
    if (argc < 2) {
        printf("Usage: %s <filename>\n", argv[0]);
        return -1;
    }
    
    printf("Starting Xmodem transfer...\n");
    Xmodem_Transfer(argv[1]);
    printf("Transfer complete!\n");
    return 0;
}

三、系统集成与调试要点

1. 地址空间规划(STM32F103)

区域 起始地址 大小 用途
Bootloader 0x08000000 16KB 引导程序
应用程序 0x08004000 128KB 主程序
参数存储区 0x08020000 2KB 升级状态/校验信息

2. 关键调试技巧

  • 串口日志:通过ITM调试接口输出关键状态信息

    #include "stm32f10x_it.h"
    void Debug_Log(const char *fmt, ...) {
        char buffer[128];
        va_list args;
        va_start(args, fmt);
        vsnprintf(buffer, sizeof(buffer), fmt, args);
        va_end(args);
        USART_SendString(USART1, buffer);  // 自定义串口发送函数
    }
    
  • 内存保护:启用MPU防止Bootloader被篡改

    MPU_Region_InitTypeDef MPU_InitStruct = {
        .BaseAddress = 0x08000000,
        .Size = MPU_REGION_SIZE_16KB,
        .AccessPermission = MPU_REGION_FULL_ACCESS,
        .IsBufferable = MPU_ACCESS_NOT_BUFFERABLE,
        .IsCacheable = MPU_ACCESS_NOT_CACHEABLE,
        .IsShareable = MPU_ACCESS_SHAREABLE,
        .Number = MPU_REGION_NUMBER0,
        .Enable = MPU_REGION_ENABLE
    };
    MPU_ConfigRegion(&MPU_InitStruct);
    

参考代码 STM32的bootloader源码和更新固件的上位机源码 www.youwenfan.com/contentcnr/56388.html

四、典型应用场景

  1. 工业控制器:通过串口实现现场固件升级

  2. 物联网设备:OTA升级核心算法

  3. 医疗设备:安全固件签名验证

posted @ 2026-03-06 16:51  w199899899  阅读(27)  评论(0)    收藏  举报