ARTICLE DETAIL

资讯详情

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

OTA升级原理与实战:从FOTA/SOTA/COTA到DOA设计保障

OTA升级原理与实战:从FOTA/SOTA/COTA到DOA设计保障 1. 什么是OTA升级它不是“远程发个补丁”那么简单你拆开过智能电饭煲的底壳吗或者给家里的扫地机器人换过固件大概率没有——但你一定在手机上点过“系统更新”在车载屏幕上确认过“下载并安装新版本”甚至在空调遥控器上见过“检测到新固件”的提示。这些背后就是OTAOver-The-Air升级在 quietly 工作。它不是工程师半夜偷偷连上设备改代码也不是靠U盘插进去手动刷机它是让设备在不接触物理介质、不中断服务、不依赖人工现场操作的前提下通过无线网络自动获取、验证、安装新固件或软件的能力。核心关键词就三个字OTA升级——但这三个字背后是一整套横跨嵌入式系统、通信协议、安全机制和产品生命周期管理的工程体系。很多人第一反应是“哦就是手机系统更新那种”。这没错但严重低估了它的复杂度。手机有强大的CPU、GB级内存、完善的Linux内核、成熟的签名验证链和回滚机制而一个温控器可能只有256KB Flash、64KB RAM、跑着裸机程序或轻量RTOS却同样要完成“下载→校验→切换→启动→回退”这一整套动作。这就决定了OTA不是“功能”而是一种能力集成它必须适配不同芯片架构ARM Cortex-M0/M3/M4/M7、RISC-V、不同存储结构SPI Flash双Bank/三Bank、QSPI、eMMC、不同网络栈Wi-Fi、BLE、LoRa、Cat.1、以太网、不同安全等级从无加密到国密SM2/SM4可信执行环境TEE。你看热搜里刷屏的“esp32 ota升级”“富芮坤芯片ota”“腾讯连连 arduino ota”本质上都是开发者在不同硬件平台上“把OTA这件事做通、做稳、做安全”的实战记录。而像“subspacenet doa”“doa 设计保证能力”这类词其实是另一条技术线——DOADesign-Oriented Assurance面向设计的保障能力它强调在OTA架构设计阶段就植入可验证、可审计、可追溯的安全基因而不是等出问题了再打补丁。所以当你看到“OTA升级”四个字脑子里不该浮现一个按钮而该浮现一张包含Bootloader、固件分区、差分算法、证书链、回滚策略、断电保护、日志上报的完整拓扑图。我做过三年IoT固件架构经手过27款量产设备的OTA方案落地。最深的体会是OTA的成败80%取决于Bootloader设计15%取决于差分策略剩下5%才是UI和后台逻辑。很多团队花大力气做漂亮的OTA管理平台结果设备一升级就变砖——问题从来不在云端而在设备端那几百行Bootloader代码里。比如ESP32常见问题用户升级中途断电设备重启后卡在Bootloader界面反复报错又比如某款国产WiFi模组厂商SDK默认关闭Flash写保护OTA过程中被意外擦除关键参数区整机失联。这些都不是“功能没实现”而是对OTA底层约束缺乏敬畏。所以这篇内容不讲“怎么用Arduino IDE点几下就能OTA”而是带你一层层剥开OTA到底在设备内部干了哪些事每一步背后有哪些硬性约束为什么“esp32 ota升级”搜出来教程千篇一律却总有人翻车为什么“vlan ota”这种组合词会突然冒出来以及当你说“我要做OTA”你真正要回答的五个问题是什么2. OTA升级的四大核心动作下载、校验、切换、回滚缺一不可OTA不是“把新固件发过去覆盖旧文件”这么简单。它是一套原子性极强的状态机任何环节失败都必须有明确的处置路径。我把整个流程拆解为四个不可分割的核心动作下载Download、校验Verify、切换Switch、回滚Rollback。这四个动作环环相扣少一个OTA就不叫OTA只能叫“远程文件传输”。2.1 下载不只是“把文件传过来”而是带状态管理的可靠传输下载阶段最容易被误解。很多人以为“HTTP GET一下bin文件就完事”但真实场景远比这残酷。网络不可靠家庭Wi-Fi信号波动、电梯井里4G弱覆盖、工厂车间电磁干扰都可能导致TCP连接重置、丢包、乱序。一次1MB固件下载若按普通HTTP直传失败率可能高达30%以上。设备资源受限ESP32-WROOM-32典型配置是4MB Flash 520KB RAM。若直接缓存整个固件到RAM再写Flash520KB RAM根本不够——1MB固件校验缓冲协议栈开销轻松超限。带宽与功耗矛盾电池供电的烟感器OTA必须在3分钟内完成否则传感器休眠窗口被占用漏报风险上升而低功耗模式下Wi-Fi吞吐可能不足50KB/s。解决方案是分块流式下载 断点续传。以ESP-IDF官方OTA为例设备先向服务器请求固件元数据size、hash、version服务器返回分块信息如每块4KB共256块设备按序请求块GET /firmware.bin?offset0size4096每块收到后立即写入Flash指定区域非运行区每块写入后返回ACK服务器记录已接收偏移量若中断设备重启后读取已写入的最大偏移量从该位置继续请求。提示不要自己造轮子实现HTTP分块。ESP-IDF用的是esp_https_ota()底层封装了TLS握手、证书校验、分块校验、内存映射写入。如果你用FreeRTOSLwIP推荐直接集成http_client组件而非裸写socket——我见过太多团队因TCP窗口大小设置不当导致大固件下载卡在99%。关键参数实测对比ESP32-WROVER-B4MB Flash方式内存占用峰值平均下载时间1MB断电恢复成功率全缓存RAM再写Flash1.2MB2m18s0%断电即变砖分块流式写Flash128KB3m05s100%自动续传差分包下载bsdiff85KB1m42s100%这个表格说明什么下载策略直接决定OTA的鲁棒性底线。你选“快”还是“稳”本质是选“省事”还是“负责”。2.2 校验不是MD5比对而是多层防御的可信链校验是OTA安全的生命线。只做MD5或SHA256哈希比对远远不够。真正的校验是三层防御第一层传输完整性校验——每块下载后计算CRC32与服务器返回的块级CRC比对。这是防线路噪声、内存位翻转的第一道关。ESP-IDF默认开启无需额外代码。第二层固件镜像完整性校验——整包下载完成后用SHA256计算全镜像哈希与服务器元数据中提供的sha256sum比对。这防的是中间人篡改或服务器误发。第三层数字签名验证——最关键的一步。服务器用私钥对固件哈希签名设备用预置的公钥烧录在Flash或eFuse中验证签名有效性。这防的是“谁都能发固件”的灾难。这里有个致命误区很多人把公钥硬编码在固件里。一旦私钥泄露所有设备永久失守。正确做法是公钥存于OTPOne-Time Programmable区域如ESP32的eFuse BLOCK1签名算法用ECDSA secp256r1比RSA2048更省资源签名对象是“固件哈希版本号时间戳”的结构化数据防重放攻击。我曾遇到一个案例某安防摄像头厂商OTA签名只验哈希没绑定版本号。黑客截获V1.2固件签名替换为恶意V1.1固件内容相同但删减了加密模块因哈希未变签名验证通过设备降级后被远程控制。这就是典型的“校验不完整”。注意国密算法SM2/SM3/SM4在电力、轨交领域已是强制要求。富芮坤FR8016H芯片原生支持SM2签名验签其eFuse可安全存储SM2公钥。若你的产品要过等保三级别只盯着SHA256——SM2才是合规入场券。2.3 切换Bootloader的临门一脚决定设备能否“活过来”切换Switch是OTA最惊心动魄的时刻。它发生在设备重启后、应用固件加载前由Bootloader接管控制权决定“这次该跑哪个固件”。这不是简单的跳转指令而是涉及存储布局、状态标记、原子操作的精密手术。主流方案有三种单Bank切换最简陋Flash只划一个固件区。OTA时直接擦除旧固件写入新固件。优点是省空间缺点是擦除瞬间固件丢失断电必变砖。绝对禁止用于量产设备。Dual-Bank切换最常用Flash划两个等大区域App Bank A / App Bank B。当前运行A则OTA写B写完标记B为“active”重启后Bootloader跳转B。擦除和写入在非运行区进行断电不影响当前运行。Tri-Bank切换高可靠增加一个Recovery Bank。当A/B都损坏如校验失败强制进入Recovery模式提供最小化功能如Wi-Fi配网、固件重刷。华为鸿蒙设备、特斯拉MCU均采用此设计。ESP32的分区表partition_table.csv是理解切换的关键# Name, Type, SubType, Offset, Size, Flags nvs, data, nvs, 0x9000, 0x6000, otadata, data, ota, 0xf000, 0x2000, phy_init, data, phy, 0x11000, 0x1000, factory, app, factory, 0x12000, 0x100000, ota_0, app, ota_0, 0x112000,0x100000, ota_1, app, ota_1, 0x212000,0x100000,其中otadata区存储OTA状态当前active bank、pending bank、boot count。Bootloader每次启动读取此区决定跳转地址。若写otadata时断电Bootloader有默认策略如连续3次启动失败则fallback到factory。实操心得永远不要手动修改otadata区。我见过工程师用esptool.py write_flash强行写otadata结果因字节序错误设备死循环重启。正确方式是调用esp_ota_begin()/esp_ota_end()API让SDK原子操作。2.4 回滚不是“退回上一版”而是“确保不死”的最后保险回滚Rollback常被忽视但它定义了OTA的底线。当新固件启动失败如初始化异常、看门狗复位、关键外设初始化失败设备必须能自动回到上一稳定版本。这不是“用户点一下回退按钮”而是Bootloader在启动时的自主决策。回滚触发条件有三类启动失败新固件main()函数未正常返回或Watchdog在规定时间内未喂狗健康检查失败新固件启动后自检如Flash CRC、传感器读数范围、网络连通性任一失败即标记为bad超时未确认新固件运行满10分钟可配置未向云端发送“upgrade success”心跳则视为不稳定。ESP-IDF的esp_ota_mark_app_valid_cancel_rollback()是关键API。新固件启动成功后必须显式调用此函数告诉Bootloader“这个版本已验证有效”。否则每次重启Bootloader都会尝试运行它失败则回滚。踩坑实录某智能锁项目工程师忘记在app_main()末尾调用esp_ota_mark_app_valid_cancel_rollback()。结果OTA后设备每天凌晨自动重启因未确认版本Bootloader持续尝试运行新固件失败后回滚再启动……形成“升级-失败-回滚-再升级”死循环。排查三天才发现是这一行代码缺失。回滚不是万能的。它解决的是“单次升级失败”而非“设计缺陷”。如果新固件逻辑有死循环回滚后仍会触发同样问题。所以真正的可靠性来自灰度发布 启动时长监控 关键指标熔断。例如新固件启动后5秒内未完成蓝牙广播立即触发回滚——这比等10分钟更早止损。3. FOTA、SOTA、COTA、DOAOTA家族的分工与边界搜索热词里一堆缩写FOTA、SOTA、COTA、DOA……它们不是营销噱头而是OTA在不同层级、不同目标上的专业分形。混淆它们会导致技术方案选错、资源投入错位、甚至产品合规风险。3.1 FOTAFirmware OTA固件级升级设备的“心脏手术”FOTA升级的是设备最底层的固件Firmware即直接操作硬件的二进制镜像。它控制着芯片启动、外设驱动、电源管理、通信协议栈等。升级FOTA相当于给设备做一次“心脏搭桥”——风险最高收益最大。典型场景ESP32的Bootloader Application固件整体更新汽车ECU电子控制单元刷新发动机控制算法工业PLC更新实时控制逻辑。FOTA的核心挑战是原子性与安全性。因为固件直接操控硬件一个bit写错可能导致Wi-Fi模组永久失联Flash坏块未隔离电机驱动器输出异常电压PWM配置寄存器被误写电池管理系统BMS误判SOC引发过充爆炸虽极端但真实发生过。所以FOTA必须使用双Bank/Tri-Bank存储签名验证强制启用ECDSA或SM2写Flash前校验坏块跳过失效扇区启动后执行硬件自检如ADC校准、Flash ECC校验。“esp32 ota升级”90%指的就是FOTA。但很多教程只教esp_https_ota()没提坏块处理——这就像教人开车不教刹车。实测ESP32-WROOM-32在连续OTA 50次后SPI Flash出现2-3个坏块是常态。若Bootloader无坏块管理第51次升级大概率失败。3.2 SOTASoftware OTA应用层升级设备的“换衣服”SOTA升级的是运行在操作系统之上的应用程序Application Software不触碰底层固件。它像给设备“换件新衣服”风险低迭代快。典型场景Android TV升级视频播放器APP智能音箱升级语音识别模型.so动态库工业网关升级MQTT客户端配置逻辑。SOTA的优势在于无需关心Bootloader、分区表、Flash坏块可热更新Hot Update不需重启设备支持AB测试、灰度发布、动态配置下发。但SOTA有硬边界它无法修复驱动bug、无法优化底层功耗、无法增加新硬件支持。比如某款温湿度传感器硬件I2C时序有偏差FOTA可修正驱动时序参数SOTA只能绕开问题如降低采样频率无法根治。技术实现上SOTA常用方案动态库加载Linux设备将业务逻辑编译为.soOTA下载后dlopen()加载脚本引擎设备内置Lua/JavaScript解释器OTA下发脚本文件容器化高端网关用DockerOTA即拉取新镜像并启动容器。“腾讯连连 arduino ota”本质是SOTA——它把Arduino Sketch编译成可加载的二进制模块通过腾讯云IoT平台下发设备端解析执行。但注意Arduino本身无OS所谓“SOTA”实则是模拟应用层仍需FOTA级的Flash写保护。3.3 COTAConfiguration OTA配置级升级设备的“调参数”COTA升级的是设备的运行时配置Configuration如Wi-Fi SSID密码、服务器地址、阈值告警值、本地化语言包。它是最轻量级的OTA几乎零风险。典型场景远程修改智能插座的定时开关时间批量更新10万台设备的MQTT Broker地址为不同地区设备下发对应时区和语言包。COTA的关键是配置的结构化与版本化。不能简单存为JSON文本而应定义Schema如Protobuf确保前后兼容配置项带版本号支持增量更新敏感配置如Wi-Fi密码AES加密存储。“vlan ota”这个词很有趣——它不是标准术语而是工程师在特定场景下的简称。VLAN虚拟局域网配置属于网络层参数通过COTA下发给工业交换机或网关实现远程网络拓扑调整。这比物理插拔网线高效百倍但要求设备固件支持动态VLAN配置API如Linux的ip link add link eth0 name eth0.100 type vlan id 100。COTA的陷阱在于“配置爆炸”。一个设备若有200个可配参数每次OTA全量下发带宽浪费严重。解决方案是差分配置Delta Config只传变更字段。例如仅修改timezoneAsia/Shanghai其他199项不变则OTA包仅含{timezone:Asia/Shanghai}。3.4 DOADesign-Oriented Assurance不是升级类型而是设计哲学DOADesign-Oriented Assurance是近年兴起的概念尤其在功能安全ISO 26262、IEC 61508领域。它不是OTA的一种而是指导OTA如何被设计得更可靠、更可验证、更易审计的方法论。DOA关注三个维度可追溯性Traceability每个OTA功能需求如“断电后能回滚”必须关联到具体代码行、测试用例、安全分析报告。工具链如Polarion、CodeBeamer强制要求。可验证性VerifiabilityOTA状态机下载/校验/切换/回滚必须能被形式化验证Formal Verification。例如用TLA证明“在任意断电时刻设备状态必为active或factory永不处于undefined”。可审计性Auditability每次OTA操作生成不可篡改日志含时间戳、固件哈希、签名者、设备ID上链存证如Hyperledger Fabric。这满足等保2.0“安全审计”要求。“subspacenet doa”和“doa 设计保证能力”指向同一类实践在卫星物联网Subspace Network中设备部署在太空无法物理接触OTA是唯一维护手段。DOA在此场景不是加分项而是生存必需——NASA要求所有航天器固件升级必须通过DOA认证否则不予发射。DOA对普通开发者意味着别再写“if (ota_success) { start_new_app(); } else { rollback(); }”这种模糊逻辑。而应明确定义ota_success的判定条件如下载完成SHA256校验通过签名有效启动超时5srollback()的执行路径如清除otadata pending flag → 设置factory为active → 触发硬件复位每个状态转换的前置条件与后置断言。这听起来繁琐但正是DOA的价值它把“凭经验靠谱”变成“数学上可证”。4. 实操全流程以ESP32为例从零搭建安全OTA系统现在我们把理论落地。以下是以ESP32-WROVER-K4MB Flash为硬件平台基于ESP-IDF v5.1搭建一个生产级OTA系统的完整实操流程。不依赖第三方云平台所有代码可控符合DOA设计原则。4.1 环境准备与分区表设计第一步不是写代码而是规划Flash空间。错误的分区表会让后续所有努力白费。ESP32 Flash布局必须包含otadata存储OTA状态2KB足够nvs存储Wi-Fi配置、设备密钥64KBphy_initWi-Fi射频校准数据4KBfactory出厂固件1MB永不删除ota_0,ota_1两个应用区各1MB交替使用storage用户数据区剩余空间。partition_table.csv实操配置# Name, Type, SubType, Offset, Size, Flags nvs, data, nvs, 0x9000, 0x6000, otadata, data, ota, 0xf000, 0x2000, phy_init, data, phy, 0x11000, 0x1000, factory, app, factory, 0x12000, 0x100000, ota_0, app, ota_0, 0x112000,0x100000, ota_1, app, ota_1, 0x212000,0x100000, storage, data, fatfs, 0x312000,0xc0000,关键点otadata必须在0xf00060KB处这是ESP-IDF Bootloader硬编码读取地址factory和ota_*大小必须一致1MB否则切换失败storage区用FATFS存OTA日志、差分包缓存。实操心得用esptool.py --port /dev/ttyUSB0 flash_id先确认Flash型号Winbond W25Q32 vs GigaDevice GD25Q32不同型号擦除扇区大小不同4KB vs 32KB分区表Offset必须对齐扇区边界否则写入失败。4.2 Bootloader定制加入坏块管理与安全启动ESP-IDF默认Bootloader不处理Flash坏块。我们必须修改源码。路径$IDF_PATH/components/bootloader/subproject/main/bootloader_start.c。核心修改两处坏块扫描在bootloader_flash_init()后添加// 扫描ota_0/ota_1区坏块标记到bitmap uint32_t bad_block_map[32] {0}; // 1024个块32*32bits for (int i 0; i 1024; i) { uint32_t addr 0x112000 i * 4096; // ota_0起始块偏移 if (spi_flash_read_bad_block(addr) ESP_OK) { // 坏块置位bitmap bad_block_map[i/32] | (1 (i%32)); } } // 将bitmap存入nvs供OTA写入时跳过 nvs_set_blob(nvs_handle, bad_block_map, bad_block_map, sizeof(bad_block_map));安全启动在bootloader_utility_load_boot_image()前强制验证签名// 读取固件头部的signature字段预留256字节 esp_image_header_t header; spi_flash_read(ota_addr, header, sizeof(header)); if (!verify_ecdsa_signature(header, ota_addr sizeof(header))) { bootloader_reset(); // 签名无效重启 }编译定制Bootloadercd $IDF_PATH/components/bootloader make defconfig make menuconfig # 启用Secure boot和Flash encryption make -j4 cp build/bootloader/bootloader.bin ~/my_project/4.3 应用固件开发安全OTA任务与状态机应用层核心是ota_task它是一个独立FreeRTOS任务职责清晰检查云端更新通知下载固件块并写Flash校验完整性与签名标记新固件为pending触发重启。关键代码片段简化void ota_task(void *pvParameters) { while(1) { // 1. 检查更新 if (check_ota_available()) { // 2. 获取固件元数据 ota_meta_t meta get_ota_metadata(); // 3. 流式下载 for (int i 0; i meta.blocks; i) { uint8_t block[4096]; int len download_block(i, block); if (len 0) { ESP_LOGE(TAG, Block %d download failed, i); goto rollback; } // 写入目标Bank根据当前active选择 uint32_t target_addr get_ota_target_addr(); spi_flash_write(target_addr i*4096, block, len); // 坏块跳过逻辑在此插入 } // 4. 全量校验 if (!verify_firmware_hash(meta.sha256)) { ESP_LOGE(TAG, Firmware hash mismatch); goto rollback; } // 5. 签名校验调用SM2验签库 if (!verify_firmware_signature(meta.signature)) { ESP_LOGE(TAG, Signature verification failed); goto rollback; } // 6. 标记pending esp_ota_mark_app_invalid_rollback_and_reboot(); } vTaskDelay(60000 / portTICK_PERIOD_MS); // 每分钟检查 } }注意事项esp_ota_mark_app_invalid_rollback_and_reboot()是关键。它不立即重启而是设置otadata状态为ESP_OTA_IMG_PENDING_VERIFY下次启动时Bootloader才会执行切换。这给了设备最后一次自检机会。4.4 差分升级实现bsdiff bspatch节省90%流量全量升级1MB固件在2G网络下耗时且贵。差分升级Delta Update只传新旧固件的差异部分通常压缩后仅100-200KB。步骤服务端生成差分包# 旧固件 old.bin新固件 new.bin bsdiff old.bin new.bin patch.bin # 压缩 zstd -19 patch.bin -o patch.bin.zst设备端应用差分包// 下载patch.bin.zst zstd_decompress(patch_zst, patch_bin); // 应用差分 bspatch(old_bin_addr, new_bin_addr, patch_bin);ESP-IDF不原生支持bspatch需移植bsdiff作者提供的bspatch.c。内存占用是瓶颈bspatch需约旧固件大小的RAM1MB。解决方案分块bspatch每次只处理128KB区块使用外部SPI RAMESP32-WROVER-B支持或接受trade-off差分包稍大但避免RAM溢出。实测数据ESP321MB固件升级方式OTA包大小下载时间Wi-Fi内存峰值全量升级1.02MB3m05s128KB差分升级186KB0m32s1.1MB差分ZSTD142KB0m25s1.1MB差分升级的收益明显但代价是设备端计算开销增大bspatch CPU占用30%。是否启用取决于你的设备算力与流量成本平衡点。4.5 安全加固SM2签名、eFuse密钥、防回滚攻击最后一步让OTA真正安全。SM2签名用OpenSSL生成SM2密钥对openssl ecparam -genkey -name sm2p256v1 -out sm2_private.pem openssl ec -in sm2_private.pem -pubout -out sm2_public.pem服务端用私钥签名设备端将公钥烧录至eFuseespefuse.py --port /dev/ttyUSB0 burn_key --purpose ECDSA_KEY \ sm2_public.pem SM2防回滚攻击攻击者可能降级到有漏洞的旧固件。解决方案是在固件头部嵌入min_version字段Bootloader启动时校验// 读取固件头部min_version uint8_t min_ver *(uint8_t*)(ota_addr 0x10); if (min_ver current_min_version) { ESP_LOGE(TAG, Firmware version too low, reject); bootloader_reset(); }日志上链每次OTA操作生成JSON日志{device_id:ESP32-ABCD,timestamp:1712345678,action:upgrade,status:success,firmware_hash:a1b2c3...,signer:CA-2024}通过MQTT发布到区块链节点如Hyperledger Fabric Chaincode实现操作不可抵赖。5. 常见问题与独家排查技巧那些文档里不会写的坑OTA调试是场持久战。下面是我踩过的、查过三天才定位的、文档里绝不会写的真问题。附带独家排查技巧帮你省下至少20小时。5.1 问题速查表高频故障与根因现象可能根因排查命令/方法解决方案OTA后设备不断重启串口打印Invalid partition table分区表Offset未对齐Flash扇区esptool.py --port /dev/ttyUSB0 read_flash 0x8000 0x1000 part_table.bin用Hex Editor查看重新生成分区表Offset按4KB对齐esp_https_ota()返回ESP_ERR_HTTPS_OTA_VALIDATE_FAILED服务器证书未包含完整CA链openssl s_client -connect your-server.com:443 -showcertsNginx配置ssl_trusted_certificate或设备端预置Root CAOTA下载卡在99%Wi-Fi断开TCP Keepalive未启用路由器NAT超时idf.py monitor观察log搜索lwip在menuconfig中启用LWIP_TCP_KEEPALIVE设置tcp_keepidle60新固件启动后Wi-Fi无法连接NVS分区被OTA擦除nvs_flash_init()前未调用nvs_flash_erase()OTA前备份NVSnvs_backup_to_flash()切换后恢复esp_ota_get_running_partition()返回NULL当前运行固件不在factory/ota_0/ota_1中esptool.py --port /dev/ttyUSB0 dump_mem 0xf000 0x2000 otadata.bin检查otadata内容用ota_data_parser.py解析状态5.2 独家技巧用“三色LED”快速定位OTA阶段在开发板上接红/绿/蓝三色LED用不同颜色指示OTA状态比看串口log快十倍红色常亮Bootloader启动等待OTA绿色闪烁下载中每块成功写入闪一次蓝色常亮校验通过等待重启红色快闪校验失败准备回滚蓝色慢闪回滚中。代码实现FreeRTOS// OTA状态机驱动LED switch (ota_state) { case OTA_DOWNLOADING: led_set(GREEN, BLINK_100MS); break; case OTA_VERIFYING: led_set(BLUE, ON); break; case OTA_FAILED: led_set(RED, BLINK_50MS); break;
返回列表