OTA(固件端)

1. 介绍

2.0 版本 OTA 升级方案实现了固件升级、表盘传输、自定义数据传输等功能的统一,通过统一升级协议支持多场景升级。根据芯片所使用的 Flash 类型(NOR Flash/NAND Flash/eMMC Flash),升级模式存在差异,核心区别在于升级流程、存储布局及交互逻辑。以下是针对通过手机APP的升级固件的方案。

⚠️ 注意

  1. 这里提到的NAND和eMMC方案都是指的直接从 NAND/eMMC boot的方案。不包括芯片已经挂了一个Nor,又挂了NAND/eMMC的方案,这种情况,如果内置资源全部使用BIN来存储,则认为是一个Nor方案;否则,如果文件系统来存储,则可以认为是一个NAND / eMMC方案。

  2. NAND/eMMC对于软件方案而言,都是块设备,因此是一种类型,下面的处理相同。因此,后面提到的NAND方案中包括eMMC。

2. 按 Flash 类型划分的 OTA 方案

2.1 NOR Flash 方案

Nor Flash的升级方案有两种: 标准OTA和RAM Run OTA。 两种方案的特点如下,客户需要根据自己的需要来选择采用那种OTA的方案。

NOR Flash 两种OTA升级方案对比表

对比维度

标准 NOR Flash OTA(独立 OTA Manager)

NOR Flash RAM Run OTA(内存运行 OTA Manager)

核心特征

XIP运行

升级时加载到SRAM运行

存储布局

ota_manager包括蓝牙接收功能,覆盖升级

ota_manager不包括蓝牙功能,备份升级

日常启动流程

boot loader ota_manager solution_code

boot loader solution_code(无ota_manager环节)

升级触发时机

触发升级后重启进入ota_manager

主程序运行中下载资源,完成后重启触发ota_manager

升级文件处理

下载升级文件直接覆盖目标分区(hcpu/resource)

1. solution_code镜像先下载到备份区;
2. resource直接覆盖目标分区;
3. 重启后解压备份区镜像到目标分区

升级中设备状态

升级阶段无主程序运行,功能不可用(常规OTA逻辑)

下载resource时设备功能不可用;但下载solution_code时可取消

Flash空间占用

占用ota_manager空间大,一般是512KB

需预留备份区空间,但ota_manager空间小(220KB左右)

ota_manager自身升级

XIP运行,不可升级

使用ramrun,可升级,且分区的位置可变

适合场景

空间有限,无须70%的备份区域

空间足够,有备份区(70%),升级code中途可反悔

2.1.1 标准 NOR Flash OTA(独立 OTA Manager)

  • 存储布局:包含独立的ota_manager(flash_map中为dfu_mng_code)程序,与boot loadersolution_code(HCPU主程序)、resource(资源区)等分区独立划分。

  • 启动流程:每次开机固定执行 boot loader ota_manager solution_code(hcpu),之后程序运行时在solution_code分区。

  • 升级流程:

    • 触发升级时,设备重启进入ota_manager;

    • ota_manager通过 BLE 与手机交互,下载升级文件并直接覆盖hcpu、resource等目标分区;(注意lcpu如果有升级,将通过solution_code携带)

    • 下载完成后重启,通过boot loader ota_manager hcpu流程运行新程序。

alt text

2.1.2 NOR Flash RAM Run OTA(内存运行 OTA Manager)

  • 存储布局:需要存放ota_ramrun的分区(flash_map中还是沿用了ota_manager名字),ota_manager程序在升级时加载到 SRAM 运行,需预留备份区(dfu_download_buffe,= solution_code * 70%)存储待升级镜像。

  • 启动流程:日常开机流程为 boot loader solution_code(hcpu),开始运行主程序。

  • 升级流程:

    • 主程序(solution_code)运行时通过 BLE 下载升级资源:

      • 压缩的solution_code(hcpu)镜像下载到备份区dfu_download_buffe

      • resource等资源直接覆盖目标分区(此阶段设备功能不可用);

    • 下载完成后重启,触发 boot loader ota_manager(SRAM运行);

    • ota_manager将备份区(dfu_download_buffe)的压缩镜像解压到solution_code(hcpu)原始分区,完成后重启进入新程序。

alt text

2.2 NAND Flash 方案

NAND Flash的升级方案有两种: 内置资源放在Builtin_res的方案和放在文件系统的方案。 两种方案参见选型原则一节描述。

两种方案具有以下共同的特点:

  • 核心特点:无独立ota_manager,通过双solution_code分区(solution_code/solution_code_Y)实现升级,其他资源(如RES、FONT)采用直接覆盖方式。

  • 启动流程:开机时boot loader根据标记选择启动solution_codesolution_code_Y,作为当前的活跃分区。

  • 分区升级:

    • 若当前运行在solution_code,升级文件下载到solution_code_Y;反之则下载到solution_code

    • 对于其他分区升级,直接覆盖目标分区(此阶段设备功能可能不可用);

    • 下载完成后重启,boot loader切换到新升级的solution_code分区,完成升级。

2.2.1 内置资源放在Builtin_res的方案

alt text

这个方案中首先内置资源是以bin的形式存储。由于NAND方案的容量比较大,一般客户会堆更多的素材,因此内置资源通常比较大。如果直接升级img(图片资源)的分区,用蓝牙进行传输,会导致传输时间过长的情况。因此,Solution提供了一个单独的img_update分区存储ota更新(新增、修改)的图片。

基本的原则如下:

  1. 在Builtin_res中使能attribute_used的宏IMAGE_ATTR_USED

  • (Top) Development Config Solution File System Config Solution resource built_in Enable  Enable Image __attribute__((used)). (support Incremental image ota)

  1. 基线版本发出后,所有涉及到更新(新增图片,修改图片[需要改名])的图片,添加到资源目录\solution\examples\xxx\resource\images_update下;所有删除或修改的图片,在img分区继续保留,只是没有代码引用。

  • 注意: 修改图片由于图片名发生了变化,代码也需要修改

  1. 重新编译。由于img分区使能了__attribute__((used),因此即便没有代码调用,也会包在img.bin中,因此,img分区的size不会发生变化;生成的img_update分区作为ota的升级分区即可。

2.2.2 内置资源放在文件系统的方案

alt text

这个方案中首先内置资源是文件形式存储在文件系统中。因此资源升级的时候,采用文件差分升级即可。也就是发生变化的文件(图片)才被ota升级,其他的维持不变。

  • 差分升级支持:基于文件系统的分区可使用差分包升级(仅需传输与基础版本的差异部分),减少传输数据量。

⚠️ 特别说明

  1. 带 MPI5 的 NAND 方案(如563、567)

    • 需在 NAND 中配置download buffer分区,用于升级与蓝牙相关的 MPI5 组件(避免直接覆盖导致蓝牙功能中断)。

  2. 不带 MPI5 的 NAND 方案(如525、527)

    • 无需特殊缓冲配置,仅需正确划分双hcpu分区及资源分区

4. 升级包制作

4.1 基础镜像包(.bin)制作

通过imgtool.exe生成加密签名的 OTA 镜像包,核心命令如下:

  1. NOR FLASH imgtool.exe gen_dfu --img_para app 0 0 --key=s01 --sigkey=sig --dfu_id=1 --hw_ver=51 --sdk_ver=7001 --fw_ver=1001001 --com_type=0

  2. NAND FLASH imgtool.exe gen_dfu --img_para app 0 0 --key=s01 --sigkey=sig --dfu_id=1 --hw_ver=51 --sdk_ver=7001 --fw_ver=1001001 --com_type=0 --bksize=2048

参数说明:

  • –img_para: App是制作的bin的文件名,比如当前制作的是app.bin,可以同时制作多个bin。如:--img_para app 0 0 lcpu 0 1

    • 第一个数代表是否使用压缩,如果压缩就填16,只有nor flash ota可以使用压缩,且需要配置备份空间。

    • 第二个数代表image id,每一个image bin都由此ID区分,参照dfu_protocol.h中OTA_EXT_V3定义下的dfu_img_id_t。

  • –dfu_id,nor flash ota升级ota manager时,填2,其余填1。升级ota manager只能单独制作ota_manager.bin,不能和其他bin混合升级。

4.2 NAND Flash 差分包制作

  • 编译基础版本,保存fat_img文件夹,如果升级工程和基础版本不是同一工程,需要copy到其他路径或者重命名,避免编译升级版本覆盖

  • 编译升级版本,保存fat_img文件夹
    alt text

  • 差分包制作,生成的zip包就是基础版本到升级版本的资源包
    alt text alt text

4.3 升级包制作示例(以 SF32LB523 NOR 方案为例)

打包 OTA 升级包所需工具及签名文件在 Solution 中的路径:

  • sdk\tools\secureboot\imgtoolv37.exe

  • sdk\tools\secureboot\sifli02\s01.bin

  • sdk\tools\secureboot\sifli02\sig_hash.bin

  • sdk\tools\secureboot\sifli02\sig_pri.pem

4.3.1 仅升级 APP 分区(快包)

调用 imgtoolv37.exe 程序对APP分区进行封装打包

rem === 52x_pack_ota_app.bat ===

@echo off
cd /d "%~dp0"

set tool_dir=ota_tool
set ota_dir=ota
set root_path=output

set project_name=mod
set verno=1.0

set param1=%~1
set param2=%~2

if "%param1%"=="" (
    echo Input param1 - project_name is NULL
)else (
    set project_name=%param1%
)
if "%param2%"=="" (
    echo Input param2 - verno is NULL
)else (
    set verno=%param2%
)
echo project name is "%project_name%"
echo version number is "%verno%"

set str_date=%date:~0,4%%date:~5,2%%date:~8,2%
set str_time=%time:~0,2%%time:~3,2%
set str_time=%str_time: =0%

set packet_name=%project_name%_%verno%_%str_date%_%str_time%
set packet_path=%root_path%\%ota_dir%
set ota_zip=%root_path%\%packet_name%.zip
set cmd=imgtoolv37.exe gen_dfu --img_para app 0 0 --key=s01 --sigkey=sig --dfu_id=1 
        --hw_ver=51 --sdk_ver=7001 --fw_ver=1001001 --com_type=0

echo %str_date%
echo %str_time%
if exist %root_path% (
    rd %root_path% /s/q
)
md %root_path%
md %packet_path%

for %%s in (*.*) do (
    if %%~xs==.bat (
        echo %%s
    ) else (
        if %%s==7za.exe (
            echo %%s
        ) else if %%s==ER_IROM1.bin (
            echo %%s
        ) else if %%s==ER_IROM2.bin (
            echo %%s
        ) else if %%s==ER_IROM3.bin (
            echo %%s
        ) else if %%s==root.bin (
            echo %%s
        ) else (
            del %%s
        )
    )
)

copy %tool_dir%\imgtoolv37.exe
copy %tool_dir%\*.bin
copy %tool_dir%\*.pem

copy ER_IROM1.bin app.bin

start /wait "" %cmd%

copy ctrl_packet.bin %packet_path%\
copy outapp.bin %packet_path%\

cd %root_path%
start /wait "" ..\7za.exe a %packet_name%.zip %ota_dir%

@pause

4.3.2 升级所有分区(全量包)

调用 imgtoolv37.exe 程序对各分区进行封装打包

rem === 52x_pack_ota_all.bat ===

@echo off
cd /d "%~dp0"

set tool_dir=ota_tool
set ota_dir=ota
set root_path=output

set project_name=mod
set verno=1.0

set param1=%~1
set param2=%~2

if "%param1%"=="" (
    echo Input param1 - project_name is NULL
)else (
    set project_name=%param1%
)
if "%param2%"=="" (
    echo Input param2 - verno is NULL
)else (
    set verno=%param2%
)
echo project name is "%project_name%"
echo version number is "%verno%"

set str_date=%date:~0,4%%date:~5,2%%date:~8,2%
set str_time=%time:~0,2%%time:~3,2%
set str_time=%str_time: =0%

set packet_name=%project_name%_%verno%_%str_date%_%str_time%
set packet_path=%root_path%\%ota_dir%
set ota_zip=%root_path%\%packet_name%.zip
set cmd=imgtoolv37.exe gen_dfu --img_para app 0 0 res 0 3 font 0 4 root 0 5 --key=s01 --sigkey=sig 
        --dfu_id=1 --hw_ver=51 --sdk_ver=7001 --fw_ver=1001001 --com_type=0

echo %str_date%
echo %str_time%
if exist %root_path% (
    rd %root_path% /s/q
)
md %root_path%
md %packet_path%

for %%s in (*.*) do (
    if %%~xs==.bat (
        echo %%s
    ) else (
        if %%s==7za.exe (
            echo %%s
        ) else if %%s==ER_IROM1.bin (
            echo %%s
        ) else if %%s==ER_IROM2.bin (
            echo %%s
        ) else if %%s==ER_IROM3.bin (
            echo %%s
        ) else if %%s==root.bin (
            echo %%s
        ) else (
            del %%s
        )
    )
)

copy %tool_dir%\imgtoolv37.exe
copy %tool_dir%\*.bin
copy %tool_dir%\*.pem

copy ER_IROM1.bin app.bin
copy ER_IROM2.bin res.bin
copy ER_IROM3.bin font.bin

start /wait "" %cmd%

copy ctrl_packet.bin %packet_path%\
copy outapp.bin %packet_path%\
copy outres.bin %packet_path%\
copy outfont.bin %packet_path%\
copy outroot.bin %packet_path%\

cd %root_path%
start /wait "" ..\7za.exe a %packet_name%.zip %ota_dir%

@pause

5. 新增 OTA 类型(自定义传输)

5.1 注册接口

通过OTA_REGISTER接口注册新的 OTA 类型,定义如下:

/*
 *id:  
 *      ota类型的标识, 需要和手机端保持一致。
 *      添加类型在"ota_custom_config.h"的OTA_DFU_CUSTOM_START_IND后添加枚举值。
 *flag: 
 *      可以位或方式传入参数,见ota_flag_t。
 *      OTA_FLAG_REINSTALL: 支持重安装,目前只有NAND ota差分资源支持重安装处理,其余都不支持。
 *      OTA_FLAG_RESUME: 支持续传,目前基于文件系统存储都支持续传,重启/传输其他ota包时不会续传。
 *      OTA_FLAG_SEP_DIR:传输的文件放到由手机和固件协商解析的子目录,只有SF_TOOL传输使用。
 *      OTA_FLAG_BACKGROUND:支持后台传输,建议只有升级较小的文件时使用后台传输功能。
 *dst:  
 *      固件端指定存放路径,如音乐,SF_TOOL,背景传输等手机不知道路径,需要固件指定存放路径。
 *backup:
 *      备份路径,基于文件系统传输都会设置备份路径,可以避免覆盖模式传输失败对原有包的影响。
 *      NAND 差分资源特殊处理,dst和backup不会生效
 *msg_handler:
 *      OTA协议消息处理回调函数
 *
*/
OTA_REGISTER(id, flag, dst, backup, msg_handler)

5.2 数据透传与安装

  • 基于文件系统:可复用sdk提供的ota_fs_proc.c,无需额外实现透传逻辑。

  • 非文件系统(如内存 / 串口写入):需自定义msg_handler处理数据接收与解析。

  • 安装流程(基于文件系统,参考ota_window.c):

    • pre_copy:清除旧文件及内存数据(如旧表盘);

    • copy:SDK 统一处理从备份区到目标区的文件搬移;

    • post_copy:执行安装后逻辑(如加载新表盘、更新配置)。

6. 代码位置

  1. SDK OTA升级核心处理 \sdk\middleware\dfu\dfu_ctrl_ext_v3.c
    负责OTA底层核心逻辑(协议交互,通信处理,flash适配,img固件分片接收,校验,写入等)

  2. 应用层OTA通用定义和接口 \solution\components\ota\common
    定义应用层OTA通用数据结构,状态错误码,状态回复,消息回调注册等

  3. 应用层OTA服务和框架 \solution\components\ble\ble_ota
    ota类型注册,文件资源续传,校验,备份写入,UI交互处理等

  4. 应用层OTA界面 \solution\components\ota\ota_app\gui
    负责HCPU端OTA相关的用户交互界面

  5. 应用层OTA各类型具体处理 \solution\components\ota\ota_app\proc
    针对不同类型的OTA的差异化处理

  6. OTA MANAGER界面和逻辑处理 \solution\components\ota\ota_manager
    负责OTA MANAGER用户交互界面,消息处理等

注意

  • HCPU编译范围,1,2,3,4,5

  • OTA MANAGER编译范围1,2,3,6

7. 常见问题

  • BLE 传输干扰:升级时需尽量停止设备与手机的其他 BLE 交互,避免传输中断。

  • NOR OTA Manager 适配:标准 NOR 方案中,ota_manager运行时使用默认 BLE 广播和 GATT 服务,如自定义需单独适配。

  • 续传限制:支持续传的场景下,重启设备或切换其他 OTA 包后,原续传进度会丢失。

  • 功能可用性:直接覆盖分区(如RES、FONT)时,设备功能不可用,需提示用户等待升级完成。