ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

基于 AS32S601 的 A/B 网络 OTA 方案:eFlash 约束、断电保护与自动回滚

基于 AS32S601 的 A/B 网络 OTA 方案:eFlash 约束、断电保护与自动回滚 摘要网络 OTA 的核心不是把新固件写进 Flash而是保证任何时刻掉电、复位或新镜像启动失败时设备仍能回到一个可信、可启动的版本。本文以 AS32S601 的 eFlash 约束为边界给出 A/B 双镜像、双份状态记录、Pending 启动意图与确认回滚机制的实现框架。文中涉及寄存器位值和厂商底层函数的地方均保留为 BSP/伪代码接口避免把未经验证的实现细节当成芯片事实。1. 为什么 OTA 不能覆盖正在运行的镜像单镜像升级的最大风险是下载任务、Flash 驱动和业务代码本身都在当前镜像中执行。擦除或改写当前执行区会让取指、异常处理和中断向量同时失去稳定性即使暂时没有跑飞掉电也会留下半写入镜像。写入目标必须是非活动区活动镜像在新版本确认前始终保留。“下载完成”不等于“可启动”镜像完整性、状态记录提交、首次启动与应用确认必须分阶段处理。回滚不是故障补丁而是启动器在超时、复位或确认失败时的正常决策路径。2.AS32S601eFlash决定方案边界的硬件约束根据芯片设计手册第 5 章PFlash 最大容量为 2 MB4 个 512 KB blockDFlash 最大容量为 512 KB。eFlash 的 sector 为 4 KB、row 为 512 B编程最小粒度为 64 bit目标地址需 8 字节对齐并且一次编程不得跨越 row。擦除命令为 sector erase 0x01、block erase 0x02编程命令为 0x10。状态轮询应围绕 BUSY 与 FINISH错误收敛至少检查 OPERR、WPERR、ECC1ERR、ECC2ERR。设计手册还明确当一个 block 正在擦除或编程时只支持读取另一个 block。因此 Bootloader、Flash 驱动和被读取的关键常量必须落在与被操作 block 不同的区域或在进入 Flash 操作前转入 RAM 执行。时钟配置也应被纳入启动顺序仅在系统时钟初始化完成后且 eFlash 空闲未执行擦除/编程时设置 EFLASH_CNFG.CLKFRQ。具体频率编码、寄存器位值及解锁序列请以当前芯片版本手册和 BSP 为准本文不假设其数值。约束已验证的设计事实实现含义容量与 blockPFlash 最大 2 MB / 4 × 512 KBDFlash 最大 512 KB分区只是示例链接脚本和区大小必须以实际型号容量为准。擦除与 rowsector 4 KBrow 512 B擦除按 sector 规划下载块可小于等于 512 B。编程粒度最小 64 bit地址 8 字节对齐不得跨 row写入前做对齐、长度和 row 边界检查。并发读取操作一个 block 时仅可读取另一个 block擦/写期间完整执行路径和中断行为要么都在另一物理 block要么整体转入 RAM。完成与错误BUSY / FINISHOPERR / WPERR / ECC1ERR / ECC2ERR每次操作后等待完成、读取状态、清错并记录失败原因。3. A/B 分区与双份状态记录设计一个实用的布局是Bootloader 放在固定、受保护的启动区应用槽 A 和槽 B 分别存放完整镜像状态记录放在独立的小型元数据区。这里的容量分配只是一种示例不能直接套用到所有 AS32S601 型号链接脚本、镜像上限、状态区位置和分区大小必须与实际 device capacity、block 边界及产品功能一起确定。状态记录采用双份Record-0 / Record-1并增加序号 generation。明确建议把 Record-0 与 Record-1 放在两个可独立擦除的 4 KB sector更新前先确认另一份当前被启动器选中的记录已提交且 CRC 合法绝不擦除唯一有效副本随后只擦除非活动记录所在的 sector。这样可避免“擦掉唯一状态页后掉电”的单点风险。非活动记录的提交顺序应是擦除后写入除 commit 外的 staged payloadcommit 保持擦除态回读并校验字段与 payload CRC再把 commit 作为最后一步从擦除态编程为完成态。commit 必须独占一个 8 字节对齐的 64-bit 编程单元且不纳入 staged payload CRC最终还要回读确认 commit、字段和 CRC 同时有效。启动时只在 commit 与 CRC 都正确的副本中选择 generation 更大的记录。字段示例含义启动器处理magic / format_version记录身份与格式版本不匹配则忽略该副本。generation单调递增的记录序号在 CRC 合法副本中选较新者。active_slot / pending_slot当前确认槽与候选槽Pending 仅用于一次受控试启动。image_size / image_crc候选镜像长度与完整性摘要跳转前按产品策略校验长度和 CRC。boot_attempts / confirm_deadline试启动计数或确认窗口超限或超时则撤销 Pending 并回到 active_slot。record_crc / commitpayload CRC 与最终提交标志commit 不计入 payload CRCcommit 是独立 64-bit 单元的最后一次编程任一项无效即回退另一份记录。图 1 总体升级策略4. 网络 OTA 主流程先写非活动区再切换启动意图启动器从双份状态记录恢复 active_slot并启动已经确认的应用镜像。应用接收版本、镜像长度、摘要和签名等元数据确认目标为非活动槽。按 sector 擦除目标槽并以不跨 512 B row 的小块下载、编程和读取回校。完整镜像验证通过后预先验证当前状态副本仍有效擦除非活动记录所在的独立 4 KB sector回读校验 staged payload 后最后以独立 64-bit commit 单元提交 pending_slot。此时尚未改变 active_slot。复位后 Bootloader 仅把 pending_slot 当作候选镜像试启动应用自检成功后显式确认才提升为 active_slot。镜像认证机制应结合产品安全目标选择例如受保护的版本元数据、签名验证、防回滚版本计数和密钥存储。CRC 可以发现传输或存储错误但不能替代来源认证。5. eFlash 写入实现擦除、行编程与校验将网络分包与 Flash 物理写入解耦网络层可以收到任意长度的数据但 Flash 层必须把它整理为 8 字节对齐、最多一个 row 的写入单元。跨 row 的尾部数据应留在 RAM 缓冲区与下一包拼接后再写入未满 64 bit 的镜像尾部可按镜像格式填充并计入完整性校验。读写并发约束要按“完整执行闭包”审查而不是只把一个 Flash 驱动函数放入 RAM任一 PFlash erase/program 事务期间要么活动可执行区以及所有可达的指令、常量、向量表和中断处理函数都位于被操作 block 以外的物理 block要么把完整调用路径连同相关中断行为整体迁入 RAM或在事务窗口内按产品策略禁止/接管中断。仅搬移 driver 函数仍可能因常量访问、异常或中断取指而违反跨 block 读取限制。清单 1 单个下载块的边界检查BSP/伪代码static ota_result_t ota_program_chunk(uint32_t dst, const uint8_t *src, size_t len){if ((dst 0x7U) ! 0U || len 0U || (len 0x7U) ! 0U || len 512U) return OTA_ALIGN_ERR;if (((dst 0x1FFU) len) 512U) return OTA_ROW_CROSS_ERR;eflash_unlock();if (!eflash_wait_idle()) return OTA_BUSY_ERR;eflash_program_64bit_units(dst, src, len);return eflash_finish_and_clear_status();}上例的 eflash_unlock、eflash_wait_idle、eflash_program_64bit_units 与状态清除均为 BSP 接口名称。实际实现应在每个 sector 擦除和每次编程后检查 FINISH/错误状态并把 OPERR、WPERR、ECC1ERR、ECC2ERR 映射为可追踪的失败原因。清单 2 双份状态记录的安全提交顺序BSP/伪代码ota_result_t ota_commit_pending(const ota_state_t *next){ota_state_t staged *next;if (!state_other_committed_copy_is_valid()) return OTA_STATE_PRECONDITION_ERR;staged.generation ota_next_generation();staged.commit OTA_COMMIT_ERASED;staged.record_crc crc32_staged_payload_excluding_commit(staged);if (!state_erase_inactive_record_4k_sector()) return OTA_STATE_ERASE_ERR;if (!state_write_payload_except_commit(staged)) return OTA_STATE_WRITE_ERR;if (!state_readback_payload_valid(staged)) return OTA_STATE_VERIFY_ERR;if (!state_program_commit_64bit(OTA_COMMIT_DONE)) return OTA_STATE_COMMIT_ERR;return state_readback_committed_valid(staged) ? OTA_OK : OTA_STATE_VERIFY_ERR;}清单中的 state_* 是表达顺序与前置条件的 BSP/伪代码接口不代表厂商 API。state_erase_inactive_record_4k_sector 只能针对未被当前启动决策依赖的那一个记录 sectorstate_write_payload_except_commit 保持 commit 擦除态state_program_commit_64bit 则把独占、8 字节对齐的 commit 单元作为最后一次 64-bit 编程。payload CRC 的计算范围明确排除 record_crc 自身和 commit 字段避免 commit 状态变化破坏 staged payload 的校验。6. 启动确认与自动回滚候选镜像第一次启动不应立即覆盖 active_slot。Bootloader 可在跳转前递增 boot_attempts 或写入短期试启动标志应用完成时钟、外设、配置迁移和业务自检后调用一个受控的确认接口。若确认窗口内发生看门狗复位、硬复位或再次上电Bootloader 保持/撤销 Pending 并回到已确认槽。清单 3 启动器选择逻辑伪代码boot_target_t boot_select_target(const ota_state_t *state){if (!state_is_valid(state)) return boot_factory_or_safe_image();if (state-pending_slot ! OTA_SLOT_NONE pending_is_eligible(state))return boot_try_pending_once(state-pending_slot);return boot_confirmed_slot(state-active_slot);}void app_confirm_healthy(void){/* 仅在应用自检、配置迁移与关键通信均成功后调用。 */ota_confirm_pending_via_bsp();}图 2 启动确认与回滚7. 断电恢复把每一个中间态设计成可启动断电恢复设计的关键是区分“数据还没写完”和“意图已经提交”。擦除/下载中的非活动镜像可以丢弃状态切换则必须先验证另一独立记录 sector 有效再擦除非活动 sector随后写入 payload、回读校验最后以单独的 64-bit commit 单元提交。启动器永远只信任 CRC 与 commit 都正确的最新记录因此在任意写入指令之间掉电都能找到旧记录或新记录而不是半条记录。擦除过程中掉电目标槽保持无效已确认槽继续启动。镜像写入过程中掉电不写 pending_slot下一次 OTA 从断点策略或重新下载开始。状态副本擦除、payload 写入或预提交回读中掉电commit/CRC 不通过启动器选择另一独立 sector 中的旧副本。Pending 试启动中掉电确认未发生按尝试次数或确认窗口回到已确认镜像。确认写入中掉电双份状态记录保证至少保留一个可判定的有效副本。图 3 异常与断电恢复8. 安全边界与测试清单A/B 解决的是可用性和可恢复性不自动等于安全 OTA。生产方案应把传输保护、镜像来源认证、密钥生命周期、版本防回滚、调试口策略和故障日志纳入同一威胁模型。不要把下载通道的 TLS 或 CRC 当成固件签名验证的替代品。测试项注入方式期望结果row 边界在 512 B row 末尾构造跨界分包Flash 层拒绝跨 row 写入或正确拆分不产生越界。对齐与尾包制造非 8 字节地址、非完整 64-bit 尾部按镜像格式缓冲/填充非法地址被拒绝。擦除/写入掉电对每个 sector、row 的关键操作点断电旧 active_slot 仍可启动未完成目标槽不被选择。状态记录掉电在另一有效副本的前提下对 inactive 4 KB sector 的擦除、payload、回读、独立 64-bit commit 间断电启动器选择 CRCcommit 有效的另一份记录。读写并发闭包擦/写 block 时触发可达常量访问、异常或中断完整执行路径在另一 block 或 RAM不得仅验证 Flash driver 在 RAM。Pending 失败候选镜像看门狗复位或不确认超出策略后自动回滚至确认槽。错误状态由测试桩模拟 OPERR/WPERR/ECC 错误记录失败原因、清理状态不提交 pending_slot。安全验证篡改摘要、签名或版本号认证失败不切换启动意图保留已确认镜像。9. 结语AS32S601 的 sector、row、64-bit 编程和跨 block 读写限制决定了 OTA 不应只被实现为一个网络下载任务。把非活动槽写入、镜像校验、双份状态、Pending 试启动和应用确认串成一个原子性逐步增强的流程设备就能在升级失败和断电场景下保留可启动路径。落地前请以实际芯片容量、当前版本手册、BSP 和链接脚本为最终依据完成地址规划与底层寄存器实现。
返回列表