1. 项目概述:STM32F103远程升级系统设计
在工业物联网和野外设备维护场景中,固件升级一直是个棘手问题。传统方式需要技术人员到现场通过JTAG/SWD接口烧录,不仅效率低下,在偏远地区还会产生高昂的维护成本。我们基于STM32F103系列芯片和EC200T 4G模块设计的远程升级系统,通过三重程序备份和智能切换机制,实现了安全可靠的无线固件更新。
这套系统的核心价值在于:
- 防变砖设计:通过保留永不更改的出厂程序A作为最后防线,即使连续两次升级失败也能恢复基础功能
- 无缝切换:运行中的程序B和备用程序C可通过上位机指令随时切换,支持灰度发布和AB测试
- 协议无关:核心升级逻辑与传输方式解耦,可适配FTP/HTTP/MQTT等多种协议
- 资源节约:在128KB Flash的STM32F103C8T6上实现完整方案,Bootloader仅占用16KB空间
2. 硬件架构与选型解析
2.1 主控芯片:STM32F103系列
选择STM32F103C8T6作为主控基于以下考量:
- 性价比:Cortex-M3内核提供72MHz主频,市场均价仅10元左右
- Flash布局:64KB/128KB容量支持多程序存储(以128KB型号为例):
code复制0x08000000-0x08003FFF Bootloader (16KB) 0x08004000-0x0800BFFF 程序A (32KB) 0x0800C000-0x08013FFF 程序B (32KB) 0x08014000-0x0801BFFF 程序C (32KB) 0x0801C000-0x0801FFFF 参数区 (16KB) - 调试接口:保留SWD接口用于紧急恢复,但日常通过4G无线升级
注意:使用前务必确认芯片Flash实际大小,部分C8T6可能存在64KB/128KB版本混用情况
2.2 通信模块:EC200T 4G模组
EC200T相比其他4G模块的优势:
- 协议支持:内置TCP/IP协议栈,支持PPP拨号与Socket直连
- 功耗控制:支持PSM模式,待机电流低至0.7mA
- 接口简单:通过UART AT指令控制,硬件设计仅需:
c复制// 典型接线 EC200T_TX -> USART2_RX(PA3) EC200T_RX -> USART2_TX(PA2) EC200T_PWRKEY -> PC13 // 硬件复位控制
3. 软件架构设计
3.1 多程序存储策略
c复制typedef struct {
uint32_t crc32; // 程序校验值
uint32_t version; // 版本号(年月日+序号)
uint32_t entry_addr; // 跳转地址
uint8_t reserved[20]; // 预留扩展
} AppHeader_t;
// 通过链接脚本固定各程序位置
MEMORY {
BOOTROM (rx) : ORIGIN = 0x08000000, LENGTH = 16K
APP_A (rx) : ORIGIN = 0x08004000, LENGTH = 32K
APP_B (rx) : ORIGIN = 0x0800C000, LENGTH = 32K
APP_C (rx) : ORIGIN = 0x08014000, LENGTH = 32K
}
3.2 Bootloader工作流程
-
启动自检:
- 检查RTC备份寄存器中的异常标志
- 验证当前运行程序的CRC32
- 若异常则自动回滚到程序A
-
升级处理:
mermaid复制graph TD A[接收升级指令] --> B{验证协议头} B -->|成功| C[擦除目标区域] C --> D[分块写入+校验] D --> E[写入程序头] E --> F[更新启动参数] -
程序跳转:
c复制void JumpToApp(uint32_t addr) { typedef void (*pFunction)(void); pFunction AppStart; __set_MSP(*(__IO uint32_t*)addr); AppStart = (pFunction)(*(__IO uint32_t*)(addr + 4)); AppStart(); }
4. 远程升级协议设计
4.1 通信协议帧格式
| 偏移量 | 长度 | 字段 | 说明 |
|---|---|---|---|
| 0 | 1 | 帧头(0xAA) | 起始标志 |
| 1 | 1 | 命令字 | 0x01:查询 0x02:升级 |
| 2 | 2 | 数据长度 | 大端格式 |
| 4 | N | 数据体 | 升级时为bin文件分片 |
| N+4 | 2 | CRC16 | 从帧头到数据体的校验 |
4.2 升级过程状态机
c复制typedef enum {
STATE_IDLE,
STATE_DOWNLOADING,
STATE_VERIFYING,
STATE_UPDATING,
STATE_ROLLBACK
} UpgradeState_t;
// 通过事件组同步状态
#define EVENT_DL_COMPLETE (1 << 0)
#define EVENT_VERIFY_OK (1 << 1)
#define EVENT_FLASH_DONE (1 << 2)
5. 防变砖机制实现
5.1 三级恢复策略
- 初级恢复:当前程序CRC校验失败时,自动加载另一备份程序
- 中级恢复:关键参数区损坏时,使用出厂默认值重建
- 终极恢复:通过硬件看门狗+备份寄存器强制回滚到程序A
5.2 看门狗配置技巧
c复制// 独立看门狗配置
IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);
IWDG_SetPrescaler(IWDG_Prescaler_256); // 约1.6s超时
IWDG_SetReload(0xFFF);
IWDG_ReloadCounter();
IWDG_Enable();
// 在关键线程中喂狗
void MonitorThread(void *arg) {
while(1) {
IWDG_ReloadCounter();
osDelay(1000);
}
}
6. 上位机交互设计
6.1 控制指令集
| 指令码 | 功能 | 参数格式 |
|---|---|---|
| 0xA1 | 查询当前程序版本 | 无 |
| 0xA2 | 切换运行程序 | 1字节(A/B/C) |
| 0xA3 | 启动远程升级 | 2字节(目标程序) |
| 0xA4 | 暂停/继续传输 | 1字节(0/1) |
6.2 文件传输优化
采用滑动窗口协议提升传输效率:
- 窗口大小:8个包(约4KB)
- 重传机制:3次尝试失败后中止
- 流量控制:根据RSSI动态调整分片大小
7. 实际部署注意事项
-
电源管理:
- 升级期间禁用低功耗模式
- 配置超级电容应对突发断电
- 增加电压监测电路
-
信号处理:
c复制// EC200T信号质量检测 int GetCSQ(void) { SendATCommand("AT+CSQ"); // 返回值为0-31(99表示无效) return ParseResponse(); } -
异常处理:
- 记录最后错误码到Flash
- 通过短信告警通知维护人员
- 支持断点续传
8. 性能优化技巧
-
Flash写入加速:
c复制void FlashWrite(uint32_t addr, uint8_t *buf, uint32_t len) { FLASH_Unlock(); FLASH_ClearFlag(FLASH_FLAG_BSY | FLASH_FLAG_EOP | FLASH_FLAG_PGERR); for(int i=0; i<len; i+=2) { uint16_t data = buf[i] | (buf[i+1] << 8); FLASH_ProgramHalfWord(addr+i, data); } FLASH_Lock(); } -
内存管理:
- 使用静态分配替代malloc
- 关键缓冲区双缓冲设计
- 合理设置FreeRTOS堆大小
9. 测试验证方案
9.1 压力测试用例
| 测试项 | 预期结果 |
|---|---|
| 连续升级10次 | 系统稳定性无异常 |
| 强制断电测试 | 能自动恢复到最后有效状态 |
| 信号切换测试 | 支持基站切换不中断 |
9.2 自动化测试脚本
python复制import serial
import time
def test_switch_app(port, target):
ser = serial.Serial(port, 115200)
cmd = bytes([0xAA, 0xA2, target])
ser.write(cmd)
time.sleep(1)
resp = ser.read(5)
assert resp[0] == 0xBB # 应答帧头
10. 扩展应用方向
-
安全增强:
- 增加RSA签名验证
- 实现差分升级
- 支持加密传输
-
运维功能:
- 远程日志下载
- 实时状态监控
- 批量设备管理
-
协议扩展:
- 适配CoAP/LwM2M
- 支持MQTT over TLS
- 集成WebSocket
在实际部署中我们发现,通过合理设置程序头中的版本号字段,可以实现灰度发布功能——先升级少量设备观察运行状态,确认稳定后再批量推送。同时保留两个可升级程序区域的设计,��得我们可以进行AB测试,比较不同版本的实际表现。
