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

    • SDK 概览与 AC791N 芯片平台
    • 环境搭建与编译指南
    • 烧录与固件升级
    • 工程结构导览
  • 产品方案应用

    • WiFi 摄像头方案
    • WiFi IPC 可视对讲方案
    • WiFi 故事机方案
    • 扫码枪 HID 方案
    • 开发板示例工程
  • 公共应用组件

    • 语音识别 ASR 引擎
    • LLM 与 AI 语音助手接入
    • 摄像头传感器驱动
    • UI 显示框架与驱动
    • USB 主机与设备栈
    • 文件系统与存储管理
    • 系统服务与外设管理
    • 生产测试与射频工具
  • 蓝牙协议栈

    • 经典蓝牙 BR/EDR
    • BLE 低功耗蓝牙
    • 蓝牙 Mesh 网络
    • 蓝牙扩展协议(RCSP/广播/无线麦克风)
  • WiFi 与网络协议栈

    • WiFi 驱动与网络模式
    • lwIP TCP/IP 协议栈
    • 网络安全与加密库
    • 应用层网络协议
    • 流媒体与音视频传输
    • 云平台接入 SDK
    • P2P 远程访问与设备互联
  • 芯片平台与驱动

    • wl82 平台与硬件加速
    • 外设驱动框架
    • 平台配置与固件打包工具
  • 媒体与音频引擎

    • 音频编解码与音源
    • 音效处理引擎
    • 视频与图像处理
  • 操作系统与运行时

    • 实时操作系统与 POSIX 层
    • C/C++ 运行时库
  • 开发资源与文档

    • 文档与规格书
    • 公共示例工程
    • UI 资源工程与打包
    • SDK 辅助工具与脚本

烧录与固件升级

本文档介绍 AC79NN SDK(AC79_AIoT_SDK)中从"产线烧录"到"运行时固件升级"的完整链路:基于 ISD Download 工具与 isd_config.ini 的离线烧录机制,以及基于 loader 与多通道(SD/U 盘、网络、RCSP)的固件升级机制。

Purpose and Scope

本页覆盖 AC79NN SDK 中与固件写入相关的两大机制:

  1. 烧录(Flashing):产线/开发阶段通过杰理 ISD Download 工具配合 isd_config.ini / isd_config_debug.ini 配置,把代码与资源写入 SPI Nor Flash 的完整配置体系,包括 cpu/wl82/tools/isd_config_rule.c 与 cpu/wl82/tools/isd_config_rule_loader.c 所实现的工具端规则解析。
  2. 固件升级(Firmware Upgrade):设备运行阶段通过 apps/common/update/ 升级库(如 norflash_update.c)配合分区表与 loader 实现的新固件下载、校验、落盘与启动切换机制,以及各升级通道(SD/U 盘、HTTP/FTP、RCSP 等)的入口。

明确留给兄弟页面的话题:

  • 具体某个升级通道的完整应用示例(如 apps/common/example/update/http_upgrade/ 的 ext_ota_example.c、ftp_upgrade、lc_flash_upgrade)属于各通道独立页面,本页只说明它们在升级体系中的位置与调用方式。
  • RCSP 协议(杰理私有双端通信协议)本身的报文格式与命令交互属于 RCSP 相关页面,本页仅提及 rcsp_update.c 作为升级通道之一。
  • 分区表整体设计(app_main.c 中的磁盘/分区配置)若单独成页,本页只引用其中 update / dw_update 分区条目。

Overview

在 AC79NN 这类带 SPI Nor Flash 的 AIoT SoC 上,"让固件进入芯片"分为两个截然不同的阶段:

  • 烧录(一次性的、产线/开发阶段):芯片尚未运行用户程序或处于可被工具接管的状态,上位机通过 ISD Download 工具(isd_download.exe,位于 cpu/wl82/tools/)读取 isd_config.ini 中描述的 SPI 时序、入口地址、产品标识与各 flash 区域属性,将编译产物(代码 + 资源)逐段写入 Nor Flash。这个阶段由 PC 工具主导,芯片侧的 UBOOT 配合完成。
  • 升级(运行阶段、面向终端用户):芯片已经在运行应用程序,新固件以文件形式(loader.bin 等)通过 SD 卡/U 盘、网络下载或 RCSP 通道进入系统,先写入临时区域,经 CRC16 校验后由 loader 在重启时完成新旧固件的搬运与切换。这个阶段由芯片侧固件主导,PC 工具不再参与。

两者的共同基础是地址分区约定:烧录配置(isd_config.ini 的 [RESERVED_CONFIG]、[VM_CONFIG]、[BURNER_CONFIG])和运行时分区表(app_main.c 中的 {"update", 21, 512, 32} 等条目)共同决定了哪些区域可写、哪些区域受保护、升级数据落在哪里。

Architecture

下图展示烧录与升级两条链路在系统中的整体架构与各自的关键组件:

flowchart TD
    subgraph sg_PC["PC 侧(产线/开发)"]
        ISDTool["isd_download.exe<br/>ISD Download 工具"]
        RuleLoader["isd_config_rule_loader.c<br/>配置规则加载"]
        RuleParse["isd_config_rule.c<br/>配置解析"]
    end

    subgraph sg_Flash["芯片侧(SPI Nor Flash)"]
        UBOOT["UBOOT 引导"]
        App["APP 应用固件"]
        Loader["loader.bin<br/>升级搬运器"]
        UpdateArea["update 分区"]
        VM["VM 配置区<br/>VM_CONFIG"]
        Reserved["保留区<br/>RESERVED_CONFIG"]
    end

    subgraph sg_Upgrade["运行时升级通道"]
        SDUdisk["SD/U 盘升级<br/>sd_udisk_upgrade"]
        NetUp["网络升级<br/>net_update / http_update"]
        RCSPUp["RCSP 升级<br/>rcsp_update"]
        NorUp["norflash_update.c<br/>Nor 升级核心"]
    end

    ISDTool --> RuleLoader --> RuleParse
    RuleParse -->|"isd_config.ini<br/>SPI 时序/分区属性"| ISDTool
    ISDTool -->|"下载代码/资源"| UBOOT
    UBOOT -->|"写入"| Reserved
    UBOOT -->|"写入"| VM
    UBOOT -->|"写入"| App
    UBOOT -->|"写入"| Loader

    SDUdisk --> NorUp
    NetUp --> NorUp
    RCSPUp --> NorUp
    NorUp -->|"fopen/fwrite loader.bin<br/>storage/nor_fs/C/"| Loader
    Loader -->|"重启后搬运新固件"| App
    App -->|"分区表: update 条目"| UpdateArea
    UpdateArea -->|"临时存放新固件"| Loader

架构解读:

  • PC 侧(cpu/wl82/tools/):isd_download.exe 是杰理官方烧录工具,isd_config_rule.c / isd_config_rule_loader.c 负责解析 isd_config.ini 中的规则(SPI 模式、时钟、入口地址、区域操作属性),这些规则决定了工具"怎么写、写哪里、写之前是否擦除、是否加保护"。
  • 芯片侧 Nor Flash 布局:isd_config_debug.ini 的 [RESERVED_CONFIG] 定义 BTIF/WTIF/PRCT 等保留区(含代码保护属性),[VM_CONFIG] 定义虚拟机参数存储区大小,[BURNER_CONFIG] 定义烧录器配置区;这些区域在烧录阶段一次性建立,运行阶段由 APP 与 loader 共同遵守。
  • 运行时升级:apps/common/update/norflash_update.c 是 Nor Flash 升级的核心实现,它把下载到的新固件以 loader.bin 文件形式写入 storage/nor_fs/C/,校验 CRC 后由 loader 在重启时完成搬运;SD/U 盘、网络、RCSP 只是不同"取数通道",最终都汇聚到同一套 loader 写入/校验接口。

烧录机制(ISD Download)

配置文件结构

cpu/wl82/tools/jtag/isd_config_debug.ini 是烧录配置的权威示例,文件头部注释明确说明:"配置数据按照 长度+配置名字+数据的方式存储",即工具解析时采用定长键值存储格式,键的顺序不可随意调整。整个文件按功能分为三大段:

  1. UBOOT 配置项(文件头部,注释标明"UBOOT 配置项,请勿随意调整顺序"):描述 SPI 时序参数与芯片启动参数。
  2. 产品标识区:CHIP_NAME、PID、VID,用于烧录时匹配产品。
  3. Flash 空间使用配置区([RESERVED_CONFIG]、[VM_CONFIG]、[BURNER_CONFIG]):定义各区域地址、长度与操作属性。
#####################################################    UBOOT配置项,请勿随意调整顺序    ##################################################
ENTRY=0x1D00020;//程序入口地址
SPIMD=RD_OUTPUT;	#RD_OUTPUT,RD_I/O,RD_I/O_CONTINUE
SPIDW=4; 		#[0 1 2 4]
SPICK=3;		#不能为小于3
OSC=btosc;
OSC_FREQ=24MHz; #[24MHz 12MHz]
SYS_CLK=48MHz;	#[48MHz 24MHz]
#UTTX=PA05;//uboot串口tx
#UTBD=1000000;//uboot串口波特率
RESET_PIN=PB01_00_0;	//port口_上下拉控制_边沿或者电平

来源:isd_config_debug.ini

设计意图:SPIMD/SPIDW/SPICK 决定工具以何种 SPI 读模式、数据宽度和时钟分频去访问 Nor Flash——这必须与芯片 UBOOT 的初始化时序完全一致,否则烧录后芯片无法自举;ENTRY 给出程序入口地址,RESET_PIN 则让工具能够通过 IO 控制芯片复位以进入下载模式。UTTX/UTBD 被注释掉,说明当前方案不使用 UART 下载通道(默认走 sdtap)。

Flash 分区与操作属性

配置文件的 [RESERVED_CONFIG] 区域定义烧录时对各区块的处理策略,这是"烧录"与"升级"能够共存的关键:

[RESERVED_CONFIG]
BTIF_ADR=AUTO;
BTIF_LEN=0x1000;
BTIF_OPT=1;

WTIF_ADR=BEGIN_END;
WTIF_LEN=0x1000;
WTIF_OPT=1;

PRCT_ADR=0;
PRCT_LEN=CODE_LEN;
PRCT_OPT=2;

[VM_CONFIG]
SIZE=24K;

[BURNER_CONFIG]
SIZE=32;

来源:isd_config_debug.ini

  • XXXX_ADR:区域起始地址;AUTO 表示由工具自动分配起始地址,BEGIN_END 表示紧接前一段的结束位置。
  • XXXX_LEN:区域长度;CODE_LEN 表示随代码长度而定。
  • XXXX_OPT:区域操作属性(注释中定义)——0 下载代码时擦除指定区域;1 下载代码时不操作指定区域;2 下载代码时给指定区域加上保护。

PRCT_OPT=2 表明代码区(PRCT_ADR=0、PRCT_LEN=CODE_LEN)在烧录时会被加上保护,防止运行期 APP 意外破坏自身代码;BTIF/WTIF 为保留区(蓝牙/无线相关信息),OPT=1 表示下载时跳过不操作,从而保留产线写入的射频校准数据。VM_CONFIG 的 SIZE=24K 预留虚拟机参数区,BURNER_CONFIG 的 SIZE=32 预留烧录器配置区——这些区域一旦建立,运行时升级不得越界写入。

工具端规则解析

cpu/wl82/tools/isd_config_rule.c 与 isd_config_rule_loader.c 是烧录工具侧的规则解析实现(随 SDK 以源码形式提供给客户,便于定制产线烧录流程)。isd_config_rule_loader.c 负责把配置文件加载为可执行规则,isd_config_rule.c 提供规则查询/校验逻辑;两者配合 isd_download.exe 完成"读配置 → 解析分区 → 按 OPT 执行擦除/写入/保护"的流程。工具端解析必须与芯片侧 UBOOT 对配置项顺序的预期保持一致,这正是配置文件头部反复强调"请勿随意调整顺序"的原因——配置按 长度+配置名字+数据 定长存储,顺序即协议。

固件升级机制(运行时)

Nor Flash 升级核心:norflash_update.c

运行时升级的核心实现在 apps/common/update/norflash_update.c。它通过文件系统接口把新固件写入固定路径 storage/nor_fs/C/loader.bin,并提供统一的"打开 → 写入 → 校验 → 关闭 → 启动 loader"生命周期。整个模块围绕一个全局参数结构 nor_fs_parm 工作:

typedef struct _nor_fs_part {
    u32 update_file_addr;       // 升级文件在 Flash 中的绝对地址
    u32 update_area_start_addr; // 升级区域起始地址
    u32 update_area_end_addr;   // 升级区域结束地址
} nor_fs_parm;

nor_fs_parm update_norfs_parm;

#define NORFLASH_LOADER_PATH  "storage/nor_fs/C/loader.bin"
static void *fd = NULL;
void register_loader_write_handler(u32(*hdl)(void *, u32));

来源:norflash_update.c

设计意图:升级文件落地采用"文件系统 + 固定路径"而非裸地址直写,好处是上层升级通道(SD/U 盘、网络、RCSP)可以复用同一套 fopen/fwrite/fread 接口,无需感知底层 Flash 布局;update_norfs_parm 记录了升级文件地址与升级区域边界,供校验与 loader 搬运时使用。

打开升级文件的逻辑同时完成升级区域参数的采集,并做空间预检:

int norflash_f_open(u32 loader_len)
{
    fd = fopen(NORFLASH_LOADER_PATH, "w+");
    if (!fd) {
        r_printf("update fopen err\n");
        return -1;
    } else {
        g_printf("update fopen succ\n");
        update_norfs_parm.update_file_addr = nor_get_absolute_addr();
        update_norfs_parm.update_area_start_addr = nor_get_start_addr();
        update_norfs_parm.update_area_end_addr = update_norfs_parm.update_area_start_addr + nor_get_capacity();
        if (loader_len > nor_get_capacity) {
            return -2;
        }
    }
    return 0;
}

来源:norflash_update.c

  • 返回 -1:文件创建失败(文件系统异常或路径不可写)。
  • 返回 -2:新固件长度超过升级区域容量(nor_get_capacity()),属于空间不足错误,上层应中止升级。
  • 成功时 update_file_addr 为文件绝对地址,update_area_* 界定可写范围。

写入与校验分别由 norflash_f_write 与 norflash_update_verify 承担。校验采用增量 CRC16(CRC16_with_initval),按 512 字节分块读取并滚动计算,避免一次性申请大缓冲区:

u32 norflash_update_verify(u32 loader_len, u32 loader_crc)
{
    u32 len = loader_len;
    u32 crc_temp = 0;
    if (fd) {
        fseek(fd, NOR_FS_SEEK_SET, 0);          //偏移到文件起始
        u16 r_len;

        u8 *temp_buf = malloc(512);
        if (NULL == temp_buf) {
            goto _ERR_RET;
        }
        u16 temp_buf_len = 512;

        while (len) {
            r_len = (len > temp_buf_len) ? temp_buf_len : len;

            fread(fd, temp_buf, r_len);
            crc_temp = CRC16_with_initval(temp_buf, r_len, crc_temp);

            len -= r_len;
        }
    }
    ...
    if (crc_temp == loader_crc) {
        return 0;    // 校验通过
    }
    return 1;        // 校验失败
}

来源:norflash_update.c

升级启动入口为 norflash_loader_start,它把本模块的写回调注册为 loader 的写处理器,再打开升级文件——这保证 loader 后续搬运固件时使用与下载阶段完全一致的 Flash 访问方式:

int  norflash_loader_start(u32 loader_len)
{
    register_loader_write_handler(norflash_f_write);
    return norflash_f_open(loader_len);
}

来源:norflash_update.c

升级通道汇聚

apps/common/update/ 目录下的其余文件均为不同取数通道,最终都调用上述 Nor 升级接口(或同类接口):

文件通道说明
fs_update.c文件系统升级从可访问的文件系统(SD/U 盘等)读取升级包
net_update.c / net_single_backup_update.c网络升级通过网络下载升级包,后者支持单备份方案
http_update.cHTTP 升级HTTP 协议下载,配套 apps/common/example/update/http_upgrade/ 示例
lc_flash_ufw_update.c / norflash_ufw_update.cUFW 升级解析统一固件包格式(UFW)的升级
expand_zone_file_update.c / ex_flash_file_download.c扩展区升级扩展 Flash 区文件下载
apps/common/third_party_profile/jieli/rcsp/.../rcsp_update.cRCSP 升级通过杰理 RCSP 私有协议由手机 APP 推送升级

示例入口位于 apps/common/example/update/:sd_udisk_upgrade/main.c(SD/U 盘升级)、ftp_upgrade/main.c(FTP 升级)、http_upgrade/example1~3(HTTP 升级,含 ext_ota_example.c 外部 OTA 示例)、lc_flash_upgrade/lc_flash_upgrade_test.c(LC Flash 升级测试)。这些示例展示的调用模式均为:获取新固件长度与 CRC → norflash_loader_start(len) → 分块写入 → norflash_update_verify(len, crc) → 重启进入 loader。

分区表对升级的支撑

运行时分区表在 apps/wifi_camera/app_main.c 与 apps/scan_box/app_main.c 中定义,其中 update 与 dw_update 条目为升级保留空间:

{"update",     	\t\t21,    512,   32   },
{"dw_update",     	\t\t21,    512,   32   },

来源:app_main.c

分区条目含义(名称、磁盘号/类型、扇区数、属性):update 分区为升级流程提供 512 扇区的暂存空间,属性 32 通常表示该分区可读写且仅升级流程使用;dw_update 是双备份(dual-write)场景下的镜像分区。升级包先落在此分区,校验通过后由 loader 搬运到代码区——这与烧录配置里 PRCT_OPT=2(代码区保护)形成闭环:运行期无法直接写代码区,只能经由 loader 在受控流程中切换。

Core Flow:一次典型升级的完整流程

以"SD 卡/U 盘放置升级包 → 设备检测并升级"为例,展示从取数到新固件生效的完整时序:

sequenceDiagram
    participant App as APP 应用
    participant Fs as 文件系统<br/>(storage/nor_fs)
    participant Nor as norflash_update.c
    participant Loader as loader.bin
    participant Flash as Nor Flash

    App->>Fs: 检测升级包文件 (SD/U 盘)
    App->>Nor: norflash_loader_start(loader_len)
    Nor->>Nor: register_loader_write_handler(norflash_f_write)
    Nor->>Fs: fopen("storage/nor_fs/C/loader.bin", "w+")
    Fs-->>Nor: 返回 fd,记录升级区域参数
    loop 分块写入
        App->>Nor: norflash_f_write(buff, len)
        Nor->>Fs: fwrite(fd, buff, len)
        Fs->>Flash: 写入 update 分区
    end
    App->>Nor: norflash_update_verify(loader_len, loader_crc)
    Nor->>Fs: fseek + 分块 fread
    Nor->>Nor: CRC16_with_initval 增量校验
    alt 校验通过 (crc_temp == loader_crc)
        Nor-->>App: 返回 0
        App->>App: 记录升级标志并重启
        App->>Loader: 系统重启进入 loader
        Loader->>Flash: 搬运 loader.bin 到代码区
        Loader->>App: 启动新固件
    else 校验失败
        Nor-->>App: 返回 1
        App->>App: 中止升级,保留旧固件
    end

流程要点:

  1. 取数:升级通道(SD/U 盘、网络、RCSP)只负责拿到新固件的字节流及其长度/CRC,不关心 Flash 细节。
  2. 落盘:norflash_loader_start 注册写回调并打开固定路径文件,后续所有写入经 norflash_f_write 走文件系统进入 update 分区,天然获得文件系统层的坏块/擦写管理。
  3. 校验:norflash_update_verify 用增量 CRC16 对整包重算并与下发方提供的 loader_crc 比对——先校验后切换,杜绝损坏固件进入代码区。
  4. 切换:校验通过后重启,loader 负责把暂存固件搬运到受保护的代码区。烧录配置中 PRCT_OPT=2 的写保护保证了这段搬运只能由 loader 完成,APP 无法越权改写自身。

状态视图

stateDiagram-v2
    [*] --> Idle: 系统正常运行
    Idle --> Downloading: 检测到升级包
    Downloading --> Verifying: 写入完成
    Verifying --> Ready: CRC 校验通过
    Verifying --> Idle: 校验失败(保留旧固件)
    Ready --> Rebooting: 记录标志并重启
    Rebooting --> LoaderRunning: loader 搬运固件
    LoaderRunning --> Idle: 启动新固件
    Downloading --> Idle: 空间不足/写入失败

失败路径集中在 Downloading(fopen 失败返回 -1、容量不足返回 -2、写入异常)与 Verifying(CRC 不匹配)两个状态;任何失败都回退到 Idle,旧固件不受影响。

Configuration Options

isd_config.ini(烧录配置)

以下配置项来自 isd_config_debug.ini(注释中同时解释了 PDCTNAME、BOOT_FIRST、UPVR_CTL 等可选升级控制项)。

配置项类型默认值/示例说明
ENTRY十六进制地址0x1D00020程序入口地址,UBOOT 启动跳转目标
SPIMD枚举RD_OUTPUTSPI 读模式:RD_OUTPUT / RD_I/O / RD_I/O_CONTINUE
SPIDW整数4SPI 数据宽度,可选 0/1/2/4
SPICK整数3SPI 时钟分频,不能小于 3
OSC枚举btosc晶振来源选择
OSC_FREQ频率24MHz晶振频率,可选 24MHz/12MHz
SYS_CLK频率48MHz系统主频,可选 48MHz/24MHz
UTTX / UTBD串口注释关闭UBOOT UART 下载 TX 引脚与波特率(当前方案关闭)
RESET_PINIO 定义PB01_00_0复位引脚:port口_上下拉控制_边沿或电平
sdtap整数2下载通道选择:0 关闭;1 PA9/PA10;2 USB;3 PB1/PB2;4 PB6/PB7
CHIP_NAME字符串AC693X芯片型号标识
PID字符串6939B_EARPHONE_BTxx产品 ID,格式 芯片封装_应用方向_方案名称,长度 27 字节
VID版本字符串0.0.0.1厂商版本标识,长度 27 字节
PDCTNAME字符串注释说明产品名,升级时用于匹配产品
BOOT_FIRST布尔注释说明1=代码更新后提示 APP 首次启动;0=不提示
UPVR_CTL布尔注释说明0=不允许高版本升级低版本(禁降级);1=允许降级
XXXX_ADR地址AUTO/BEGIN_END/数值区域起始地址;AUTO 由工具自动分配
XXXX_LEN长度CODE_LEN/数值区域长度;CODE_LEN 随代码长度
XXXX_OPT整数0/1/20=下载时擦除该区;1=下载时不操作;2=下载时加保护
[RESERVED_CONFIG]段BTIF/WTIF/PRCT保留区配置:BTIF/WTIF 各 0x1000 且 OPT=1;PRCT 覆盖整个代码区且 OPT=2(保护)
[VM_CONFIG] SIZE容量24K虚拟机参数存储区大小
[BURNER_CONFIG] SIZE容量32烧录器配置区大小

注意:配置按 长度+配置名字+数据 定长存储,键的顺序不可调整;工具端 isd_config_rule.c / isd_config_rule_loader.c 的解析严格依赖该顺序。

运行时升级参数(代码内)

参数类型来源/默认说明
NORFLASH_LOADER_PATH宏storage/nor_fs/C/loader.bin升级文件固定落盘路径
update_norfs_parmnor_fs_parm全局变量update_file_addr、update_area_start_addr、update_area_end_addr,记录升级区域边界
校验缓冲区动态512 字节norflash_update_verify 内 malloc(512),分块读整包
update 分区分区条目{"update", 21, 512, 32}升级暂存分区:512 扇区,属性 32
dw_update 分区分区条目{"dw_update", 21, 512, 32}双备份升级镜像分区

API Reference

以下接口来自 norflash_update.c,是各升级通道对接 Nor Flash 升级的标准入口。

int norflash_loader_start(u32 loader_len)

升级流程入口:注册写回调并打开升级文件。

参数:

  • loader_len(u32):新 loader 的长度,用于打开文件前的空间预检。

返回:

  • 0:成功,升级文件已创建,fd 可用。
  • -1:fopen 失败(文件系统异常/路径不可写)。
  • -2:loader_len 超过 nor_get_capacity(),升级区域空间不足。

说明: 内部先 register_loader_write_handler(norflash_f_write),再调用 norflash_f_open(loader_len);只有打开成功才允许后续写入。

u32 norflash_f_write(u8 *buff, u16 len)

分块写入升级数据。

参数:

  • buff(u8*):待写入数据块。
  • len(u16):块长度。

返回: 实际写入字节数;fd 为空时返回 0。

u32 norflash_update_verify(u32 loader_len, u32 loader_crc)

对已写入的整包文件做增量 CRC16 校验。

参数:

  • loader_len(u32):loader 总长度。
  • loader_crc(u32):下发方提供的期望 CRC16 值(调用 CRC16_with_initval 的初值约定)。

返回:

  • 0:校验通过(crc_temp == loader_crc)。
  • 1:校验失败,或内存申请失败、fd 无效。

内部行为: fseek 到文件起始,按 512 字节分块 fread,用 CRC16_with_initval 滚动累加 CRC;临时缓冲区用完即 free。

void norflash_update_close(void)

关闭升级文件句柄,释放 fd。升级完成或失败后应调用。

int get_nor_update_param(void *buf)

导出升级区域参数。

参数:

  • buf(void*):接收 nor_fs_parm 结构的内存指针。

返回: sizeof(nor_fs_parm);buf 为空时不拷贝。用于向 loader/上层告知升级文件的 Flash 地址与升级区域边界。

配套外部接口

  • void register_loader_write_handler(u32(*hdl)(void *, u32)):由 loader 侧实现,注册 Flash 写回调。
  • u16 CRC16_with_initval(const void *ptr, u32 len, u16 i_val):增量 CRC16 计算。
  • u32 nor_get_absolute_addr(void) / u32 nor_get_start_addr(void) / u32 nor_get_capacity(void):查询 Nor Flash 绝对地址、起始地址与容量。

Failure Modes, Edge Cases & Concurrency

以下失败模式与边界行为均可在源码中找到直接依据(norflash_update.c 的错误码与分支、isd_config_debug.ini 的注释约束)。

升级侧失败模式

失败场景源码证据行为与后果
升级文件创建失败norflash_f_open 返回 -1(r_printf("update fopen err"))升级中止;需检查文件系统挂载与 storage/nor_fs/C/ 可写性
新固件超过升级区容量norflash_f_open 返回 -2(loader_len > nor_get_capacity)升级中止,防止越界写坏相邻分区
CRC 校验失败norflash_update_verify 返回 1丢弃新固件、保留旧固件运行,不会进入重启切换
校验内存申请失败malloc(512) 返回 NULL 走 _ERR_RET返回 1 视为校验失败,安全降级
写入时 fd 无效norflash_f_write 返回 0写入静默失败,最终在校验环节暴露
升级中途断电校验/切换两阶段设计未校验通过的半包数据不会生效;若断电发生在 loader 搬运中,由 loader 的引导保护逻辑处理(见下)

边界与约束

  • 禁止降级:UPVR_CTL 注释明确 0=不允许高版本升级低版本、1=允许。默认策略为禁止降级,防止产线或用户误刷旧固件导致功能回退。
  • 首次启动提示:BOOT_FIRST 控制代码更新后 APP 是否提示"首次启动",用于升级后初始化差异化数据。
  • 代码区写保护:烧录配置 PRCT_OPT=2 在烧录时给整个代码区(PRCT_ADR=0、PRCT_LEN=CODE_LEN)加保护;BTIF/WTIF 保留区 OPT=1 保证升级不覆盖产线校准数据。
  • 配置顺序即协议:isd_config.ini 按 长度+配置名字+数据 定长存储且"请勿随意调整顺序",增删配置项必须同时修改工具端 isd_config_rule*.c 解析逻辑,否则烧录工具与 UBOOT 解析错位。
  • SPI 参数强一致:SPIMD/SPIDW/SPICK/OSC_FREQ/SYS_CLK 必须与芯片 UBOOT 初始化一致,否则"烧录成功但无法自举"。

并发与一致性

  • norflash_update.c 使用全局单实例 fd 与 update_norfs_parm,模块并非重入安全设计:同一时刻只允许一个升级通道执行升级。SD/U 盘与网络通道若同时触发,需由上层任务互斥(如升级标志/状态机)串行化,源码本身未提供加锁。
  • 校验与切换之间必须保证文件不被再次写入:norflash_update_verify 先 fseek 到文件头再顺序读取,任何并发写都会破坏 CRC 结果——这既是校验的正确性前提,也意味着写入完成到校验完成期间应停止该通道的数据流。
  • 分区表层面,update 与 dw_update 分属不同分区条目,双备份升级时两个区域可独立管理;但 loader 搬运期间不允许 APP 访问代码区,重启切换是原子的(由 boot 流程保证)。

Performance & Operational Notes

  • 内存占用:校验路径固定使用 512 字节临时缓冲,写入路径按 u16 len 分块,整包升级的内存峰值很低,适合 RAM 受限的嵌入式场景;代价是 CRC 计算与写入均为顺序 IO,整包耗时与固件大小线性相关。
  • IO 模式:升级文件经 storage/nor_fs/C/ 文件系统读写,相比裸地址直写多一层文件系统开销,但换来了坏块管理与擦写调度,对 Nor Flash 寿命更友好;norflash_loader_start 注册写回调也保证了 loader 搬运与下载阶段使用同一 Flash 访问路径。
  • 产线烧录吞吐:isd_config.ini 的 SPIDW=4、SYS_CLK=48MHz 等参数决定工具端写入速率;OPT=1(不操作)的保留区避免每次烧录都擦除校准数据,缩短产线节拍。
  • 升级通道选择:网络/HTTP 通道(net_update.c、http_update.c)适合 OTA 批量升级;SD/U 盘(fs_update.c、sd_udisk_upgrade)适合无网络环境;RCSP(rcsp_update.c)适合手机 APP 直连升级。各通道共享同一套校验/切换逻辑,业务上按产品形态选用即可。
  • 日志:关键路径有 g_printf(成功)与 r_printf(错误)日志,如 update fopen succ/err、升级区域地址打印,便于产线与现场排障。

Extension Points

  1. 自定义写回调:register_loader_write_handler(u32(*hdl)(void *, u32)) 允许替换 loader 数据写入方式,norflash_loader_start 内部已用它把 norflash_f_write 注册为默认实现;自定义通道可在不改动校验逻辑的前提下更换落盘介质。
  2. 新升级通道接入:参照 apps/common/update/ 现有实现(fs_update.c、http_update.c、net_update.c)与 apps/common/example/update/ 示例,新通道只需实现"获取新固件长度/CRC → norflash_loader_start → 分块 norflash_f_write → norflash_update_verify → 重启",即可复用全部校验与切换机制。
  3. 版本策略:UPVR_CTL(禁降级开关)与 BOOT_FIRST(首启提示)在烧录配置中开放,产品无需改代码即可调整升级策略。
  4. 分区布局:update / dw_update 分区条目位于 app_main.c 分区表,调整扇区数即可改变升级暂存容量;配合 isd_config.ini 的 [RESERVED_CONFIG] 可重新划分烧录期区域属性。

Related Links

  • 烧录工具与规则源码:isd_config_rule.c、isd_config_rule_loader.c、isd_config_debug.ini
  • 配置文件说明文档:ISD_CONFIG.INI配置文件说明.pdf
  • Nor 升级核心实现:norflash_update.c
  • 升级通道库(apps/common/update/):fs_update.c、http_update.c、net_update.c、net_single_backup_update.c、lc_flash_ufw_update.c、norflash_ufw_update.c
  • 升级示例(apps/common/example/update/):sd_udisk_upgrade/main.c、http_upgrade/example1~3、ftp_upgrade/main.c、lc_flash_upgrade/lc_flash_upgrade_test.c
  • RCSP 协议升级:rcsp_update.c
  • 分区表与 update 分区定义:app_main.c(wifi_camera)、app_main.c(scan_box)
Prev
环境搭建与编译指南
Next
工程结构导览