STM32L051 的 串口升级(UART Bootloader / IAP)
一、STM32L051 串口升级总体方案
1、系统架构
Flash 布局(64 KB)
┌─────────────────────┐ 0x08000000
│ Bootloader (8 KB) │ ← 上电首先运行
├─────────────────────┤ 0x08002000
│ Application A │ ← 正常运行区
├─────────────────────┤ 0x0800C000
│ Application B │ ← 备用/升级区(可选)
└─────────────────────┘ 0x08010000
推荐方案:
- Bootloader + 单 App(覆盖升级)
- 双分区(A/B)
二、启动流程(Bootloader 逻辑)
text
上电复位
↓
Bootloader 启动
↓
检查升级标志(Flash / GPIO / 命令)
↓
是否需要升级?
├─ 是 → 接收串口固件 → 擦写 Flash → 跳转
└─ 否 → 直接跳转到 App
三、Flash 分区与关键地址
| 区域 | 起始地址 | 大小 |
|---|---|---|
| Bootloader | 0x08000000 | 8 KB |
| Application | 0x08002000 | 56 KB |
升级标志位(放在 Flash 末尾)
c
#define UPDATE_FLAG_ADDR 0x0800FF00
#define UPDATE_MAGIC_NUM 0x12345678
四、Bootloader 核心代码(HAL 库)
1、串口初始化(UART1)
c
void UART_Init(void)
{
huart1.Instance = USART1;
huart1.Init.BaudRate = 115200;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
HAL_UART_Init(&huart1);
}
2、跳转到 APP
c
typedef void (*pFunction)(void);
pFunction JumpToApplication;
uint32_t JumpAddress;
void Jump_To_App(uint32_t app_addr)
{
__disable_irq();
JumpAddress = *(__IO uint32_t*)(app_addr + 4);
JumpToApplication = (pFunction)JumpAddress;
__set_MSP(*(__IO uint32_t*)app_addr);
JumpToApplication();
}
3、 Flash 擦除 & 写入
c
void Flash_Write(uint32_t addr, uint8_t *data, uint32_t len)
{
HAL_FLASH_Unlock();
for (uint32_t i = 0; i < len; i += 4)
{
uint32_t word = data[i] |
(data[i+1] << 8) |
(data[i+2] << 16) |
(data[i+3] << 24);
HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, addr + i, word);
}
HAL_FLASH_Lock();
}
五、串口升级协议(简单可靠)
帧格式(推荐)
| HEAD | CMD | LEN | DATA | CRC |
| 0xAA | 0x01| N | ... | CRC |
| CMD | 功能 |
|---|---|
| 0x01 | 开始升级 |
| 0x02 | 发送数据 |
| 0x03 | 结束升级 |
| 0x04 | 校验成功 |
接收数据示例
c
void Receive_Firmware(void)
{
uint8_t buf[256];
uint32_t writeAddr = APP_START_ADDR;
while (1)
{
HAL_UART_Receive(&huart1, buf, 132, HAL_MAX_DELAY);
if (buf[0] == 0xAA && buf[1] == 0x02)
{
Flash_Write(writeAddr, &buf[4], 128);
writeAddr += 128;
}
else if (buf[1] == 0x03)
{
break;
}
}
}
参考代码 stm32l051的串口升级程序 www.youwenfan.com/contentcsv/72126.html
六、APP 程序注意事项
1、中断向量偏移
c
SCB->VTOR = FLASH_BASE | 0x2000;
2、Linker 修改(Keil)
ROM: 0x08002000
Size: 0xE000
七、升级触发方式
| 方式 | 说明 |
|---|---|
| 串口命令 | PC 下发升级指令 |
| GPIO 按键 | BOOT 引脚拉高 |
| 软件标志 | 写入 Flash 标志 |
| 看门狗超时 | 异常重启升级 |
八、防变砖设计
CRC 校验
升级失败自动回滚
Bootloader 不升级
写保护 Option Bytes
掉电保护(页写完成才更新标志)
九、PC 端升级工具
python
import serial
ser = serial.Serial('COM3', 115200)
def send_bin(file):
with open(file, 'rb') as f:
while True:
data = f.read(128)
if not data:
break
ser.write(b'\xAA\x02\x80' + data)
ser.write(b'\xAA\x03\x00')