1. STM32远程升级系统架构解析
在野外设备维护中,最头疼的就是设备程序需要更新时得派人跑到现场。我们设计的这套系统基于STM32F103芯片,通过4G模块实现远程无线升级,彻底解决这个痛点。整个系统由三部分组成:Bootloader程序、三个主应用程序(AppA/B/C)以及远程服务器端。
1.1 存储空间分配方案
Flash空间划分是IAP设计的核心,以STM32F103C8T6(64KB Flash)为例:
code复制0x08000000-0x08003FFF 16KB Bootloader区
0x08004000-0x0801BFFF 96KB AppA区(只读)
0x0801C000-0x08037FFF 112KB AppB区
0x08038000-0x08053FFF 112KB AppC区
0x08054000-0x08057FFF 16KB 参数存储区
这种分配方式考虑了几个关键因素:
- Bootloader预留16KB空间,确保有足够空间实现复杂校验逻辑
- AppA作为出厂程序永久保留,尺寸固定为96KB
- AppB和AppC采用相同大小设计,便于镜像切换
- 单独划分参数区存储升级记录和系统配置
实际项目中要根据芯片具体Flash容量调整,比如STM32F103RET6(512KB)可以给每个App分配128KB空间。
1.2 程序跳转机制
Bootloader启动后首先检查升级标志位,若无升级需求则根据当前运行标志跳转到对应App。关键跳转代码如下:
c复制typedef void (*pFunction)(void);
void JumpToApp(uint32_t appAddress)
{
pFunction Jump_To_App;
/* 检查栈顶地址是否合法 */
if(((*(__IO uint32_t*)appAddress) & 0x2FFE0000) == 0x20000000)
{
/* 设置主堆栈指针 */
__set_MSP(*(__IO uint32_t*) appAddress);
/* 获取复位向量地址 */
Jump_To_App = (pFunction)(*(__IO uint32_t*)(appAddress + 4));
/* 跳转到应用程序 */
Jump_To_App();
}
}
这个跳转过程需要注意:
- 必须先关闭所有中断
- 复位所有外设寄存器
- 重新初始化堆栈指针
- 检查目标地址有效性
2. 防变砖多重保护机制
2.1 三级备份系统设计
我们采用独特的"1+2"备份方案:
- AppA:出厂固化程序,永远不更新,作为最后保障
- AppB:主运行程序,可远程更新
- AppC:镜像备份程序,更新时先写入此处
升级流程采用"写备份→校验→切换"的三步法:
- 新固件下载到AppC区域
- CRC32校验通过后设置标志位
- 重启后Bootloader将AppC内容复制到AppB
2.2 固件完整性验证
除了常规的CRC校验,我们还增加了三重验证:
- 头信息校验:固件前16字节包含魔数(0xA5A5A5A5)、版本号、大小等信息
- SHA-256摘要:固件尾部附加256位摘要值
- 运行测试:跳转前先执行基本功能自检
校验失败时的处理策略:
mermaid复制graph TD
A[收到新固件] --> B{头信息校验}
B -->|失败| C[删除固件]
B -->|通过| D{CRC校验}
D -->|失败| C
D -->|通过| E{SHA256校验}
E -->|失败| C
E -->|通过| F[设置升级标志]
2.3 看门狗防护系统
为防止升级过程中死机,我们部署了三级看门狗:
- 硬件看门狗:使用STM32内置IWDG, timeout=4s
- 软件看门狗:FreeRTOS任务监控,3s喂狗
- 网络看门狗:4G通信心跳检测,30s超时
喂狗策略示例:
c复制void Watchdog_Feed(void)
{
static uint32_t counter = 0;
IWDG_ReloadCounter(); // 硬件看门狗
if(xTaskGetTickCount() - lastFeedTime > 3000){
vTaskSuspendAll(); // 暂停所有任务
NVIC_SystemReset(); // 强制复位
}
if(++counter % 10 == 0){
EC200T_SendAT("AT+CPING=\"8.8.8.8\""); // 网络检测
}
}
3. 4G远程升级实现细节
3.1 EC200T模块配置
移远EC200T模块通过AT命令控制,关键配置流程:
- 初始化序列:
bash复制AT+CFUN=1 # 全功能模式
AT+CPIN? # 检查SIM卡
AT+CREG? # 网络注册
AT+CGATT=1 # 附着网络
- FTP下载配置:
bash复制AT+QFTPCFG="contextid",1
AT+QFTPCFG="transmode",1 # 被动模式
AT+QFTPCFG="account","username"
AT+QFTPCFG="password","pass123"
- 文件下载命令:
bash复制AT+QFTPGET="ftp.server.com","/firmware/appB.bin",1
实际使用中发现EC200T的FTP客户端对服务器响应时间敏感,建议在服务器端配置KeepAliveTimeout 300以上。
3.2 断点续传实现
野外环境网络不稳定,我们实现了分段下载机制:
- 在参数区记录已下载字节数
- 每次连接从断点位置继续下载
- 每接收1KB数据立即写入Flash并更新记录
关键代码片段:
c复制uint32_t resume_position = Read_DownloadPos();
char cmd[128];
sprintf(cmd, "AT+QFTPGET=\"%s\",\"%s\",1,%lu", server, path, resume_position);
Send_AT_Cmd(cmd);
while(1){
uint8_t buffer[1024];
uint16_t len = Receive_Data(buffer);
FLASH_Write(buffer, len);
resume_position += len;
Save_DownloadPos(resume_position);
}
4. 上位机控制协议设计
4.1 通信协议格式
采用精简的二进制协议,帧结构:
| 偏移 | 长度 | 说明 |
|---|---|---|
| 0 | 1 | 帧头0xAA |
| 1 | 1 | 命令字 |
| 2 | 2 | 数据长度 |
| 4 | N | 数据体 |
| N+4 | 2 | CRC16 |
常用命令码:
- 0x01:查询当前App
- 0x02:切换App
- 0x03:启动升级
- 0x04:传输数据
- 0x05:确认升级
4.2 安全认证机制
为防止非法控制,我们采用动态令牌认证:
- 设备上电生成随机数Token(4字节)
- 上位机发送用户名+MD5(密码+Token)
- 设备验证通过后建立会话
认证流程示例:
python复制def build_auth_packet(username, password, token):
import hashlib
m = hashlib.md5()
m.update(password.encode() + token.to_bytes(4, 'big'))
digest = m.digest()
return b'\xAA\x00\x10' + username.encode() + digest
5. 实战问题排查手册
5.1 典型故障处理表
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| 升级后无法启动 | 固件校验失败 | 检查Bootloader日志,确认下载完整性 |
| 4G连接超时 | SIM卡欠费 | 检查AT+COPS?返回状态 |
| FTP登录失败 | 服务器防火墙 | 测试telnet server 21端口 |
| App切换无效 | Flash写入失败 | 使用STM32 ST-LINK Utility验证Flash内容 |
5.2 调试技巧
- Bootloader日志输出:
c复制#define DEBUG_PORT USART1
void Log_Printf(char *fmt, ...)
{
va_list args;
va_start(args, fmt);
char buffer[128];
vsprintf(buffer, fmt, args);
for(char *p=buffer; *p; p++){
while(!(DEBUG_PORT->SR & USART_SR_TXE));
DEBUG_PORT->DR = (*p & 0xFF);
}
va_end(args);
}
- 内存泄漏检测:
在FreeRTOSConfig.h中配置:
c复制#define configUSE_TRACE_FACILITY 1
#define configUSE_STATS_FORMATTING_FUNCTIONS 1
然后通过任务命令查看内存使用:
bash复制vTaskList(buffer); // 获取任务列表
vTaskGetRunTimeStats(buffer2); // 获取CPU占用率
- 网络质量测试:
bash复制AT+QPING=1,"8.8.8.8" # 测试ping延迟
AT+QENG="servingcell" # 获取基站信息
这套系统在我们多个野外气象站项目中稳定运行超过2年,最远的一次升级是在海拔4500米的青藏高原监测站完成的。关键是要做好各种异常情况的处理预案,比如升级过程中突然断电的情况,我们通过在Flash参数区记录升级状态,下次上电时会自动回滚到上一个可用版本。
