IC:

概述

OTA (空中下载技术)升级机制允许设备在固件正常运行时,通过 Wi-Fi、SPI、UART 以及文件系统等方式, 根据接收到的数据进行自我更新,可及时升级设备功能与性能。

使用 OTA 之前请先参考 Flash 布局 章节了解更多分区相关细节。

固件分区

Flash 布局 中 BOOT 和 APP 固件均有两个固件分区( OTA1 和 OTA2 )用于冗余存储和版本控制。

用户需要根据实际的固件大小以及合理的预留空间来设置这些分区的大小。

备注

BOOT 固件的 OTA 功能默认关闭,如需使用,请参考 BOOT OTA

固件标签和版本号

在 OTA1/OTA2 之间的启动选择主要依赖于固件头中的的标签和版本号。如下图所示,固件头中包含 8 字节的标签, 2 字节的主版本号和 2 字节的次版本号。

../../rst_rtos/1_ota/figures/major_and_minor_version_cn.svg

对于固件标签和版本号的详细描述如下:

项目

描述

OTA 选择流程

固件标签

  • 一个固定的 8 字节长度的数据

  • BOOT 固件和 APP 固件分别有各自的固件标签

检查固件标签的有效性

版本号

  • 主版本号和次版本号的组合,计算方式如下:

    \[\text{版本号} = (\text{主版本号} \ll 16) \, | \, \text{次版本号}\]
  • BOOT 固件和 APP 固件分别有各自的版本号

比较版本号的大小

每次启动, 启动程序中会检查固件标签的有效性和比较版本号大小,以决定从 OTA1 或 OTA2 启动。 固件标签和版本一致性确保了可靠的启动,每个固件必须检查以下项目:

  1. 检查 OTA1 和 OTA2 的固件标签是否有效。

    • 如果只有一个固件标签有效,则从有效的固件启动。

    • 如果两个固件标签都无效,则启动失败。

  2. 比较 OTA1 和 OTA2 的版本号。

    • 如果 OTA1 和 OTA2 的版本号都有效且版本号不同,设备将从版本号更大的固件启动。

    • 如果 OTA1 和 OTA2 的版本号都有效但版本号相同,设备将从 OTA1 启动。

../../rst_rtos/1_ota/figures/ota_select_diagram_cn.svg

基于上述的启动流程, OTA 支持以下两种方式在下次启动时切换到新的固件:

在新固件中设置一个更高的版本号,OTA 完成后下次启动将会从新固件启动。该方式需要在每次升级时都修改增加新固件的版本号。

在项目文件夹 {SDK}/amebaxxx_gcc_project 中配置文件 manifest.json 中修改新固件的版本号。

  1. 为 BOOT 固件配置版本号,版本号范围为 0 到 32767 。

    "boot":
    {
       "IMG_ID": "0",
       "IMG_VER_MAJOR": 1,
       "IMG_VER_MINOR": 1,
       ...
    },
    
  2. 为 APP 固件配置版本号,版本号范围为 0 到 65535。

    "app":
    {
       "IMG_ID": "1",
       "IMG_VER_MAJOR": 1,
       "IMG_VER_MINOR": 1,
       ...
    },
    

防回滚功能

防回滚功能用于防止回滚到主版本号低于 OTP 中设置的版本号的固件版本。当启用防回滚功能时,固件头中的主版本号不能小于 OTP 中设置的防回滚版本号, 否则固件将被视为无效。

通常,如果此次 OTA 更新解决了此前的版本的安全性问题,用户可以在更新完成之后将防回滚版本号设置为此次更新的版本号,以防止回滚到低于此版本的固件版本。

防回滚流程如下所示:

  1. 分别比较从 OTA1 和 OTA2 固件头获取的主版本号与 OTP 中的防回滚版本号的大小。

  2. 如果固件的主版本号小于防回滚版本号,该固件将被视为无效。

../../rst_rtos/1_ota/figures/anti_rollback_flow_cn.svg

用户可以通过以下步骤启用防回滚功能:

  1. 更改 OTP 中的防回滚版本号。

    • OTP 的物理地址范围为 0x36E ~ 0x36F。

    • OTP 中的值的比特 0 的数量表示防回滚版本号。OTP 默认值为 FFFF ,则表示默认的防回滚版本号为 0。

    • 由于 OTP 物理地址只能从 1 写 0 ,地址范围最多 16 位,所以只支持 16 个防回滚版本号。

    通过以下命令读出当前的防回滚版本号:

    EFUSE rraw 36E 2
    

    通过以下命令设置防回滚版本号:

    EFUSE wraw 36E 2 xxxx
    

    其中 xxxx 为需要设置的版本号,举例说明:

    • 例 1 :写 FFFC 或 FFCF ,都是有 2 个比特被置位 0 ,则 OTP 中的版本号就是 2。表示主版本号小于 2 的固件都被禁止启动。

    • 例 2 :写 FFF0 或 0FFF ,都是有 4 个比特被置位 0 ,则 OTP 中的版本号就是 4。表示主版本号小于 4 的固件都被禁止启动。

  2. 启用防回滚功能。

    通过以下命令读出当前值:

    EFUSE rraw 368 1
    

    将读出来的值比特 6 置 0 后再写入,比如读出来为 FF ,则写入:

    EFUSE wraw 368 1 BF
    

默认情况下, BOOT 固件和 APP 固件均使用同一个防回滚版本号,即从 OTP 中读取。

如果 BOOT 固件和 APP 固件需要使用不相同的防回滚版本号,修改 bootloader\boot_ota_km4.cbootloader\boot_ota_hp.c 中 的函数 BOOT_OTA_GetCertRollbackVer() ,为 APP 固件自定义一个其他获取防回滚版本号的方式。

备注

  • 启用防回滚功能之后,需要修改防回滚版本号,防回滚才真正生效。

  • 如果需要防回滚功能,建议在出厂的时候启用防回滚但不设置版本号,在 OTA 之后选择性写入防回滚版本号。

  • 在应用中修改防回滚版本号,请参考 OTP API 参考 中接口的用法,在代码中实现。

  • 一旦启用防回滚,就无法禁用。

BOOT OTA

默认情况, BOOT OTA 并未启用,用户可通过以下步骤使能 BOOT OTA:

  1. 参考 配置 SDK (menuconfig) 进入 CONFIG OTA OPTION 配置,勾选 Enable Bootloader OTA ,此步骤会在编译过程中将 BOOT 固件集成到 ota_all.bin 中。

  2. Flash 布局 中规划和修改 BOOT OTA2 的分区范围,请保证 4K 对齐。

  3. 将 BOOT OTA2 分区的起始地址写入 OTP

    EFUSE wraw 36C 2 IMG_BOOT_OTA2
    

    BOOT OTA2 地址写入 OTP 中的值的计算公式如下:

    \[\text{写入 OTP 的值} = ((\text{IMG_BOOT_OTA2} \gg 12) \& FF) \ll 8 \mid ((\text{IMG_BOOT_OTA2} \gg 20) \& FF )\]

    例如, IMG_BOOT_OTA2 为 0x08234000 ,则写入 OTP 的命令为:

    EFUSE wraw 36C 2 3482
    

    小心

    • OTP 区域无法重复写入,请确保在开发阶段或者批量生产时提前写入

    • 如果 OTP 中的 BOOT OTA2 的地址为 0xFFFF ,则在 OTA 期间不会进行 BOOT 固件升级,设备总是从 BOOT OTA1 启动。

BOOT OTA 选择流程

芯片 ROM 中的引导程序根据 BOOT 固件头中的标签和版本号选择启动哪个分区,流程如下图所示。

../../rst_rtos/1_ota/figures/km4_bootloader_ota_select_flow_cn.svg

APP OTA

APP 固件支持 OTA 更新,并能够从 OTA1 或 OTA2 启动。默认启用 APP OTA。

备注

对于 RTL8726E 和 RTL8713E,还需要加载 DSP 固件,关于 DSP 固件的更多细节请参考 DSP 固件

APP OTA 选择流程

BOOT 固件运行时会根据 APP 固件的版本号和标签选择启动分区,选择流程如下图所示:

../../rst_rtos/1_ota/figures/application_image_ota_select_flow_cn.svg

OTA 压缩方案

当启用 OTA 固件压缩功能时, APP OTA1 分区保持不变,而 APP OTA2 分区的固件将被压缩,从而减小固件的大小,这可以有效节省 Flash 空间。

压缩算法采用 LZMA(Lempel-Ziv-Markov 链算法),这种无损数据压缩算法以高压缩比和相对较低的解压内存需求著称,并广泛应用于 .7z 格式的文件压缩和 7-Zip 软件中。

压缩效率可使用压缩率来衡量。压缩率的计算公式如下:

\[\text{压缩率(%)} = \left( \frac{\text{压缩后固件大小}}{\text{原始固件大小}} \right) \times 100\]

压缩率受到固件内容的影响:原始固件内容越复杂,压缩率往往越高(通常为 50% ~ 70%)。

启用 OTA 压缩功能后的启动流程具有以下特点:

  1. 版本号和标签的判断与普通流程一致。

  2. 只有 APP 固件支持压缩方案。

  3. 压缩固件在 OTA 过程中将始终被下载到 OTA2 区域。

  4. 如果判断需要从 OTA2 的压缩固件启动, BOOT 流程会进行解压缩并且覆盖 OTA1 区域。

  5. 支持 OTA 过程和启动时解压过程的掉电保护。

  6. 压缩固件只需要在下载完成后首次启动时解压一次,之后启动将不再解压。

../../rst_rtos/1_ota/figures/compress_image_ota_select_flow_cn.svg

通过以下图片给出示例:

  1. 设备从 OTA1 启动并运行 OTA 应用。

  2. 压缩固件被下载到 OTA2。

  3. 下一次启动时,系统将选择压缩固件,将其解压到 OTA1 ,然后继续从 OTA1 启动。

../../rst_rtos/1_ota/figures/compress_ota_select_diagram_cn.svg

用户可通过以下步骤打开 OTA 压缩方案:

  1. 参考 配置 SDK (menuconfig) 进入 CONFIG OTA OPTION 配置,勾选 Enable Compress APP Image 来启用 OTA 固件压缩功能。

  2. 编译项目时, APP 固件被压缩后生成压缩固件 {SDK}\amebaxxx_gcc_project\project_xx\asdk\image\xxx_app_compress.bin,同时生成压缩后的 ota_all.bin 以供用户 OTA 使用。

  3. 烧录 {SDK}\amebaxxx_gcc_project\xxx_bool_all.bin 到 BOOT OTA1 区域,并烧录压缩固件 {SDK}\amebaxxx_gcc_project\project_xx\asdk\image\xxx_app_compress.bin 到 APP OTA2 区域,验证压缩固件解压过程。

备注

  • 首次启用 OTA 压缩方案必须更新 BOOT ,需要重新烧录 BOOT 固件。

  • 如果启用了 OTA 压缩方案, APP OTA2 区会被设置的更小,已经不再适合放未压缩的应用固件。因此在量产阶段推荐使用 进阶用法

OTA 固件

OTA 固件格式

ota_all.bin 的文件格式如下图所示,其中 OTA 固件头部分为主头部和子头部,主头部包含版本号和子头部的数量,子头部包含升级固件的信息。 每增加一个升级固件,便增加对应的一个子头部。

../../rst_rtos/1_ota/figures/firmware_format_cn.svg
OTA 固件头部

项目

地址偏移

大小

描述

版本号

0x00

4 字节

OTA 固件主头部中的版本号,默认值是 0xFFFFFFFF

数量

0x04

4 字节

OTA 固件子头部的数量,值为 1 或 2

标签

0x08

4 字节

OTA 固件子头部的标签,值为 OTA

长度

0x0C

4 字节

OTA 固件子头部的长度,值为 0x18

校验和

0x10

4 字节

对应升级固件的校验和

固件长度

0x14

4 字节

对应升级固件的长度

固件偏移量

0x18

4 字节

在当前 OTA 固件中此升级固件的起始位置

固件 ID

0x1C

4 字节

对应升级固件的固件 ID

  • OTA_IMGID_BOOT:0x0

  • OTA_IMGID_APP:0x1

修改编译配置

  1. 参考 固件标签和版本号 调整版本号或者切换方案。

  2. 调整 BOOT 固件的防回滚版本号,并在必要时启用防回滚,启用步骤请参考 防回滚功能

  3. 如果用户需要升级 BOOT 固件,启用步骤请参考 BOOT OTA

  4. 如果需要启用 OTA 压缩功能,请按照 OTA 压缩方案 中的步骤进行操作。

生成 OTA 固件

在编译项目时, OTA 固件将自动生成。

  1. OTA 固件内将包括如下内容

  2. 编译项目。OTA 固件 ( ota_all.bin ) 将生成在 {SDK}\amebaxxx_gcc_project 目录下。

从无线网络更新

本节介绍通过无线网络服务器进行 OTA 的设计原则和用法。它具有良好的可移植性,便于用户移植到自己的 OTA 应用固件中。

网络服务器 OTA 显示设备如何从网络下载服务器升级固件。网络下载服务器基于网络套接字将固件发送给设备,如下图所示:

../../rst_rtos/1_ota/figures/ota_update_diagram_via_network_cn.svg

小心

确保设备和 PC 连接到同一局域网。

OTA 例程

按照以下步骤运行 OTA 例程以从 HTTP 服务器升级。

  1. 按照 破坏固件标签 的描述修改。

  2. 编辑 example_ota.c

    1. 根据服务器 IP 地址编辑主机

      #define PORT   8082
      static const char *host = "192.168.31.193";   //"m-apps.oss-cn-shenzhen.aliyuncs.com"
      static const char *resource = "ota_all.bin"; //"051103061600.bin"
      
    2. 将 OTA 类型编辑为 OTA_HTTP

      ret = ota_update_init(ctx, (char *)host, PORT, (char *)resource, OTA_HTTP);
      
  3. 使用命令 ./build.py -a ota 重新编译项目并将固件下载到设备。

  4. 使用命令 ./build.py 重新编译项目,并将 ota_all.bin 复制到 DownloadServer (HTTP)

  5. 编辑 http_server.py

    server_ip = '192.168.31.193'
    server_port = 8082
    
  6. 使用命令 python http_server.py 执行脚本,以启动下载服务器程序。

  7. 重置设备并连接到 HTTP 服务器。

  8. 固件下载完成后,设备将自动重置并从新固件启动。