杰理 SDK 文档中心
首页
首页
  • 项目概览

    • SDK 简介与核心特性
    • 芯片平台与硬件资料
    • SDK 版本与发布信息
  • 快速开始

    • 环境搭建与工具链
    • 编译工程
    • 烧录与量产工具
  • 工程结构与构建系统

    • 工程目录布局
    • 构建与链接配置
  • 应用层开发

    • mbox_flash 应用框架
    • 板级支持包 (BSP)
    • 公共应用模块
    • UI 显示子系统
  • 蓝牙子系统

    • BLE 控制器、链路层与 HCI 传输
    • GATT 服务框架
    • BLE 应用示例:遥控器 / Dongle / 对讲机
    • 经典蓝牙支持
  • 音频子系统

    • 音频编解码器
    • 音频设备接口 (DAC / ADC / APA)
    • 音效处理与 EQ
    • 播放、录音与 MIO 工作流
  • 设备与文件系统

    • 存储设备驱动 (NorFlash / SDMMC / USB)
    • 文件系统 (FAT / nor_fs / SYDF)
    • 设备管理框架 (dev_mg)
  • 系统服务与电源管理

    • 消息机制 (msg / hot_msg)
    • 配置与参数存储 (app_config / VM)
    • 电源管理 (SOFT OFF / POWER DOWN)
  • 固件升级

    • 升级框架总览 (code_v1 / code_v2)
    • 双 Bank 升级机制
    • 升级通道:UART / 测试盒 / BLE OTA / USB / SD
  • 补丁包与版本维护

    • 版本升级补丁链 (v1.1.0 → v1.4.0)
    • 问题修复补丁
    • 固件裁剪与资源优化
  • 开发工具与支持

    • 辅助工具与脚本
    • 文档、配置说明与常见问题

升级框架总览 (code_v1 / code_v2)

本页概述 AW30N BLE SDK 中的设备固件升级(OTA/烧录)框架,涵盖 code_v1 与 code_v2 两套升级代码的实现、数据结构、升级通道、参数传递与核心流程,是理解 SDK 升级能力的入口页面。

Purpose and Scope

本页面向需要理解或二次开发 AW30N SDK 升级功能的工程师,系统讲解:

  • 升级框架的整体架构:code_v1 与 code_v2 两套实现的定位与差异;
  • UFW 固件包格式:ufw_syd_head_v1 / ufw_file_head_v1 等头部结构;
  • 升级参数传递机制:SDK 与 U-Boot 之间通过 UPDATA_PARM 传递升级意图;
  • 升级通道体系:USB、UART、SD 卡、BLE/RCSP、TestBox、NOR Flash 等;
  • 升级目标注册机制:REGISTER_UPDATE_TARGET 与 .update_target 段;
  • 升级状态机与结果上报:UPDATE_STATE_T、UPDATA_RESULT 与 DEVICE_FIRST_START 等标志。

以下内容属于兄弟页面,不在本页展开:具体 BLE OTA 的 RCSP 协议细节(参见 RCSP 升级/通道下载相关页面)、具体外设驱动(UART/SD/Flash 驱动)、U-Boot 侧实现。

Overview

升级框架是 SDK 中负责"将新固件安全地写入 Flash、并在重启后由引导程序完成搬运"的整套机制。它解决的核心问题是:在应用运行时如何可靠地把新固件(.ufw 文件)下发、校验、落盘,并把升级意图与参数传递给下一阶段(U-Boot/Loader),最终实现系统自更新。

SDK 中并存两套升级代码,分别位于 sdk/apps/include_lib/update/code_v1/ 与 sdk/apps/include_lib/update/code_v2/:

  • code_v1(update_v1.h):早期实现,面向 SD 卡 / FAT 文件系统 + UFW 文件 的升级路径。它直接解析 UFW 文件(check_ufw_file),再调用 try_to_upgrade 完成升级,错误通过枚举(FAT_MOUNT_ERROR、FIND_OTA_ERROR 等)返回。
  • code_v2(update.h):新一代框架,抽象出 升级通道(UPDATA_TYPE)、升级目标(update_target)、升级状态机(UPDATE_STATE_T) 与 参数传递(UPDATA_PARM) 等概念,支持 USB/UART/SD/BLE/TestBox/NOR Flash 等更多通道,是当前 SDK 的主力实现。

两者并非互斥:code_v2 在底层复用 Flash/SFC 等基础设施,而 code_v1 的 UFW 文件解析逻辑也以 USER_NORFLASH_UFW_UPDATA 等通道形式被 code_v2 兼容。

升级的宏观流程为:获取升级文件 → 校验文件头 → 进入升级模式(复位到 Loader/U-Boot)→ Loader 按参数搬运固件 → 重启后校验结果并上报。update.c 是 code_v2 的应用层入口实现(update.c),其中定义了升级文件名、升级前需要关闭的外设(ram_protect_close、hwi_all_close、ll_hci_destory 等)以及看门狗处理。

Architecture

flowchart TD
    subgraph sg_App["应用层 (App)"]
        APP_CONFIG["app_config.h<br/>TFG_DEV_UPGRADE_SUPPORT<br/>TFG_UPGRADE_FILE_NAME"]
        UPDATE_C["update.c<br/>app_update_init / app_update_handle"]
    end

    subgraph sg_V2["code_v2 框架 (update.h)"]
        MODE_API["update_mode_api_v2<br/>选择升级通道"]
        PARM["UPDATA_PARM<br/>magic=0x5441 参数传递"]
        TARGET["update_target 注册表<br/>.update_target 段"]
        STATE["UPDATE_STATE_T 状态机"]
        RESULT["UPDATA_RESULT 结果上报"]
    end

    subgraph sg_V1["code_v1 框架 (update_v1.h)"]
        UFW_CHECK["check_ufw_file<br/>解析 UFW 文件头"]
        UFW_PARSE["ufw_syd_head_v1<br/>ufw_file_head_v1"]
        TRY_UP["try_to_upgrade<br/>SD 卡升级入口"]
    end

    subgraph sg_CH["升级通道 (UPDATA_TYPE)"]
        CH_USB["USB_UPDATA / USB_HID_UPDATA"]
        CH_UART["UART_UPDATA / TESTBOX_UART_UPDATA"]
        CH_SD["SD0_UPDATA / SD1_UPDATA"]
        CH_BLE["BLE_APP_UPDATA / SPP_APP_UPDATA"]
        CH_NOR["NORFLASH_UPDATA / DUAL_BANK_UPDATA"]
    end

    subgraph sg_BOOT["引导阶段 (U-Boot/Loader)"]
        LOADER["LOADER.BIN"]
        FLASH["Flash 分区写入"]
    end

    APP_CONFIG --> UPDATE_C
    UPDATE_C --> MODE_API
    MODE_API --> PARM
    MODE_API --> CH_USB
    MODE_API --> CH_UART
    MODE_API --> CH_SD
    MODE_API --> CH_BLE
    MODE_API --> CH_NOR
    TARGET --> MODE_API
    STATE --> RESULT
    PARM --> LOADER
    LOADER --> FLASH
    TRY_UP --> UFW_CHECK
    UFW_CHECK --> UFW_PARSE
    CH_NOR --> TRY_UP
    RESULT --> UPDATE_C

架构说明:

  • 应用层:app_config.h 通过 TFG_DEV_UPGRADE_SUPPORT 开关使能升级功能,TFG_UPGRADE_FILE_NAME 指定升级文件名(默认 /update.ufw,见 app_config.h)。update.c 提供 app_update_init / app_update_handle 作为应用入口(update.c)。
  • code_v2 框架:以 update_mode_api_v2(type, priv_param_fill_hdl, priv_update_jump_handle) 为统一入口,按 UPDATA_TYPE 选择通道,构造 UPDATA_PARM 传递给引导程序;update_target 注册表用于登记每个通道关闭外设驱动的回调;状态机 UPDATE_STATE_T 管理升级任务生命周期;UPDATA_RESULT 用于结果上报。
  • code_v1 框架:直接面向 UFW 文件,check_ufw_file 校验文件头后 try_to_upgrade 执行升级,适用于 SD 卡 + FAT 文件系统场景,其 UFW 解析被 code_v2 的 NOR Flash 通道复用。
  • 引导阶段:SDK 侧只负责"准备"与"复位跳转",真正的固件搬运由 U-Boot/Loader(LOADER.BIN)依据 UPDATA_PARM(含 ota_addr、文件路径)完成,重启后 SDK 再通过 update_success_boot_check / update_result_deal 处理结果。

code_v1 与 code_v2 的定位与差异

两套代码分别对应 SDK 演进的两个阶段,理解其差异有助于在阅读具体升级代码时快速定位。

维度code_v1 (update_v1.h)code_v2 (update.h)
设计思路面向文件的单一路径(SD 卡 + UFW)面向通道的抽象框架(USB/UART/SD/BLE/TestBox/NOR)
入口 APItry_to_upgrade(dev_name, up_file_path)update_mode_api_v2(type, ...)
文件校验check_ufw_file 解析 UFW 头部由各通道负责,兼容 UFW(USER_NORFLASH_UFW_UPDATA)
参数传递UPDATA_PARM(magic 0x5441)UPDATA_PARM + UPDATA_EXT_PARM + ext_arg_t
通道注册无(硬编码路径)REGISTER_UPDATE_TARGET + .update_target 段
状态管理同步返回错误码UPDATE_STATE_T 状态机 + UPDATA_RESULT 结果上报
结果标志—DEVICE_FIRST_START(BIT31) / DEVICE_UPDATE_KEY_ERR(BIT30)

设计意图:code_v1 诞生于早期芯片方案,升级路径固定为"读 SD 卡里的 UFW 文件";code_v2 将"从哪里拿固件"(通道)与"如何升级"(目标/参数)解耦,使同一套升级核心逻辑可以复用多个通道,新增通道只需注册一个 update_target 并实现 driver_close 回调,无需改动框架本身。

UFW 固件包格式(code_v1 定义)

UFW(Update FirmWare)文件是升级固件的打包格式,code_v1 在 update_v1.h 中定义了系统头与文件头:

struct ufw_syd_head_v1 {
    u16 Crc;                // crc16 for this struct
    u16 CrcOfSydFileHead;
    u32 FileLength;         // file length
    u16 FileCount;          // 此FW文件中包含的子文件个数
    u16 Version;
    u16 HeadAlignmentSize;
    u16 Res;
    char szChipName[16];    // 此FW文件对应的芯片类型,如AC690X,AC691X
    u32 Res2[4];
    u32 Res3[4];
} _GNU_PACKED_;

Source: update_v1.h

系统头的关键字段:Crc/CrcOfSydFileHead 提供两级 CRC 校验(头部自身 + 文件头区域);FileCount 表示包内含子文件数量;szChipName 限定芯片型号,防止刷错固件。_GNU_PACKED_ 保证结构体按 1 字节对齐,与打包工具的内存布局一致。

每个子文件由 ufw_file_head_v1 描述:

struct ufw_file_head_v1 {
    u8 FileType;            // 文件类型
    u8 Res;                 // 保留
    u16 Index;              // 文件索引号
    u16 Crc;                // 明文数据的校验码
    u16 Version;            // 本结构体版本
    u32 Addr;               // 地址
    u32 Length;             // 数据长度
    u32 AllLength;          // 数据长度+尾部对齐的数据长度
    u32 EncryptedAddr;      // 加密数据的地址偏移(相对u32Addr的地址)
    u32 EncryptedLength;    // 加密的数据长度
    union {
        // 当文件类型是FILE_TYPE_FW_RESERVE_ZONE_FILE有效
        struct {
            u32 ReserveZoneAddress;
            u32 ReserveZoneLength;
            char szReserveZoneName[12];
        } _GNU_PACKED_;
        struct {
            u32 Res0;                 // 保留
            u32 Res1[4];             // 保留
            u32 Res2[4];             // 保留
        } _GNU_PACKED_;
    };
    char name[16];
} _GNU_PACKED_;

Source: update_v1.h

文件头设计要点:

  • Addr/Length/AllLength:指明数据落盘地址、明文长度与对齐后长度,Loader 据此把数据写入 Flash 对应分区;
  • EncryptedAddr/EncryptedLength:支持密文区与明文区分离(安全升级),解密由 Loader 侧完成;
  • 联合体:当文件类型为保留区文件(FILE_TYPE_FW_RESERVE_ZONE_FILE)时,前 20 字节解析为保留区地址/长度/名称;否则为保留字段。这种"按类型复用头部"的做法节省了头部空间;
  • name[16]:短文件名(8+3 结构),与 update.c 中"升级文件路径必须是短文件名(8+3),仅支持 2 层目录"的注释约束一致(update.c)。

升级参数传递:UPDATA_PARM

SDK 与 U-Boot 之间通过固定地址处的 UPDATA_PARM 结构传递升级意图。code_v2 在 update.h 中定义:

#define UPDATE_PARAM_MAGIC		0x5441
typedef struct _UPDATA_PARM {
    u16 parm_crc;
    u16 parm_type;              //UPDATA_TYPE:sdk pass parm to uboot
    u16 parm_result;            //UPDATA_TYPE:uboot return result to sdk
    u16 magic;					//0x5441
    //8byte
    union {
        struct {
            u8  file_path[32];         //updata file path
        };
        struct {
            u8  file_patch[32];         //updata file path
        };
    };
    u8  parm_priv[32];          //sd updata
    //64byte
    u32 ota_addr;
    u16 ext_arg_len;
    u16 ext_arg_crc;
    //8 byte
} UPDATA_PARM;

Source: update.h

该结构是 SDK → U-Boot → SDK 的双向约定:parm_type 由 SDK 写入(取 UPDATA_TYPE 枚举值,如 UART_UPDATA),parm_result 由 U-Boot 写回升级结果;magic 固定为 0x5441(UPDATE_PARAM_MAGIC),用于防止在 parm_crc 恰好为 0 时误判有效性。file_path 指向升级文件路径(如 /update.ufw),ota_addr 给出 OTA 数据地址,ext_arg_len/ext_arg_crc 描述附加参数区。

code_v2 还定义了扩展参数机制(update.h):

enum EXT_ARG_TYPE {
    EXT_LDO_TRIM_RES = 0,
    EXT_JUMP_FLAG,
    EXT_KEEP_ROMIO_INFO = 0x10,

    EXT_TYPE_MAX = 0xff,
};

struct ext_arg_t {
    u8 type;
    u8 len;
    u8 *data;
};

Source: update.h

扩展参数以 TLV(type-len-data)形式存在:EXT_LDO_TRIM_RES 传递 LDO trim 校准值(通过 update_param_priv_fill 填充,update.h),EXT_JUMP_FLAG 控制跳转行为,EXT_KEEP_ROMIO_INFO(0x10)用于在升级时保持 ROM IO 配置(对应 update_keep_io 与 update_get_latch_romio API)。code_v1 中的 UPDATA_EXT_PARM 则以固定结构传递 SD 端口与 IO 方向配置(update_v1.h)。

升级结果与标志位

code_v2 在固定内存区维护升级状态(update.h):

extern u32 UPDATA_BEG;
extern u32 UPDATA_SIZE;

#define UPDATA_FLAG_ADDR		((void *)((u32)&UPDATA_BEG + 0x08))
#define BOOT_STATUS_ADDR		((void *)((u32)&UPDATA_BEG)) //预留8个bytes

#define UPDATA_MAGIC            (0x5A00)        //防止CRC == 0 的情况

Source: update.h

UPDATA_BEG 为链接脚本保留的专用内存区:前 8 字节是 BOOT_STATUS_ADDR(启动状态),UPDATA_FLAG_ADDR 存放升级标志。UPDATA_MAGIC = 0x5A00 被同时用作 UPDATA_RESULT 与 UPDATA_TYPE 的枚举基值,即"结果/类型的合法值都带 magic 前缀",避免与未初始化内存(0x00/0xFF)混淆:

typedef enum {
    UPDATA_NON = UPDATA_MAGIC,   //0x5A00
    UPDATA_READY,                //0x5A01
    UPDATA_SUCC,                 //0x5A02
    UPDATA_PARM_ERR,             //0x5A03
    UPDATA_DEV_ERR,              //0x5A04
    UPDATA_KEY_ERR,              //0x5A05
} UPDATA_RESULT;

Source: update.h

结果处理由 update_result_set / update_result_get / update_result_deal / update_clear_result / update_success_boot_check 一组 API 完成;update.c 中定义了应用层辅助标志(update.c):

#define LOADER_NAME			"LOADER.BIN"
#define DEVICE_UPDATE_KEY_ERR  BIT(30)
#define DEVICE_FIRST_START     BIT(31)

Source: update.c

  • DEVICE_FIRST_START(BIT31):首次启动标志——升级成功后设备第一次运行,应用据此做首次启动初始化(device_is_first_start() 可查询);
  • DEVICE_UPDATE_KEY_ERR(BIT30):升级按键错误标志,用于区分"升级失败"与"未满足升级条件";
  • LOADER_NAME:Loader 文件名,ota_loader_patch 相关路径即指向它(code_v1 的 UPDATA_PARM.ota_loader_patch[32],update_v1.h)。

升级通道体系(UPDATA_TYPE)

code_v2 用 UPDATA_TYPE 枚举统一标识所有升级通道(update.h):

typedef enum {
    USB_UPDATA = UPDATA_MAGIC,      //0x5A00
    SD0_UPDATA,                     //0x5A01
    SD1_UPDATA,
    PC_UPDATA,
    UART_UPDATA,
    BT_UPDATA,
    BLE_APP_UPDATA,
    SPP_APP_UPDATA,
    DUAL_BANK_UPDATA,
    BLE_TEST_UPDATA,
    NORFLASH_UPDATA,
    TESTBOX_UART_UPDATA,
    TESTBOX_UART_UPDATA_2,
    //NOTE:以上的定义不要调整,新升级方式在此添加,注意加在USER_NORFLASH_UFW_UPDATA之前;
    USER_NORFLASH_UFW_UPDATA,
    USER_LC_FLASH_UFW_UPDATA,
    USB_HID_UPDATA,

    NON_DEV = 0xFFFF,
} UPDATA_TYPE;

Source: update.h

枚举设计的关键约束(注释中明确写出):已有定义的顺序不能调整,新增通道必须加在 USER_NORFLASH_UFW_UPDATA 之前。这是因为 parm_type 通过 UPDATA_PARM 传递给 U-Boot,两边按枚举值硬编码约定;插入到枚举末尾附近可保持与旧 Loader 的兼容性。NON_DEV = 0xFFFF 作为"无设备"哨兵值。

通道间的互斥与触发方式由 UPGRADE_TYPE 描述(update.h):

typedef enum {
    UPGRADE_NULL = 0,
    UPGRADE_USB_HARD_KEY,
    UPGRADE_USB_SOFTKEY,
    UPGRADE_UART_SOFT_KEY,
    UPGRADE_UART_ONE_WIRE_HARD_KEY,
} UPGRADE_TYPE;

Source: update.h

UPGRADE_TYPE 区分 硬件按键触发(UPGRADE_USB_HARD_KEY、UPGRADE_UART_ONE_WIRE_HARD_KEY)与 软件命令触发(UPGRADE_USB_SOFTKEY、UPGRADE_UART_SOFT_KEY)。硬件触发面向产线/售后(上电检测按键进入升级),软件触发面向应用内 OTA。pmu_flag.h 中的 disable_uart_upgrade 位可进一步关闭 UART 升级(见补丁包中该定义),说明框架支持按产品配置裁剪通道。

各通道的硬件参数通过独立结构体配置:

  • SD 卡通道(_UPDATA_SD):control_type(控制器,SD_CONTROLLER_0/1)、control_io(SD0_IO_A~SD0_IO_F)、max_data_baud、wDevTimeOutMax、io_det_func(在线检测函数指针)、hc_mode 等(update.h);
  • UART 通道(_UPDATA_UART):control_io_tx/control_io_rx 指定 IO 对接、control_baud 波特率、control_timeout 超时(单位 10ms),结构体注释"共12个bytes"体现了对内存布局的严格约束(update.h);
  • U 盘通道(_UPDATE_UDISK):内部联合体用 32 字节缓冲承载 LDO trim 参数(rx_ldo_trim/tx_ldo_trim)(update.h)。

升级目标注册机制(update_target)

code_v2 的一个关键设计是把"通道外设驱动关闭"抽象为可注册的目标(update.h):

typedef void(*update_handler_t)(void);

typedef struct _UPDATE_STATE_T {
    UPDATE_TASK_INIT,
    UPDATE_CH_INIT,
    UPDATE_CH_SUCESS_REPORT,
    UPDATE_CH_EXIT,
} UPDATE_STATE_T;

struct update_target {
    char *name;
    update_handler_t driver_close;
};

#define REGISTER_UPDATE_TARGET(target) \
        const struct update_target target sec(.update_target)

extern const struct update_target update_target_begin[];
extern const struct update_target update_target_end[];

#define list_for_each_update_target(p) \
    for (p = update_target_begin; p < update_target_end; p++)

Source: update.h

工作原理:REGISTER_UPDATE_TARGET(target) 把 struct update_target 放入链接脚本的 .update_target 自定义段;链接后 update_target_begin[] 到 update_target_end[] 之间的连续数组即"全部注册目标",list_for_each_update_target 可遍历它们。这是典型的段收集(section collection)注册模式——模块只需在自己的 .c 文件里声明一个 REGISTER_UPDATE_TARGET 实例,无需修改框架注册表;框架升级前遍历所有目标,依次调用其 driver_close 回调关闭对应外设驱动(如 HCI、WiFi、看门狗等),确保升级期间外设处于安全状态。

update.c 中升级前关闭的外设清单印证了这一点(update.c):ll_hci_destory(蓝牙 HCI 销毁)、hci_controller_destory(控制器销毁)、ram_protect_close(RAM 保护关闭)、hwi_all_close(全部硬件中断关闭)、wifi_det_close(弱符号,WiFi 检测关闭)。

升级状态机与任务生命周期

code_v2 用 UPDATE_STATE_T 描述升级任务状态(update.h):

stateDiagram-v2
    [*] --> UPDATE_TASK_INIT
    UPDATE_TASK_INIT --> UPDATE_CH_INIT
    UPDATE_CH_INIT --> UPDATE_CH_SUCESS_REPORT
    UPDATE_CH_SUCESS_REPORT --> UPDATE_CH_EXIT
    UPDATE_CH_EXIT --> [*]
    UPDATE_CH_INIT --> UPDATE_CH_EXIT : 通道初始化失败
  • UPDATE_TASK_INIT:升级任务创建、参数准备;
  • UPDATE_CH_INIT:通道初始化(打开 SD/UART/USB 等设备、解析文件);
  • UPDATE_CH_SUCESS_REPORT:成功后上报结果(写 UPDATA_RESULT);
  • UPDATE_CH_EXIT:退出升级任务,释放资源。

失败路径直接由 UPDATE_CH_INIT 跳转 UPDATE_CH_EXIT,保证错误时也能走统一的收尾逻辑。任务级入口为 app_update_init / app_update_handle(msg)(update.h)。

核心升级流程

sequenceDiagram
    participant APP as 应用 (app_update_handle)
    participant V2 as code_v2 (update_mode_api_v2)
    participant TGT as update_target 遍历
    participant PARM as UPDATA_PARM (magic 0x5441)
    participant UBOOT as U-Boot / Loader (LOADER.BIN)
    participant FLASH as Flash 分区

    APP->>V2: 触发升级 (UPDATA_TYPE)
    V2->>V2: 填充 parm_type / file_path / ota_addr
    V2->>TGT: list_for_each_update_target
    TGT-->>V2: 依次调用 driver_close
    V2->>V2: 关闭外设/中断/看门狗 (ram_protect_close, hwi_all_close)
    V2->>PARM: 写入参数区 (update_param_priv_fill)
    V2->>UBOOT: 复位跳转进入升级模式
    UBOOT->>FLASH: 按 parm 搬运固件/校验 CRC
    UBOOT-->>PARM: 写回 parm_result
    FLASH-->>UBOOT: 完成
    UBOOT-->>APP: 重启
    APP->>APP: update_success_boot_check / update_result_deal
    APP->>APP: 设置 DEVICE_FIRST_START 处理首次启动

分步说明:

  1. 触发:应用调用 update_mode_api_v2(type, priv_param_fill_hdl, priv_update_jump_handle),type 指定 UPDATA_TYPE(如 UART_UPDATA);回调 priv_param_fill_hdl 允许调用方填充私有参数,priv_update_jump_handle 在跳转前回调;
  2. 参数准备:构造 UPDATA_PARM,写入 parm_type、文件路径、ota_addr 与扩展参数(update_param_priv_fill);
  3. 外设收尾:遍历 update_target 段调用所有 driver_close,随后关闭 RAM 保护、硬件中断与相关控制器(update.c 中 common_update_before_jump_reset_handle 汇总此类操作,update.h);
  4. 跳转:复位进入 U-Boot/Loader 升级模式,update_enter_cb_register 注册的 update_enter_callback 会被触发(update.h);
  5. Loader 执行:U-Boot 读取 UPDATA_PARM,按 file_path/ota_addr 搬运固件并校验(UFW 头 CRC / 数据 CRC),结果写回 parm_result;
  6. 结果处理:重启后 update_success_boot_check 判断是否升级成功,update_result_deal 消费结果,device_is_first_start 结合 DEVICE_FIRST_START 标志驱动首次启动流程。

code_v1 的流程更短:check_ufw_file(dev_name, up_file_path) 校验 UFW 文件(FAT_MOUNT_ERROR 等错误在此返回),随后 try_to_upgrade / try_to_upgrade_api(..., check) 直接执行升级(update_v1.h)。SDK 内建 ONLINE_SUB_OP_ENTER_UPGRADE_MODE(0x26)命令用于在线进入升级模式(cfg_tools.h),该命令经 RCSP/串口工具下发,对应升级工具链的"在线升级"能力。

使用示例

示例一:code_v1 文件升级入口(SD 卡 + UFW)

u32 check_ufw_file(char *dev_name, char *up_file_path);
u32 try_to_upgrade(char *dev_name, char *up_file_path);
u32 try_to_upgrade_api(char *dev_name, char *up_file_path, bool check);

Source: update_v1.h

典型调用序列:先 check_ufw_file 校验文件(返回 NO_ERROR 才继续),再 try_to_upgrade 执行;try_to_upgrade_api 的 check 参数控制是否先做校验。dev_name 为设备名(如 mnt/sd0),up_file_path 为升级文件路径。

示例二:code_v2 升级模式入口

void update_mode_api_v2(UPDATA_TYPE type, void (*priv_param_fill_hdl)(UPDATA_PARM *p), void (*priv_update_jump_handle)(int type));
void update_param_priv_fill(UPDATA_PARM *p, void *priv, u16 priv_len);

Source: update.h

update_mode_api_v2 是 code_v2 的统一升级入口:传入通道类型(如 UART_UPDATA、BLE_APP_UPDATA),并通过两个回调注入私有参数填充逻辑与跳转前处理逻辑。update_param_priv_fill 用于向 UPDATA_PARM 的 parm_priv[32] 区填充自定义私有数据(如校准信息)。

示例三:注册升级目标(外设驱动关闭回调)

#define REGISTER_UPDATE_TARGET(target) \
        const struct update_target target sec(.update_target)

struct update_target {
    char *name;
    update_handler_t driver_close;
};

Source: update.h

模块中声明一个 REGISTER_UPDATE_TARGET(xxx_target) 实例并实现 driver_close 函数,框架遍历 update_target_begin~update_target_end 时自动调用它。新增升级通道时无需修改框架代码,这是本框架最主要的扩展点。

示例四:升级结果查询与处理

u16 update_result_get(void);
int update_result_deal();
void update_result_set(u16 result);
void update_clear_result();
bool update_success_boot_check(void);
bool device_is_first_start();

Source: update.h

应用启动时通常组合使用:update_success_boot_check() 判断本次启动是否为升级成功后的启动;device_is_first_start() 判断 DEVICE_FIRST_START 标志,用于首次启动初始化(如清标志、恢复默认配置)。

配置选项

配置项类型默认值说明位置
TFG_DEV_UPGRADE_SUPPORT宏ENABLE总开关,使能设备升级功能app_config.h
TFG_UPGRADE_FILE_NAME宏"/update.ufw"升级文件路径(短文件名 8+3,仅 2 层目录)app_config.h
UPDATA_MAGIC宏0x5A00升级标志/结果 magic 值,防止 CRC==0 误判update.h
UPDATA_KEEP_IO_ENABLE宏0升级时是否保持 IO 功能update.h
UPDATE_PARAM_MAGIC宏0x5441UPDATA_PARM 有效性魔数update.h
UPDATE_PRIV_PARAM_LEN宏32私有参数区长度update.h
UPDATA_PARM_SIZE宏256参数结构总大小update.h
TESTBOX_UART_UPDATE_EN宏视工程使能 TestBox UART 升级(testbox_uart_update.h 条件编译)update.c
CONFIG_APP_OTA_EN宏视工程使能 RCSP 蓝牙 OTA(rcsp_bluetooth.h 条件编译)update.c
CONFIG_UPDATE_STORAGE_DEV_EN符号视工程存储设备升级使能(extern const int)update.h
CONFIG_UPDATE_TESTBOX_UART_EN符号视工程TestBox UART 升级使能update.h
CONFIG_UPDATE_APP_OTA_EN符号视工程应用 OTA 使能update.h
CONFIG_UPDATE_TESTBOX_BLE_EN符号视工程TestBox BLE 升级使能update.h

API 参考

code_v2(update.h)

函数签名说明
void update_mode_api_v2(UPDATA_TYPE type, void (*priv_param_fill_hdl)(UPDATA_PARM *p), void (*priv_update_jump_handle)(int type))统一升级入口:按 type 选择通道,priv_param_fill_hdl 填充私有参数,priv_update_jump_handle 在跳转前回调
void update_param_priv_fill(UPDATA_PARM *p, void *priv, u16 priv_len)向 UPDATA_PARM.parm_priv 填充私有数据
u16 update_result_get(void)读取升级结果(UPDATA_RESULT 值)
bool device_is_first_start(void)查询 DEVICE_FIRST_START 标志,判断是否升级后首次启动
int update_result_deal(void)处理升级结果(消费并清理)
void update_result_set(u16 result)写入升级结果
void update_clear_result(void)清除升级结果
bool update_success_boot_check(void)检查本次启动是否为升级成功启动
void update_enter_cb_register(void *callback)注册进入升级模式的回调(存于 update_enter_callback)
void app_update_handle(int msg)应用层升级消息处理
int app_update_init(void)应用层升级模块初始化
void update_keep_io(UPDATA_PARM *p)保持 IO 功能(配合 UPDATA_KEEP_IO_ENABLE)
u32 update_get_latch_romio(void *data)获取锁存的 ROM IO 配置(配合 EXT_KEEP_ROMIO_INFO)
void common_update_before_jump_reset_handle(void)跳转复位前的公共收尾处理
int get_ble_connect_handle(void)获取 BLE 连接句柄(升级前判断连接状态)

code_v1(update_v1.h)

函数签名说明
u32 check_ufw_file(char *dev_name, char *up_file_path)校验 UFW 文件(打开设备/挂载 FAT/解析头部),返回 NO_ERROR 表示通过
u32 try_to_upgrade(char *dev_name, char *up_file_path)执行升级,返回错误枚举值
u32 try_to_upgrade_api(char *dev_name, char *up_file_path, bool check)带 check 开关的升级入口,check=true 时先校验再升级

失败模式、边界情况与并发

code_v1 错误码体系

code_v1 以同步枚举返回升级各阶段错误(update_v1.h):

enum {
    NO_ERROR,
    SFC_OPEN_ERROR,        // SFC 打开失败
    DEVIVE_OPEN_ERROR,     // 设备打开失败
    FAT_MOUNT_ERROR,       // FAT 文件系统挂载失败
    FILE_OPEN_ERROR,       // 升级文件打开失败
    FIND_FLASH_BIN_ERROR,  // 未找到 flash bin
    FIND_FLASH2_BIN_ERROR, // 未找到 flash2 bin
    NO_NEED_UPGRADE,       // 无需升级(版本相同/不满足条件)
    FIND_OTA_ERROR,        // 未找到 OTA 数据
    FIND_LOADER0_ERROR,    // 未找到 Loader0
    FLASH_SIZE_ERROR,      // Flash 容量不足/不匹配
};

Source: update_v1.h

该枚举覆盖了升级链路的典型故障点:介质层(SFC_OPEN_ERROR)、文件系统层(FAT_MOUNT_ERROR)、文件层(FILE_OPEN_ERROR)、内容层(FIND_OTA_ERROR、FIND_LOADER0_ERROR)与容量层(FLASH_SIZE_ERROR)。NO_NEED_UPGRADE 是正常分支而非错误:当目标固件版本与当前一致时,框架应安全退出而非反复升级。

code_v2 结果与标志的边界

  • magic 防误判:UPDATA_MAGIC = 0x5A00 与 UPDATE_PARAM_MAGIC = 0x5441 都刻意避开 0x00/0xFF/全零,防止未初始化内存或 CRC==0 被误认为有效升级请求;
  • 首次启动与按键错误:DEVICE_FIRST_START(BIT31)与 DEVICE_UPDATE_KEY_ERR(BIT30)共用一个 g_updata_flag 变量,属于位标志语义,处理时需按位判断、按位清除,避免互相覆盖;
  • NON_DEV = 0xFFFF:作为通道枚举的"无设备"值,当检测不到升级设备(如未插 SD 卡、未接 USB)时应返回该值,避免误进入升级模式;
  • 文件路径约束:升级文件必须是短文件名(8+3)且最多两层目录(update.c),长文件名/深层目录会导致 FILE_OPEN_ERROR——这是 FAT 环境下为节省内存而做的硬性限制。

并发与一致性

  • 升级过程是单任务、独占式的:进入升级模式前必须关闭其他活动(ll_hci_destory、hci_controller_destory、hwi_all_close),避免外设中断/蓝牙栈在固件搬运期间干扰 Flash 写入;
  • update_target 的 driver_close 回调在遍历时被顺序调用,注册顺序即关闭顺序,因此依赖顺序的驱动应在注册宏的声明位置体现先后;
  • 升级参数区(UPDATA_BEG 附近)是 SDK 与 U-Boot 共享的固定内存,复位不丢失;parm_result 由 U-Boot 写回,SDK 侧读写需注意内存屏障/缓存一致性(_GNU_PACKED_ 结构体访问建议按字节或 volatile 处理);
  • 补丁包中出现 disable_uart_upgrade 位(pmu_flag.h),说明量产固件常禁用 UART 升级以缩小攻击面,只保留产线/售后专用通道——安全与便利的权衡由该标志位控制。

性能与运维要点

  • CRC 校验开销:UFW 头部含两级 CRC(Crc 与 CrcOfSydFileHead),文件较大时校验集中在 Loader 阶段执行,应用侧 check_ufw_file 只做头部级快速校验,避免重复全量校验拖慢启动;
  • 升级期间看门狗:update.c 引入 wdt.h,升级跳转前需正确喂狗或关闭看门狗,防止长耗时搬运触发复位(common_update_before_jump_reset_handle 统一处理此类收尾);
  • 超时配置:UART 通道 control_timeout 单位为 10ms(update.h),SD 通道 wDevTimeOutMax 用于设备响应超时,产线调试时优先检查这些参数;
  • 首次启动流程:升级成功后的首次启动通过 DEVICE_FIRST_START 区分,用于执行校准恢复、标志清理等一次性操作,漏清标志会导致每次开机都走首次启动流程;
  • 通道裁剪:CONFIG_UPDATE_STORAGE_DEV_EN、CONFIG_UPDATE_TESTBOX_UART_EN、CONFIG_UPDATE_APP_OTA_EN、CONFIG_UPDATE_TESTBOX_BLE_EN 四个链接期符号(extern const int)用于裁剪通道,ROM 紧张的方案可按需关闭(补丁包中 TFG_DEV_UPGRADE_SUPPORT 0 的做法即整体关闭升级功能)。

扩展点

  1. 新增升级通道:在 UPDATA_TYPE 枚举中 USER_NORFLASH_UFW_UPDATA 之前追加新值(保持旧值不变以兼容 Loader),实现通道参数结构体(参考 _UPDATA_SD / _UPDATA_UART)并在 update_mode_api_v2 的分发逻辑中接入;
  2. 注册驱动关闭目标:模块内 REGISTER_UPDATE_TARGET(名字) + 实现 driver_close,框架自动遍历执行,无需改动框架;
  3. 私有参数扩展:通过 update_param_priv_fill 填充 parm_priv[32],或使用 ext_arg_t TLV 扩展 EXT_ARG_TYPE 新类型(如新增产线校准参数);
  4. 进入升级回调:update_enter_cb_register 注册 update_enter_callback,可在跳转前执行自定义逻辑(如保存日志、通知对端);
  5. code_v1 兼容路径:SD 卡 + UFW 场景可直接调用 try_to_upgrade_api;code_v2 的 USER_NORFLASH_UFW_UPDATA / USER_LC_FLASH_UFW_UPDATA 通道则把 UFW 文件解析复用到 NOR Flash/LC Flash 介质上。

相关实现文件

  • sdk/apps/include_lib/update/code_v1/update_v1.h — code_v1 头文件:UFW 格式、错误枚举、升级 API
  • sdk/apps/include_lib/update/code_v2/update.h — code_v2 头文件:通道枚举、参数结构、状态机、注册机制
  • sdk/apps/app/bsp/common/update/update.c — 应用层升级实现:入口、外设收尾、标志位
  • sdk/apps/app/bsp/common/update/dev_update.c — 设备升级实现
  • sdk/apps/app/bsp/common/update/testbox_uart_update.c — TestBox UART 升级通道
  • sdk/apps/app/bsp/common/update/testbox_update.c — TestBox 升级通道
  • sdk/apps/app/bsp/common/third_party_profile/jieli/JL_rcsp/rcsp_update/rcsp_user_update.c — RCSP 用户升级(BLE OTA 应用侧)
  • sdk/apps/app/bsp/common/third_party_profile/jieli/JL_rcsp/rcsp_update/rcsp_ch_loader_download.c — RCSP 通道 Loader 下载
  • sdk/apps/app/src/mbox_flash/app_config.h — 升级功能开关与升级文件名配置
  • sdk/apps/include_lib/config/cfg_tools.h — 在线进入升级模式命令(0x26)

Related Links

  • BLE OTA / RCSP 升级:参见 RCSP 升级与通道下载相关页面(rcsp_user_update.c / rcsp_ch_loader_download.c 归属的 RCSP 能力页)
  • UART/TestBox 产线升级:参见 TestBox 升级通道相关页面
  • U-Boot 与 Loader:引导程序侧的固件搬运与 parm_result 回写,参见 Boot/Loader 相关文档
  • SDK 配置总览:app_config.h 各功能开关(TFG_DEV_UPGRADE_SUPPORT 所在配置体系)
Next
双 Bank 升级机制