杰理 SDK 文档中心
首页
首页
  • 概述与快速开始

    • SDK 总览与芯片能力
    • 环境搭建与编译构建
    • 烧录与固件升级
    • 文档与版本资源
  • 应用与示例方案

    • demo 示例工程
    • WiFi 摄像头方案 (wifi_camera)
    • WiFi 音箱方案 (wifi_soundbox)
    • WiFi 婴儿监护方案 (wifi_bbm)
    • 公共应用模块库
    • 示例代码库 (example)
  • 系统架构与平台

    • 总体架构与工程分层
    • 系统启动与运行框架
    • 芯片驱动与板级适配
    • 设备管理与文件系统
    • 系统工具库与算法
  • 音频子系统

    • 音频框架与处理节点
    • 音频编解码与音效
    • 播放器与录音器
    • 语音交互与 AI 唤醒
    • LE Audio 与蓝牙音频
    • 音频调试与歌词
  • 视频与显示子系统

    • 摄像头驱动与 ISP
    • 视频编码与图像处理
    • 显示与 GPU 加速
    • 屏幕镜像 (screen_mirror)
  • 无线连接与网络

    • 蓝牙协议栈 (双模蓝牙)
    • WiFi 协议栈与配网
    • 网络协议栈
    • 云平台与 IoT 协议
  • UI 子系统

    • LVGL 集成与应用
    • UI 工程与工具链
  • 配置系统

    • 功能配置
    • 板级配置
    • 网络与蓝牙配置
    • 音频配置与提示音
  • 工具与测试

    • 产测与射频测试工具
    • 固件升级与更新机制
    • 调试与日志工具
  • 硬件参考设计

    • 原理图参考设计
    • 芯片数据手册

烧录与固件升级

本文档介绍 AC792N SDK 中固件烧录(Flashing)与升级(OTA/Update)机制的完整实现:从应用层升级参数的组织与传递,到双备份(Double Bank)Flash 编程接口,再到 UART、网络、NorFlash、USB/SD 等各升级通道的接入方式。

Purpose and Scope

本文档覆盖 AC792N SDK 固件升级子系统的核心实现,包括:

  • 应用层升级框架(sdk/apps/common/update/update.c)中的升级参数结构、CRC 校验与结果持久化机制;
  • 双备份升级引擎的对外 API(sdk/include_lib/update/db_updata_api.h)及其数据流;
  • 各升级通道(UART、HTTP 网络、NorFlash、TWS、USB MSD、SD 卡、文件系统、测试盒)的定位与协作关系。

以下主题由其他页面覆盖,本文档不展开:USB 设备协议栈本身的实现(见 USB 相关目录项)、网络协议栈细节、fs_update.c 所依赖的文件系统内部实现。本文档侧重"升级机制本身如何工作",而不是某个具体外设驱动的细节。

Overview

AC792N SDK 是一套面向蓝牙/WiFi 音频与摄像头类产品的嵌入式固件 SDK。固件升级能力是量产烧录与售后 OTA 的共同基础,其设计目标是:

  1. 多通道统一:无论固件包来自串口(UART)、U 盘(MSD)、SD 卡、网络(HTTP)还是 TWS 对耳,应用层最终都通过同一套参数填充与跳转机制进入升级流程;
  2. 断电安全:升级参数(UPDATA_PARM)存放在固定 RAM 地址,通过 CRC16 保护;升级结果持久化到 Flash 参数区,重启后可判断上次升级是否成功;
  3. 双备份可回退:核心升级引擎采用双 Bank 结构(db_update_* API),新固件写入备份 Bank,校验通过后再烧录启动信息(boot info),从而在升级失败时仍能回退到旧固件;
  4. Loader 引导:应用通过 update_mode_api_v2() 等接口把升级类型、参数与跳转地址写入 UPDATA_PARM,随后跳转到独立 Loader(LOADER.BIN / ota.bin / UFW 包)完成实际的 Flash 编程。

升级包在文件系统侧以 *.UFW(见 update.c)为标识;Loader 名称固定为 LOADER.BIN。

Architecture

下图展示升级子系统的整体架构:应用层、升级框架、双备份引擎与各传输通道之间的关系。

flowchart TD
    subgraph sg_App["应用层 (sdk/apps/common)"]
        APP["业务应用 (音频/摄像头)"]
        UFW["UFW 升级包 (/*.UFW)"]
    end

    subgraph sg_Frame["升级框架 update.c"]
        MODE_API["update_mode_api_v2()"]
        PARAM["UPDATA_PARM 参数块 + CRC16"]
        RESULT["update_result_get/set()"]
        BOOTCHK["update_success_boot_check()"]
        HWCLOSE["update_close_hw()"]
    end

    subgraph sg_Channels["升级传输通道"]
        UART["uart_update.c"]
        NET["net_update.c / http_update.c"]
        NOR["norflash_update.c / norflash_ufw_update.c"]
        USB_SD["usb msd_upgrade / sd_upgrade_impl"]
        TWS["update_tws.c / update_tws_new.c"]
        FS["fs_update.c / expand_zone_file_update.c"]
        TESTBOX["testbox_update.c"]
    end

    subgraph sg_Engine["双备份升级引擎 (db_update_*) 与 Loader"]
        DB_API["db_update_init/write/verify"]
        LOADER["LOADER.BIN / ota.bin"]
        BANK_A["Bank A (当前固件)"]
        BANK_B["Bank B (目标固件)"]
        BOOTINFO["Boot Info 区域"]
    end

    APP --> MODE_API
    APP --> UFW
    MODE_API --> PARAM
    PARAM --> RESULT
    RESULT --> BOOTCHK
    MODE_API --> HWCLOSE

    PARAM -.->|"跳转 Loader"| LOADER
    UART --> DB_API
    NET --> DB_API
    NOR --> DB_API
    USB_SD --> DB_API
    TWS --> DB_API
    FS --> DB_API
    TESTBOX --> DB_API
    DB_API --> BANK_A
    DB_API --> BANK_B
    DB_API --> BOOTINFO
    LOADER --> DB_API

架构要点说明:

  • 应用层通过 update_mode_api_v2(type, priv_param_fill_hdl, priv_update_jump_handle) 发起升级,这是所有升级方式的统一入口(见 update.c);
  • 升级框架负责把升级类型、结果、CRC 写入 UPDATA_PARM 参数块,该参数块位于固定的 RAM 地址(UPDATA_FLAG_ADDR),用于应用与 Loader 之间的"握手";
  • 传输通道负责把新固件数据搬运到目标介质(SD 卡文件、网络缓存、NorFlash、U 盘等),最终都调用双备份引擎或 Loader 完成 Flash 编程;
  • 双备份引擎(db_update_*,见 db_updata_api.h)以"目标 Bank + Boot Info"为核心:新固件先写入备用 Bank,校验通过后再切换启动信息,保证可回退。

核心概念

UPDATA_PARM 参数块

UPDATA_PARM 是应用与 Loader 之间传递升级信息的共享结构,存放在 UPDATA_FLAG_ADDR 指向的 RAM 中,其字段包括:

字段作用
parm_type升级类型标识(如 NORFLASH_UPDATA、SD0/SD1/USB 等)
parm_result升级结果(UPDATA_NON / UPDATA_READY / UPDATA_SUCC 等)
parm_crc对整个参数块(跳过 crc 字段自身)计算的 CRC16
magic参数魔数 UPDATE_PARAM_MAGIC,用于合法性识别
ota_addrLoader/OTA 代码地址(来自 succ_report.loader_saddr)
parm_priv私有参数区,不同升级类型填充各自专属参数

参数块填充后必须重新计算 CRC16,见 update.c:

//fill common content \ private content \ crc16
static void update_param_content_fill(int type, UPDATA_PARM *p, void (*priv_param_fill_hdl)(UPDATA_PARM *P))
{
    if (support_norflash_update_en) {
        p->parm_type = NORFLASH_UPDATA;                                //uboot通过该标识从外挂flash读取ota.bin
        *((u16 *)((u8 *)p + sizeof(UPDATA_PARM) + 32)) = (u16)type;    //将实际的升级类型保存到UPDATA_PARM后
    } else {
        p->parm_type = (u16)type;
    }

    p->parm_result = (u16)UPDATA_READY;
    p->magic = UPDATE_PARAM_MAGIC;
    p->ota_addr = succ_report.loader_saddr;

    //支持loader放到外挂flash里ota_addr为0
    if (0 == p->ota_addr && !support_norflash_update_en) {
        log_error("ota addr err\n");
        return;
    }

    if (priv_param_fill_hdl) {
        priv_param_fill_hdl(p);
    }

    p->parm_crc = CRC16(((u8 *)p) + 2, sizeof(UPDATA_PARM) - 2);	//2 : crc_val
}

设计意图:CRC16 覆盖除 crc 字段以外的全部参数,Loader 在跳转前重新计算比对,可发现参数被踩踏或未正确初始化的情况。support_norflash_update_en 分支说明当 Loader 放在外挂 NorFlash 时,parm_type 固定为 NORFLASH_UPDATA,真实类型被保存在参数块之后 32 字节偏移处——这是一种向后兼容的"类型透传"方案。

升级结果机制与启动检查

升级结果的读写围绕 UPDATA_PARM 的 parm_result 字段展开,并在每次上电时被检查。这是"升级是否成功"这一关键状态在应用与 Loader 之间传递的唯一通道。

读取与清理结果

update_result_get() 在系统启动早期被调用:它读取 UPDATA_FLAG_ADDR 处的参数块,用 CRC16 校验(从 parm_crc 之后开始计算),校验通过后把 parm_result 存入全局标志 g_updata_flag,并将 magic 高 16 位合并进去,随后立即清零参数块,防止重复消费(见 update.c):

u16 update_result_get(void)
{
    u16 ret = UPDATA_NON;

    if (!UPDATE_SUPPORT_DEV_IS_NULL()) {
        UPDATA_PARM *p = UPDATA_FLAG_ADDR;
        u16 crc_cal;
        crc_cal = CRC16(((u8 *)p) + 2, sizeof(UPDATA_PARM) - 2);	//2 : crc_val
        if (crc_cal && crc_cal == p->parm_crc) {
            ret =  p->parm_result;
        }
        g_updata_flag = ret;
        g_updata_flag |= ((u32)(p->magic)) << 16;

        memset(p, 0x00, sizeof(UPDATA_PARM));
    }

    return ret;
}

写入结果

update_result_set(result) 写入升级结果。它特别处理了 UPDIFF_FLASH_UPDATA(差分升级)与 COMBAK_FLASH_UPDATA(组合备份升级)两种类型——这两种类型不写结果,因为其流程由 Loader 完全接管(见 update.c):

void update_result_set(u16 result)
{
    if (!UPDATE_SUPPORT_DEV_IS_NULL()) {
        UPDATA_PARM *p = UPDATA_FLAG_ADDR;

        if (p->parm_type == UPDIFF_FLASH_UPDATA || p->parm_type == COMBAK_FLASH_UPDATA) {
            log_info("update updiff/combak\n");
            return;
        }

        /* memset(p, 0x00, sizeof(UPDATA_PARM)); */
        p->parm_result = result;
        p->parm_crc = CRC16(((u8 *)p) + 2, sizeof(UPDATA_PARM) - 2);
    }
}

启动期检查函数

函数行为用途
update_success_boot_check()若结果为 UPDATA_SUCC 且类型是 SD0/SD1/USB 升级,返回 true避免成功升级后重复升级
device_is_first_start()判断 DEVICE_FIRST_START、DEVICE_UPDATE_KEY_ERR 位或结果等于 UPDATA_SUCC识别首次启动/升级后的首次启动
update_result_deal()结果非 UPDATA_NON 时进入 while(1) 死循环并持续喂狗(wdt_clear())FPGA 环境除外;正常环境等待复位/关机处理
vm_need_recover()结果低 16 位为 UPDATA_SUCC 时返回 true通知 VM(参数区)需要恢复

关键常量定义(见 update.c):

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

设计意图:DEVICE_FIRST_START 与 DEVICE_UPDATE_KEY_ERR 作为 g_updata_flag 的高位标志,与低 16 位的升级结果并存于一个 32 位变量,使启动检查逻辑只需一次读操作即可完成多种判断,同时保持与 Loader 的位级兼容。

升级发起流程:update_mode_api_v2

update_mode_api_v2() 是应用层发起升级的统一入口,流程为:申请参数内存 → 清零 → 填充公共参数与私有参数 → 写回 RAM 参数区 → 关闭外设硬件 → 跳转 Loader。其前半段如下(见 update.c):

void update_mode_api_v2(UPDATA_TYPE type, void (*priv_param_fill_hdl)(UPDATA_PARM *p), void (*priv_update_jump_handle)(int type))
{
    u16 update_param_len = sizeof(UPDATA_PARM) + UPDATE_PRIV_PARAM_LEN;

    UPDATA_PARM *p = malloc(update_param_len);

    if (p) {
        memset((u8 *)p, 0x00, sizeof(UPDATA_PARM));
#if 0 //兼容新的ota loader
        if (support_vm_data_keep) {//单备份升级,parm_priv参数存vm_addr和vm_len到ota.bin的,传给net_ota.bin网络升级使用
            u32 vm_addr = 0, vm_len = 0;
            vm_reverse_addr_size_get(&vm_addr, &vm_len);
            memcpy(p->parm_priv, &vm_addr, sizeof(vm_addr));
            memcpy(p->parm_priv + sizeof(vm_addr), &vm_len, sizeof(vm_len));
        }
#endif
        update_param_content_fill(type, p, priv_param_fill_hdl);
        ...

跳转前的硬件收尾由 update_before_jump_common_handle() 完成:关闭 UI、local_irq_disable() 关闭中断、hwi_all_close() 关闭所有硬件中断、wifi_det_close() 关闭 WiFi 检测(见 update.c):

static void update_before_jump_common_handle(UPDATA_TYPE up_type)
{
    dev_update_close_ui();

    local_irq_disable();
    hwi_all_close();

#ifdef CONFIG_SUPPORT_WIFI_DETECT
    wifi_det_close();
#endif
    /*跳转的时候遇到死掉的情况很可能是硬件模块没关导致,加上保护可以判断哪个异常,保护的地址根据不同SDK而定*/
    /* u8 inv = 0; */
    /* mpu_set(1, (u32)&test_pro_addr, (u32)test_pro_addr, inv, "0r", DBG_FM); */
}

设计意图:跳转 Loader 前必须把中断与硬件模块全部关闭,否则 Loader 运行期间残留的中断/外设可能破坏 Flash 编程时序。注释中提到的 MPU 保护(被注释)是调试异常跳转时的可选手段。

update_close_hw() 则按名称过滤关闭除指定设备外的所有升级目标硬件驱动——例如 USB 升级时保留 USB 外设、关闭其余外设(见 update.c):

void update_close_hw(void *filter_name)
{
    const struct update_target *p;
    list_for_each_update_target(p) {
        if (memcmp(filter_name, p->name, strlen(filter_name)) != 0) {
            printf("close Hw Name : %s\n", p->name);
            p->driver_close();
        }
    }
}

双备份升级引擎 API(db_update_*)

双备份(Double Bank)升级引擎通过 sdk/include_lib/update/db_updata_api.h 暴露,是 AC792N 支持"升级失败可回退"的核心。其典型生命周期为:

  1. db_update_init(max_pkt_len) — 初始化升级任务,设定每次编程的最大包长;
  2. db_update_allow_check(fw_size) — 校验目标 Bank 是否有足够空间容纳新固件;
  3. db_update_write(data, len, write_complete_cb) — 将下载数据拷贝到临时缓冲并异步通知任务写入非易失存储(每次不超过 max_pkt_len);
  4. db_update_verify(verify_result_hdl) — 校验整个升级过程是否正确;
  5. db_update_burn_boot_info(bak_addr, bak_size, burn_boot_info_result_hdl) — 校验通过后烧录新的启动信息,使系统下次从新 Bank 启动;
  6. db_update_exit() — 退出升级任务。

辅助接口:db_update_local_crc_info() 读取本地固件 CRC;db_update_db_package_crc_info(fst_pkt, fst_len, dcrc) 解析升级包首包(至少 128 字节)中的头信息得到远端 CRC;db_update_target_base() 获取目标 Bank 基址与大小;db_update_erase_advance() / db_update_erase_all() 提前或整体擦除升级区;db_update_retry() 允许不重新传输数据包而重试上次升级;db_update_break_last_update_param() 打断上次升级参数。

完整的 API 原型见 db_updata_api.h:

/* @brief:Initializes the update task,and setting the crc value and file size of new fw;
 * @param max_ptk_len: Supported maxium length of every programming,it decides the max size of programming every time
 */
int db_update_init(u16 max_pkt_len);

/* @brief:copy the data to temporary buffer and notify task to write non-volatile storage
 * @param data:the pointer to download data
 * @param len:the length to download data, no larger than max_pkt_len
 * @param write_complete_cb:callback for programming done,return 0 if no err occurred
*/
int db_update_write(void *data, u16 len, int (*write_complete_cb)(int err));

/* @brief:After the new fw verification succeed,call this api to program the new boot info for new fw
 * @param bak_addr:bakup area for firmware-patch process
 * @param bak_size:bak area size
 * @param burn_boot_info_result_hdl:this callback for error notification
 *                                  if err equals 0,the operate to burn boot info succeed,other value means to fail.
 */
int db_update_burn_boot_info(u32 bak_addr, u32 bak_size, int (*burn_boot_info_result_hdl)(int err));

/* @brief:Verify the db update process is correct
 * @param verify_result_hdl:this callback for error notification
 */
int db_update_verify(int (*verify_result_hdl)(int ret));

/* @brief:Try to update again without tranfer package
 * @param bak_addr:bakup area for firmware-patch process
 * @param bak_size:bak area size
 * @param try_result_hdl:this callback for error notification
 *                                  ret equals 1 mean can update, 0 mean can not ,other mean error.
 */
int db_update_retry(u32 bak_addr, u32 bak_size, int (*try_result_hdl)(int ret));

CRC 信息结构体定义(见 db_updata_api.h):

/* @brief:struct for firmware crc16&crc32
 */
struct crc_info {
    u32 crc32;
    u16 crc16;
};

设计意图:db_update_retry 的存在说明引擎具备"断点续传"能力——传输中断后不必重新下载整个固件包,只要目标 Bank 内数据仍完整(CRC 可验),即可直接烧录启动信息完成升级。这对网络升级场景的弱网重试尤为重要。

升级通道矩阵

SDK 在 sdk/apps/common/update/ 下为每种传输介质提供独立实现,全部汇入同一套参数/跳转机制:

通道模块文件典型场景
UART 升级uart_update.c / uart_update_master.c产线烧录、售后串口工具
网络升级net_update.c / http_update.c / net_single_backup_update.c云端 OTA(HTTP 下载固件包)
NorFlash 升级norflash_update.c / norflash_ufw_update.c / ex_flash_file_download.cLoader 置于外挂 NorFlash 的架构
USB 升级sdk/apps/common/usb/device/msd_upgrade.cU 盘(MSD)拖固件升级
SD 卡升级sd_upgrade_impl.h(实现层)SD 卡固件包升级
TWS 升级update_tws.c / update_tws_new.c真无线耳机主耳→副耳透传升级
文件系统升级fs_update.c / expand_zone_file_update.c基于 FS 的扩展区/文件更新
测试盒升级testbox_update.c产测盒通信升级

Core Flow:一次完整升级的时序

下图以"网络/串口下载 → 双备份引擎写 Bank B → 校验 → 烧 Boot Info → 重启"为主线,展示一次典型升级的完整时序:

sequenceDiagram
    participant APP as 业务应用
    participant U as update.c 框架
    participant CH as 传输通道 (UART/HTTP/USB/SD)
    participant DB as db_update_* 引擎
    participant FL as Flash (Bank A/B + Boot Info)
    participant LD as Loader

    APP->>U: 调用 update_mode_api_v2(type, priv_fill, jump)
    U->>U: 填充 UPDATA_PARM + CRC16,写入 UPDATA_FLAG_ADDR
    U->>U: update_close_hw / 关中断 / hwi_all_close
    U->>LD: 跳转 Loader (LOADER.BIN / ota.bin)
    LD->>DB: db_update_init(max_pkt_len)
    DB->>FL: 读取本地 CRC (db_update_local_crc_info)
    CH->>DB: 传输固件数据 (db_update_write, 每包 ≤ max_pkt_len)
    DB->>FL: 写入 Bank B(异步,write_complete_cb 回调)
    CH->>DB: 数据传完
    DB->>FL: db_update_verify 校验 Bank B CRC
    alt 校验通过
        DB->>FL: db_update_burn_boot_info 烧录新 Boot Info
        FL-->>DB: 成功 (err == 0)
        DB->>LD: 结束,复位重启
        LD->>APP: 从 Bank B 启动,update_result_get 读到结果
    else 校验失败
        DB-->>CH: verify_result_hdl 报错
        CH->>CH: 可选 db_update_retry / 上报失败
        FL-->>LD: 保持旧 Boot Info,仍从 Bank A 启动
    end

流程要点:

  1. 应用层只负责组织参数与跳转,不直接操作 Flash——实际编程发生在 Loader 上下文;
  2. 数据先入 RAM 临时缓冲,再由引擎任务异步写入非易失存储,write_complete_cb 在每包编程完成后回调,便于通道层做流控;
  3. 校验通过前不碰 Boot Info,这是"升级失败仍可启动"的根因;校验失败时旧 Bank 的启动信息原封不动;
  4. 升级结果经 UPDATA_PARM.parm_result 持久化,下次启动由 update_result_get() 消费并清零。

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

升级结果非预期

  • update_result_get() 中 CRC16 不匹配时 ret 保持 UPDATA_NON,参数块被清零,系统按"无升级记录"处理——避免脏数据触发错误分支;
  • update_result_deal() 对非 UPDATA_NON/0 的结果进入死循环并喂狗,等待复位。源码注释明确提示"关机要慎重,要设置开机键",即量产中该路径依赖外部复位手段。

空间不足

db_update_allow_check(fw_size) 在写入前校验目标 Bank 容量;若新固件大于 Bank 大小,写入不得开始。调用方必须先用 db_update_target_base() 查询 Bank 基址/大小并做容量判断。

并发与异步编程

db_update_write() 是"拷贝到临时缓冲 + 异步编程"模型,len 不得超过 db_update_init 传入的 max_pkt_len,否则会破坏缓冲边界。通道层必须串行调用写接口,不能并发写多个包;编程完成信号依赖 write_complete_cb,编程期间 Flash 处于忙状态,任何并发读(如 db_update_read)都应与写互斥。

升级中断与重试

  • 传输中断:目标 Bank 数据可能不完整,但引擎支持 db_update_retry() 基于已写数据的 CRC 判断能否直接完成;
  • 需要强制重新开始:调用 db_update_break_last_update_param() 打断上次升级参数,再走完整流程;
  • 擦除时序:大面积擦除耗时较长,db_update_erase_advance() 通过 erase_state_pause 回调上报擦除进度/暂停点,便于上层维持看门狗或 UI 提示,避免擦除期间被复位。

启动边界标志

DEVICE_FIRST_START(BIT31)与 DEVICE_UPDATE_KEY_ERR(BIT30)是 g_updata_flag 中的特殊状态位:前者标识首次启动(触发 VM 恢复等初始化),后者标识升级密钥错误(如差分升级鉴权失败)。两者都使 device_is_first_start() 返回 true,引导系统走"首次启动"路径。

性能与运维注意事项

  • 包长即吞吐:db_update_init(max_pkt_len) 的 max_pkt_len 决定每次编程的数据量,直接影响写 Flash 的吞吐;增大包长可减少编程任务切换开销,但受 RAM 缓冲与通道 MTU 限制;
  • 擦除是耗时大头:升级区擦除常比写入更慢,db_update_erase_advance/db_update_erase_all 允许把擦除提前到下载之前(后台并行),以缩短用户感知的升级时间;
  • 喂狗义务:update_result_deal() 与擦除回调路径中都涉及 wdt_clear(),说明升级流程必须主动喂狗,防止长 Flash 操作触发看门狗复位;
  • 产线烧录:UART/测试盒通道面向产线,强调确定性时序;OTA(HTTP)通道面向售后,依赖 db_update_retry 提供弱网容错;
  • 调试手段:跳转死机多为外设未关闭,可用被注释的 mpu_set(...) 保护地址辅助定位异常。

扩展点

  1. 新增传输通道:仿照 sdk/apps/common/update/ 下既有通道(如 uart_update.c),实现数据获取后调用 db_update_write/verify/burn_boot_info 即可接入双备份引擎,或直接复用 update_mode_api_v2 走 Loader 流程;
  2. 私有参数扩展:通过 update_mode_api_v2 的 priv_param_fill_hdl 回调向 UPDATA_PARM.parm_priv 写入通道专属参数;若 Loader 位于外挂 NorFlash,注意 update_param_priv_fill() 会把 NorFlash 参数放在 parm_priv 前面,私有参数须追加在其后;
  3. 特殊升级类型:UPDIFF_FLASH_UPDATA(差分)与 COMBAK_FLASH_UPDATA(组合备份)不经过 update_result_set,由 Loader 全权接管,适合需要自定义回滚策略的升级;
  4. UI/状态接入:led_update_start()/led_update_finish() 与 dev_update_close_ui() 为升级过程的指示与收尾预留了钩子(当前为空实现),可在此接入 LED/屏显升级状态。

Related Links

  • 升级框架主实现:update.c
  • 双备份升级 API 头文件:db_updata_api.h
  • 升级适配层:upgrade_adapter.h
  • SD 卡升级实现:sd_upgrade_impl.h
  • USB MSD 升级:msd_upgrade.c
  • UART 升级:uart_update.c
  • 网络升级:net_update.c / http_update.c
  • NorFlash 升级:norflash_update.c / norflash_ufw_update.c
  • TWS 升级:update_tws.c / update_tws_new.c
  • SDK 总览:README.md

Configuration Options(编译期/运行时配置)

升级子系统的主要开关来自 app_config.h / 宏定义与 SDK 全局配置,源码中可直接观测到的包括:

配置/符号类型默认行为说明
UPDATE_SUPPORT_DEV_IS_NULL()宏依据目标设备判断升级支持设备是否存在;结果读写前必须判空
support_norflash_update_en常量0使能外挂 NorFlash 上的 Loader/OTA;使能时 parm_type 固定为 NORFLASH_UPDATA,真实类型偏移保存
support_vm_data_keep常量0单备份升级时是否在 parm_priv 中携带 VM 地址/长度(当前代码中该分支被 #if 0 禁用,兼容新 ota loader 用)
CONFIG_FPGA_ENABLE宏关FPGA 验证环境跳过 update_result_deal 的死循环等待
CONFIG_SUPPORT_WIFI_DETECT宏关跳转 Loader 前调用 wifi_det_close() 关闭 WiFi 检测
THIRD_PARTY_PROTOCOLS_SEL & RCSP_MODE_EN宏关使能 RCSP(杰理私有协议)时引入 rcsp_cfg.h 相关逻辑
UPDATE_PARAM_MAGIC常量—UPDATA_PARM.magic 的魔数值,Loader 侧用于参数合法性识别
UPDATE_PRIV_PARAM_LEN常量—私有参数区长度,update_mode_api_v2 按 sizeof(UPDATA_PARM) + UPDATE_PRIV_PARAM_LEN 申请内存

说明:以上符号中部分为 SDK 全局宏(由构建系统注入),本文档基于 update.c / db_updata_api.h 源码中的直接引用列出;具体数值请以对应产品的 app_config.h 与构建配置为准。

API Reference 摘要

应用层升级框架(update.c)

函数签名要点说明
update_mode_api_v2(UPDATA_TYPE type, void (*priv_param_fill_hdl)(UPDATA_PARM*), void (*priv_update_jump_handle)(int))统一升级入口:填参数 → 跳 Loader
update_result_getu16 update_result_get(void)读取并清零升级结果(带 CRC16 校验)
update_result_setvoid update_result_set(u16 result)写入升级结果(差分/组合备份类型除外)
update_success_boot_checkbool update_success_boot_check(void)成功升级后的首次启动检查
device_is_first_startbool device_is_first_start(void)首次启动/升级密钥错误判断
update_result_dealint update_result_deal(void)处理非预期结果(喂狗等待复位)
update_close_hwvoid update_close_hw(void *filter_name)关闭除指定名称外的全部升级目标硬件
update_param_priv_fill(UPDATA_PARM *p, void *priv, u16 priv_len)填充私有参数,NorFlash 模式下追加在 NorFlash 参数之后
vm_need_recoverbool vm_need_recover(void)VM 恢复判断(结果为 UPDATA_SUCC 时)

双备份升级引擎(db_updata_api.h)

函数参数返回说明
db_update_initu16 max_pkt_lenint初始化升级任务,设定每次编程最大包长
db_update_exit无int退出升级任务
db_update_local_crc_infostruct crc_info *lcrcint获取本地固件 CRC16/CRC32
db_update_db_package_crc_infou8 *fst_pkt, u32 fst_len, struct crc_info *dcrcint解析升级包首包(≥128 字节)头部得到远端 CRC
db_update_allow_checku32 fw_sizeint校验目标 Bank 空间是否足够(须在 init 之后调用)
db_update_writevoid *data, u16 len, int (*write_complete_cb)(int err)int拷贝数据到临时缓冲并异步编程,len ≤ max_pkt_len
db_update_readvoid *data, u32 len, u32 offsetint从目标 Bank 按偏移读取数据
db_update_burn_boot_infou32 bak_addr, u32 bak_size, int (*burn_boot_info_result_hdl)(int err)int校验通过后烧录新 Boot Info,err==0 表示成功
db_update_target_baseu32 *bank_base, u32 *bank_sizeint获取目标 Bank 基址与大小
db_update_verifyint (*verify_result_hdl)(int ret)int校验双备份升级过程是否正确
db_update_retryu32 bak_addr, u32 bak_size, int (*try_result_hdl)(int ret)int不重新传输数据包重试升级;ret==1 可升级、0 不可、其他为错误
db_update_break_last_update_param无int打断上次升级参数,强制重新开始
db_update_erase_advanceint (*erase_state_pause)(int ret)int提前擦除升级区,回调上报擦除进度(ret==1 结束、0 擦除中)
db_update_erase_all无void整体擦除升级区

回调语义约定(源自头文件注释):write_complete_cb/burn_boot_info_result_hdl/verify_result_hdl 中 err/ret == 0 表示成功,非 0 表示失败;try_result_hdl 中 ret == 1 表示可升级、0 表示不可、其他值表示错误。

总结

AC792N SDK 的烧录与升级能力建立在"应用层参数握手 + Loader 执行 + 双备份引擎编程"的三段式架构上:update.c 负责把升级类型、结果与 CRC 组装进 UPDATA_PARM 并跳转 Loader;db_update_* 系列 API 负责把新固件安全写入备份 Bank,校验通过后才切换 Boot Info;UART、HTTP、NorFlash、USB/SD、TWS 等通道各自负责数据搬运,最终汇聚到同一引擎。这套设计在保证多通道统一的同时,通过 CRC 保护、双 Bank 回退与断点重试,为产线与 OTA 场景提供了断电安全的升级保障。

Prev
环境搭建与编译构建
Next
文档与版本资源