当前位置:首页 > 消费电子 > 消费电子
[导读]小家电“静默升级”不是后台偷偷写当前固件,而是运行区不动、新包写备用区、校验过再重启切换。电饭煲煮饭、扫地机回充途中被覆盖Flash,一半断电就变砖。正确架构是A/B双分区 + BootLoader仲裁 + 下载任务后台跑。


小家电“静默升级”不是后台偷偷写当前固件,而是运行区不动、新包写备用区、校验过再重启切换。电饭煲煮饭、扫地机回充途中被覆盖Flash,一半断电就变砖。正确架构是A/B双分区 + BootLoader仲裁 + 下载任务后台跑。

一、Flash分区规划

以256KB级MCU为例:

0x0000  BootLoader  (只读,校验+跳转)

0x5000  Param区     (版本/启动槽/尝试计数/下载偏移)

0x8000  APP_A       (当前运行)

0x...   APP_B       (备用)

APP_A/B必须等大,Param区单独分出来,按字节写标志,别和代码区混。

二、下载任务:只碰备用区

收到云端版本推送后,先判断自己是不是目标版本、设备是否busy:

typedef struct {

   uint8_t  active_slot;     // 0=A,1=B

   uint8_t  pending_slot;    // 待验证槽

   uint8_t  try_cnt;        // 启动尝试次数

   uint32_t dl_offset;      // 断点偏移

   uint8_t  state;

} boot_param_t;


void ota_task(void*p){

   if(ota_check_version()==NO_UPDATE) return;

   if(device_busy()){        // 加热/电机/充电中不升

       return;

   }

   if(battery_or_vin() < 30%) return;   // 电量门槛


   uint32_t off = param.dl_offset;

   while(off < fw_total){

       int n = net_recv_block(fw_buf, BLOCK_SZ, off);

       if(n<=0){ vTaskDelay(1000); continue; }   // 弱网退避

       flash_erase_write(APP_B + off, fw_buf, n);

       off += n;

       param.dl_offset = off;

       save_param();         // 断点持久化

   }

}

要点:

写的是APP_B,当前APP_A继续跑业务

块粒度写入,每块落Flash再存offset

网络断重连从dl_offset续传,不重头下

下载任务优先级低于控制业务,阻塞等数据不占CPU

三、校验:下载完别急着重启

整包收完做两层校验:

if(sha256_file(APP_B, fw_total) != hdr.sha256)

   goto ota_abort;

if(rsa_verify(hdr.sig, APP_B, fw_total) != OK)

   goto ota_abort;

只做CRC不够,量产要签名校验挡掉非法固件。 校验过才写pending:

param.pending_slot = 1;   // 下次起B

param.try_cnt = 0;

save_param();

// 不立即重启

“用户无感知”就在这:下载校验都在后台完成,机器照常工作。

四、择机重启 + BootLoader仲裁

别在用户按启动键时重启。等空闲窗口:

设备进入待机

凌晨定时(如2:00~5:00)

连续无操作N秒

if(param.pending_slot!=0xFF && idle_secure()){

   sys_soft_reset();

}

BootLoader上电逻辑:

void bootloader_main(void){

   read_param();

   if(param.pending_slot != 0xFF){

       if(image_valid(APP_B)){

           jump_slot = APP_B;

       }else{

           pending_slot = 0xFF;       // 校验失败回A

       }

   }

   if(try_cnt_exceed(jump_slot)){

       jump_slot = active_slot;       // 回滚

   }

   param.try_cnt++;

   save_param();

   jump_to(jump_slot);

}

决策权在BootLoader,不在APP。

五、新固件自确认

新固件起来后必须“报到”,否则看门狗超时回滚:

void app_after_ota(void){

   if(is_pending_boot()){

       self_test();          // 外设/通信/加热自检

       mark_slot_valid();    // 写Param:B已确认

       param.pending_slot = 0xFF;

       param.active_slot = 1;

       param.try_cnt = 0;

       save_param();

   }

}

规则:

启动30秒内没mark valid → 下次BootLoader切回A

看门狗复位try_cnt累加,超3次锁定旧版

回滚原因写日志,上报云端

六、静默体验三红线

不写当前运行区 → 双分区兜底

不用户操作中重启 → busy判断+空闲窗口

不信任未校验固件 → SHA256+签名

附加细节:

版本检测走定时唤醒,别一直连Wi-Fi

差分升级(bsdiff)小家电固件体积能砍80%

灰度先推1%再放量

Param区双备份,掉电可恢复

七、落坑清单

单分区直接擦APP区→断电变砖

下载完立刻重启→用户正用着突然黑屏

只校验CRC不验签名→恶意包可刷入

不存dl_offset→弱网每次重下

新固件不mark valid→每次都回滚

BootLoader不计数→坏固件死循环重启

加热/电机中升级→中断业务逻辑

电量低于30%还写Flash→掉电残片

八、落地顺序

Flash划Boot/Param/APP_A/APP_B

下载任务写备用区,块级落盘+offset

SHA256+签名校验

置pending,不重启

待机/定时窗口软复位

BootLoader校验+跳槽+try_cnt

新固件自检mark valid

超时/崩溃自动回滚A

云端上报版本+灰度

小家电静默OTA的本质就一句:升级过程永远不碰正在跑的那份固件。后台下载到B区、校验过再给BootLoader交棒、新固件自己确认存活——用户侧表现就是“昨晚还在煮饭,今早发现版本号高了”。没双分区、没BootLoader仲裁、没自确认机制,都算Demo级OTA,量产返修率会教你做人。



本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除( 邮箱:macysun@21ic.com )。
关闭