基于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
四、典型应用场景
-
工业控制器:通过串口实现现场固件升级
-
物联网设备:OTA升级核心算法
-
医疗设备:安全固件签名验证
浙公网安备 33010602011771号