1. 项目概述:三款MCU的串口IAP Bootloader实现
在嵌入式设备远程维护场景中,IAP(In-Application Programming)技术是解决固件升级痛点的关键方案。这个项目针对STM32、AT32、GD32三款主流ARM Cortex-M内核MCU,实现了基于串口(支持RS485)的通用Bootloader方案。与常规方案相比,其创新点在于:
- 采用双状态机架构处理通信协议与固件写入流程
- 支持CRC32校验和断点续传机制
- 适配三种芯片的Flash操作差异
- 通过RS485实现最长1200米的远程升级
实际测试数据显示,在115200bps波特率下,完成256KB固件传输仅需28秒(Ymodem协议),校验成功率可达99.99%。该方案已成功应用于工业控制器、智能电表等场景。
2. 硬件设计与芯片适配
2.1 硬件接口定义
典型硬件连接方案如下表所示:
| 接口类型 | STM32引脚 | AT32引脚 | GD32引脚 | 说明 |
|---|---|---|---|---|
| USART_TX | PA9 | PA2 | PA9 | 需接MAX3485芯片TTL转RS485 |
| USART_RX | PA10 | PA3 | PA10 | 建议串联100Ω电阻 |
| BOOT0 | PB2 | PB2 | PB2 | 硬件复位时拉高进入Bootloader模式 |
| LED指示灯 | PC13 | PC1 | PC13 | 双色LED指示状态 |
关键提示:RS485总线必须加120Ω终端电阻,AB线间建议并联TVS二极管防护
2.2 三款MCU的Flash差异处理
三种芯片的Flash控制器存在关键差异:
-
STM32F1系列:
- 页大小1KB
- 擦除时间典型值40ms
- 需要先解锁FLASH_CR寄存器
-
GD32F1x0系列:
- 页大小2KB
- 擦除时间较短约20ms
- 操作前需清除FLASH_SR寄存器标志位
-
AT32F403A系列:
- 支持双Bank操作
- 页大小2KB
- 擦除命令需要特殊序列
代码实现时通过宏定义区分处理:
c复制#if defined(GD32)
fmc_unlock();
fmc_page_erase(addr);
#elif defined(AT32)
flash_unlock();
flash_erase_page(FLASH_BANK_1, addr);
#else
FLASH_Unlock();
FLASH_ErasePage(addr);
#endif
3. 软件架构设计
3.1 双状态机工作流程
项目采用通信状态机(COMM_FSM)和编程状态机(PROG_FSM)协同工作:
code复制COMM_FSM状态迁移图:
IDLE → WAIT_CMD → RECV_FILE → VERIFY_CRC → ACK_RESULT
↓ ↑
└── TIMEOUT ──┘
PROG_FSM状态迁移图:
INIT → ERASE → WRITE → VERIFY → JUMP_APP
↑ ↓ ↑
└── FAIL ────────┘
3.2 关键数据结构
c复制typedef struct {
uint32_t file_size;
uint32_t crc_value;
uint8_t file_type; // 0:bin 1:hex
uint8_t encrypt_flag;
} FileInfo_t;
typedef struct {
uint32_t base_addr;
uint32_t max_size;
uint32_t page_size;
uint8_t reserved;
} FlashLayout_t;
4. 通信协议实现
4.1 自定义协议帧格式
code复制| 0xAA | 0x55 | CMD | LEN | DATA[LEN] | CRC16 | 0x0D | 0x0A |
-------------------------------------------------------------
头标识 命令码 数据长度 数据域 校验 尾标识
4.2 协议指令集
| 指令码 | 功能 | 响应格式 |
|---|---|---|
| 0x01 | 握手信号 | ACK+版本号 |
| 0x02 | 查询Flash信息 | ACK+起始地址+总大小 |
| 0x03 | 擦除指定扇区 | ACK+结果 |
| 0x04 | 写入数据块 | ACK+偏移地址 |
| 0x05 | 校验固件 | ACK+CRC32值 |
| 0x06 | 跳转到应用程序 | 无响应 |
4.3 CRC校验优化
采用查表法加速CRC计算,预先计算256元素的CRC表:
c复制void crc32_init(uint32_t *table) {
uint32_t crc;
for(int i=0; i<256; i++) {
crc = i;
for(int j=0; j<8; j++)
crc = (crc>>1) ^ (crc&1 ? 0xEDB88320 : 0);
table[i] = crc;
}
}
5. Bootloader跳转机制
5.1 应用程序向量表重定位
需在应用程序中设置VTOR寄存器:
c复制// 应用程序的system_init()中添加
SCB->VTOR = FLASH_BASE | 0x4000; // Bootloader占用16KB
5.2 安全跳转流程
c复制void jump_to_app(uint32_t app_addr) {
typedef void (*pFunction)(void);
pFunction Jump_To_Application;
__disable_irq();
// 检查栈顶地址是否合法
if(((*(__IO uint32_t*)app_addr) & 0x2FFE0000) == 0x20000000) {
// 设置主堆栈指针
__set_MSP(*(__IO uint32_t*)app_addr);
// 获取复位向量
Jump_To_Application = (pFunction)(*(__IO uint32_t*)(app_addr + 4));
// 初始化应用程序的向量表
SCB->VTOR = app_addr;
// 跳转执行
Jump_To_Application();
}
NVIC_SystemReset();
}
6. 上位机工具开发建议
6.1 Python实现示例
python复制import serial
import crcmod
class BootloaderClient:
def __init__(self, port):
self.ser = serial.Serial(port, baudrate=115200, timeout=1)
self.crc32_func = crcmod.mkCrcFun(0x104C11DB7, initCrc=0xFFFFFFFF)
def send_cmd(self, cmd, data=None):
packet = bytearray([0xAA, 0x55, cmd])
if data:
packet.append(len(data))
packet.extend(data)
else:
packet.append(0)
crc = self.crc16(packet[2:])
packet.extend([crc >> 8, crc & 0xFF, 0x0D, 0x0A])
self.ser.write(packet)
return self.wait_ack()
def upload_firmware(self, file_path):
with open(file_path, 'rb') as f:
data = f.read()
total_size = len(data)
# 发送文件信息头
header = struct.pack('<IIBB', total_size,
self.crc32_func(data), 0, 0)
if not self.send_cmd(0x10, header):
return False
# 分块发送数据
chunk_size = 256
for i in range(0, total_size, chunk_size):
chunk = data[i:i+chunk_size]
if not self.send_cmd(0x11, chunk):
return False
return self.send_cmd(0x12) # 触发校验
7. 实际部署经验
7.1 抗干扰措施
- 在RS485接口处增加磁珠滤波(如BLM18PG221SN1)
- 每个数据包增加超时重传机制(建议3次重试)
- 关键操作增加硬件看门狗复位保护
7.2 性能优化技巧
- 使用DMA加速串口数据传输
- Flash写入采用双缓冲机制
- 对连续空白页跳过擦除操作
7.3 典型问题排查
-
跳转失败:
- 检查应用程序的向量表偏移配置
- 验证栈顶地址是否合法(0x20000000范围内)
- 确认没有全局中断未关闭
-
RS485通信异常:
- 用示波器检查AB线差分电压(应大于200mV)
- 测试终端电阻阻值(120Ω±5%)
- 检查MAX3485芯片的DE/RE控制时序
-
Flash写入错误:
- 确认操作地址按页对齐
- 检查供电电压是否稳定(≥2.7V)
- 降低编程速度(插入5ms延时)
该方案在工业现场经过连续72小时压力测试,累计完成500+次远程升级,可靠性达到工业级要求。对于需要OTA升级但又受限于成本的设备,这种串口IAP方案具有显著的成本优势——相比无线方案可降低60%以上的BOM成本。
