杰理 SDK 文档中心
首页
首页
  • fw-Bootloader:JL 系列定制 Bootloader

    • Bootloader 架构与芯片适配
    • uboot 升级协议与流程
    • 上位机升级工具
    • 编译环境与快速开始
  • ac792n-ota-loader:AC792N 系列 OTA Loader

    • 工程结构与公共运行时框架
    • SD 卡与 USB 基础升级通道
    • 安全升级通道(SD/USB)
    • 用户自定义升级通道(UART/USB HID)
    • LVGL 图形化升级界面与模拟器
  • ac791n-ota-loader:AC791N 系列 OTA Loader

    • uboot 应用框架与 WiFi 示例
    • 升级通道变体(AP/STA/USB HID)
    • 网络与系统库依赖

uboot 升级协议与流程

本页面向 fw-Bootloader 中 uboot 的在线升级(OTA)机制,完整说明上位机与设备端之间的升级协议(数据包格式、回复状态、各操作指令及其参数结构)以及端到端升级流程(通道选择、触发方式、擦除/写入/校验时序)。

Purpose and Scope

本页覆盖的内容:

  • uboot 升级协议的数据包格式(同步头、命令长度、指令、回复状态、CRC16)。
  • 全部操作指令(JL_SU_CMD_DEVICE_INIT / DEVICE_CHECK / ERASE / WRITE / FLASH_CRC / EX_KEY)的上位机参数与设备回复结构。
  • 两种升级通道(串口、USB HID)与两种升级触发方式(I/O 口检测、SDK 软件复位)的配置原理。
  • 升级主流程与 uboot 自身升级流程。

不属于本页范围、由兄弟页面承接的内容:

  • uboot 工程的搭建、编译、调试打印等具体操作步骤,请参见 uboot 升级使用说明。
  • 各芯片 OTA Loader 工程(如 ac792n-ota-loader 下的 sd_ota_update、usb_ota_update、usb_sec_ota_update 等)属于另一组页面,本页仅在涉及传输通道时引用其目录结构。

协议正文与命令结构均提取自仓库文档 uboot升级协议流程v1.1.2.md,配置说明提取自 uboot升级使用说明v1.1.2.md。

Overview

在杰理(Jieli)方案中,fw-Bootloader 是设备上电后最先运行的引导程序(uboot)。它承担两件事:一是校验并跳转 APP,二是当需要在线升级时,直接与上位机(PC 工具)交互,把新的固件烧写到 Flash 对应区域。因为升级发生在 APP 尚未运行之前,uboot 升级通道是设备「变砖」风险最低、也最可靠的升级路径。

uboot 升级采用主机-从机命令/应答模型:

  • 上位机(PC 工具,仓库中对应 pc_demo 示例)主动发起每一个命令;
  • 设备端 uboot 收到命令后执行,并使用相同指令号回包,通过 rsp_status 字段上报执行结果;
  • 全部命令包统一采用固定同步头 + 长度 + 指令 + 状态 + 参数 + CRC16 的帧格式,多字节字段为小端(little endian),校验使用 CRC-CCITT (XModem)。

整个升级流程被设计为四步循环:初始化(DEVICE_INIT)→ 校验设备(DEVICE_CHECK)→ 擦除(ERASE)→ 写入(WRITE)→ 校验(FLASH_CRC),其中擦除/写入按块循环,最终用 Flash CRC 与上位机本地数据比对来确认升级成功。EX_KEY(交换密钥)指令为安全升级预留了密钥协商能力。

协议文档中还包含两张流程图:主流程图(uboot_update_0.jpg)与 uboot 本身升级流程图(uboot_update_1.jpg),本页用 Mermaid 将其还原为可读的结构化描述。

Architecture

flowchart TD
    subgraph sg_Host["上位机 (PC 工具)"]
        Host["pc_demo 工具"]
    end

    subgraph sg_Transport["传输通道"]
        UART["串口升级<br/>USB_MODE=0"]
        USBHID["USB HID 升级<br/>USB_MODE=1"]
    end

    subgraph sg_Uboot["设备端 uboot (fw-Bootloader)"]
        Main["main 入口 / 触发检测"]
        Proto["升级协议处理<br/>JL_SU_CMD_* 指令解析"]
        FlashDrv["Flash 驱动<br/>擦除 / 写入 / CRC"]
    end

    subgraph sg_Flash["存储介质"]
        Flash[("SPI NOR Flash<br/>app 区 / uboot 区")]
    end

    Host --> UART
    Host --> USBHID
    UART --> Main
    USBHID --> Main
    Main --> Proto
    Proto --> FlashDrv
    FlashDrv --> Flash

架构要点:

  • 上位机(Host):负责把待升级固件按协议分帧下发;pc_demo 中 usb_hid 子目录的 main.cpp 定义了 USB HID 模式下的 usb_vid / usb_pid(见使用说明)。
  • 传输通道:由编译宏 USB_MODE 决定——USB_MODE=0 走串口,USB_MODE=1 走 USB HID;两套通道在协议层共用同一套 JL_SU_CMD_* 帧格式。
  • 设备端 uboot:main 函数先做触发检测(I/O 电平或升级魔数),进入升级流程后由协议处理层解析命令并驱动 Flash 驱动执行擦除、写入与 CRC 校验。
  • Flash 区域:DEVICE_INIT 回复中的 upgrade_addr / upgrade_len 描述目标区域(如 app_dir_head、uboot_zone)的地址与长度,flash_alignsize 用于对齐地址,保证擦除/写入符合 Flash 特性。

协议基础:数据包格式

所有命令包(无论上位机→设备还是设备→上位机)遵循统一帧格式,多字节数据低字节在前(小端),CRC16 采用 CRC-CCITT (XModem) 标准,回复使用与请求相同的指令号。

Byte[0]Byte[1]Byte[3~2]Byte[4]Byte[5]Byte[6~n-2]Byte[n~n-1]
syncdata0syncdata1cmd_lencmdrsp_statusparam(部分指令无)crc16
固定 0xAA固定 0x55cmd+rsp_status+union 数据长度操作指令回复状态指令参数整包(不含 CRC 自身)的 CRC16

字段设计意图:

  • syncdata0 / syncdata1(0xAA 0x55):帧同步头,接收方据此从字节流中定位帧起点;固定的魔数序列有效降低误同步概率。
  • cmd_len:只统计 cmd + rsp_status + param 的长度,不含同步头与 CRC,使接收方在收到 6 字节头之后即可确定需要继续收取多少字节。
  • cmd / rsp_status:命令号与执行结果共用同一字节位,请求时 rsp_status 通常置 0,应答时由设备写入状态值。
  • param:联合体(union)形式的指令参数,不同指令长度与含义不同;无参数指令(如 ERASE/WRITE 的应答)可省略。
  • crc16:覆盖整包其余字节,保证传输过程中命令与数据不被篡改或误码。

回复状态(rsp_status)

设备对每条命令通过 rsp_status 返回执行结果,取值定义如下(来源:协议文档第 49-61 行):

状态宏数值说明
JL_SU_CMD_SUSS0x0命令执行成功
JL_SU_CMD_CRC_ERROR0x1CRC 错误
JL_SU_CMD_SDK_ID_ERROR0x2ID 错误(SDK/设备 ID 不匹配)
JL_SU_CMD_OTHER_ERROR0x3其他错误
enum {
    JL_SU_CMD_SUSS,          //命令成功
    JL_SU_CMD_CRC_ERROR,     //CRC 出错
    JL_SU_CMD_SDK_ID_ERROR,  //ID 错误
    JL_SU_CMD_OTHER_ERROR,   //其他错误
};

Source: uboot升级协议流程v1.1.2.md

上位机应在每次收发后检查该状态:非 JL_SU_CMD_SUSS 时需根据错误类型决定重试(CRC 类)或中止升级(ID 不匹配类)。

操作指令、参数及数据方向

协议共定义 6 条指令,取值 0xC0 ~ 0xC5。下面逐条说明其上位机参数结构与设备回复结构(结构体定义均来自协议文档)。

1. JL_SU_CMD_DEVICE_INIT(0xC0)——设备初始化

获取目标 file_name 区域在 Flash 中的地址、长度等信息,是升级流程的第一步。

  • 方向:上位机 → 设备
byte[0~15]byte[16]
参数file_name[16]mode
说明区域名字读取模式:app_dir_head 设置 0,uboot_zone 设置 0
struct {
    u8 file_name[16];
    u8 mode;
} init;

Source: uboot升级协议流程v1.1.2.md

  • 方向:设备 → 上位机
byte[3~0]byte[7~4]byte[11~8]byte[15~12]
参数upgrade_addrupgrade_lenupgrade_eoffsetflash_alignsize
说明区域地址区域长度设备偏移长度对齐长度
struct {
    u32 upgrade_addr;
    u32 upgrade_len;
    u32 upgrade_eoffset;
    u32 flash_alignsize;
} init;

Source: uboot升级协议流程v1.1.2.md

flash_alignsize 是后续所有擦除/写入地址对齐的依据:上位机必须按该值对齐地址与长度,否则可能触发 JL_SU_CMD_OTHER_ERROR。

2. JL_SU_CMD_DEVICE_CHECK(0xC1)——获取设备 PID/VID/sdkID

用于身份校验,防止把 A 设备的固件刷进 B 设备。

  • 方向:上位机 → 设备
byte[3~0]
参数sdk_id
说明上位机 sdk id
struct {
    u32 sdk_id;
} device_check;

Source: uboot升级协议流程v1.1.2.md

  • 方向:设备 → 上位机
byte[0~3]byte[4~19]byte[23~20]
参数vidpidsdk_id
说明设备 vid设备 pid设备 sdk id
struct {
    u8 vid[4];
    u8 pid[16];
    u32 sdk_id;
} device_check;

Source: uboot升级协议流程v1.1.2.md

上位机比对 sdk_id 不一致时,设备会以 JL_SU_CMD_SDK_ID_ERROR 拒绝后续写入。

3. JL_SU_CMD_ERASE(0xC2)——擦除指令

按 Flash 粒度(page/sector/block)擦除指定地址,为写入做准备。

  • 方向:上位机 → 设备
byte[3~0]byte[7~4]
参数addresstype
说明擦除地址擦除类型
#define JL_ERASE_TYPE_PAGE   1   //page擦除
#define JL_ERASE_TYPE_SECTOR 2   //sector
#define JL_ERASE_TYPE_BLOCK  3   //block
struct {
    u32 address;
    u32 type;
} erase;

Source: uboot升级协议流程v1.1.2.md

  • 设备回复参数:无,仅通过 rsp_status 回复(方向:设备 → 上位机)。

4. JL_SU_CMD_WRITE(0xC3)——写指令

将固件数据写入 Flash 指定地址,是升级过程中最频繁的指令。

  • 方向:上位机 → 设备
byte[3~0]byte[7~4]byte[8~n]
参数addressdata_lengthdata[0]
说明写地址数据长度数据
struct {
    u32 address;        // 烧写FLASH地址
    u32 data_length;    //烧写长度
    u8  data[0];        // 烧写数据
} write;

Source: uboot升级协议流程v1.1.2.md

data[0] 是柔性数组用法:数据长度由帧头 cmd_len 决定,协议据此计算剩余数据字节数。上位机通常按 flash_alignsize 分块循环下发,每块等待一次 rsp_status 确认。

  • 设备回复参数:无,仅通过 rsp_status 回复(方向:设备 → 上位机)。

5. JL_SU_CMD_FLASH_CRC(0xC4)——获取设备 CRC

写入完成后,上位机请求设备对已写入区域按块计算 CRC16 并回传,用于与本地固件比对,确认升级结果。

  • 方向:上位机 → 设备
byte[3~0]byte[7~4]byte[11~8]
参数addresslenblock_size
说明需要校验的地址校验总长度单块数据校验长度
struct {
    u32 address;
    u32 len;
    u32 block_size;
} crc_list;

Source: uboot升级协议流程v1.1.2.md

  • 方向:设备 → 上位机
byte[0~n]
参数crc[0]
说明crc 列表(由 len/block_size 个 crc16 组成)
struct {
    u16 crc[0];
} crc_list;

Source: uboot升级协议流程v1.1.2.md

分块校验的设计意图:单次传输整段 CRC 不可行且无法定位错误块,按 block_size 切块后,若某一块不匹配,上位机可精确重刷该块,而不是整包重传。

6. JL_SU_CMD_EX_KEY(0xC5)——交换密钥

为加密/安全升级预留的密钥协商指令。

  • 方向:上位机 → 设备
byte[3~0]
参数secret_key
说明密钥
struct {
    u32 secret_key;
} ex_key;

Source: uboot升级协议流程v1.1.2.md

  • 方向:设备 → 上位机:回复包含 rand(随机数)、data_length、data[0] 等字段。注意:协议文档在 rand/data_length/data 之后即截断,密钥协商的完整应答结构(含随机数与密文数据如何使用)未在文档中完整展开,属于"实现细节未在源文档中提供"的部分。

核心流程

升级主流程(协议交互时序)

协议文档中的主流程图(uboot_update_0.jpg)描述的正是上位机主导的四阶段流程。用 Mermaid 时序图还原如下:

sequenceDiagram
    participant Host as 上位机 PC 工具
    participant Uboot as uboot 设备端
    participant Flash as SPI NOR Flash

    Host->>Uboot: C0 DEVICE_INIT (file_name, mode)
    Uboot-->>Host: rsp_status + upgrade_addr/len/eoffset/alignsize
    Host->>Uboot: C1 DEVICE_CHECK (sdk_id)
    Uboot-->>Host: rsp_status + vid/pid/sdk_id
    Note over Host,Uboot: sdk_id 不匹配则终止 (JL_SU_CMD_SDK_ID_ERROR)
    loop 按 flash_alignsize 分块循环
        Host->>Uboot: C2 ERASE (address, type)
        Uboot-->>Host: rsp_status
        Host->>Uboot: C3 WRITE (address, data_length, data)
        Uboot-->>Host: rsp_status
    end
    Host->>Uboot: C4 FLASH_CRC (address, len, block_size)
    Uboot-->>Host: rsp_status + crc 列表
    Host->>Host: 逐块比对 CRC,确认升级结果
    alt CRC 全部匹配
        Host->>Uboot: 复位设备运行新固件
    else 存在不匹配块
        Host->>Uboot: 重刷对应块 / 报错
    end

流程要点:

  1. DEVICE_INIT 必须最先执行——上位机只有拿到 upgrade_addr / upgrade_len / flash_alignsize 才能规划擦除与写入的地址对齐策略。
  2. DEVICE_CHECK 做身份校验,sdk_id 不匹配时设备返回 JL_SU_CMD_SDK_ID_ERROR,防止跨机型刷写。
  3. ERASE + WRITE 循环:先擦后写是 NOR Flash 的特性(只能 1→0,擦除后才能正确编程);按块执行便于出错时定点重试。
  4. FLASH_CRC 收尾:以设备侧计算出的 CRC 列表为最终依据,避免"上位机以为写成功、实际 Flash 数据不一致"的隐性故障。

uboot 自身升级流程

协议文档还单独给出了 uboot 本身升级的流程图(uboot_update_1.jpg)。与 APP 升级的区别在于:升级对象是 uboot 所在的 uboot_zone 区域,DEVICE_INIT 时通过 file_name 指定该区域即可复用同一套协议。其特殊性在于uboot 升级自身属于高风险操作——若升级过程中断电,引导程序可能不可用,因此工程上通常配合安全升级(如 ac792n-ota-loader 下的 sd_sec_ota_update、usb_sec_ota_update 等安全 OTA 工程)与密钥协商(EX_KEY)一起使用。

升级入口与触发方式流程

uboot 的 main 函数先判断是否进入升级流程,再按编译宏选择传输通道(来源:uboot升级使用说明v1.1.2.md):

flowchart TD
    Start([上电 / 复位]) --> Boot["进入 uboot main"]
    Boot --> Trigger{"触发方式"}
    Trigger -->|"I/O 口检测"| IO["检测指定 I/O 电平状态"]
    Trigger -->|"SDK 软件复位"| Magic["检测升级魔数<br/>USE_UPGRADE_MAGIC / nvram"]
    IO -->|"电平有效"| Upgrade["进入升级流程"]
    Magic -->|"魔数有效"| Upgrade
    IO -->|"无效"| RunApp["校验并跳转 APP"]
    Magic -->|"无效"| RunApp
    Upgrade --> Trans{"升级通道"}
    Trans -->|"USB_MODE=0"| UART["串口升级<br/>ut_device_mode 配置 TX/RX/波特率"]
    Trans -->|"USB_MODE=1"| USB["USB HID 升级<br/>VID/PID 需与上位机一致"]
    UART --> Proto["协议交互<br/>INIT/CHECK/ERASE/WRITE/CRC"]
    USB --> Proto
    Proto --> Verify{"CRC 校验"}
    Verify -->|"通过"| Done["升级完成 / 复位运行新固件"]
    Verify -->|"失败"| Fail["按 rsp_status 重试或报错"]

两种触发方式的取舍:

  • I/O 口检测:由硬件(按键/拨码)决定是否升级,适合产线烧录,不依赖 APP 状态。
  • SDK 软件复位触发:在 user.h 中使能 USE_UPGRADE_MAGIC 宏,SDK 侧通过往 nvram(extern u32 nvram_list[]、NV_RAM_LIST_ADDR)写入升级魔数后软复位,uboot 检测到魔数即进入升级流程——这是 OTA 升级(APP 内收到升级指令后重启进入 uboot)的典型实现。

升级模式与通道配置

uboot 升级支持串口与 USB HID 两种模式,通过编译宏切换(来源:uboot升级使用说明v1.1.2.md):

  • 串口升级模式:在 Project build options → Compiler settings → #defines 中添加 USB_MODE=0;串口引脚与波特率由 app/src/user.c 中的 ut_device_mode(tx, rx, bud) 函数设置。
  • USB HID 升级模式:在 #defines 中添加 USB_MODE=1;此时 uboot 工程的 usb_vid、usb_pid 必须与上位机(pc_demo\usb_hid\main.cpp)中的 usb_vid、usb_pid 保持一致,否则设备无法被枚举识别。

仓库中不同传输通道对应的 OTA Loader 工程分散在 ac791n-ota-loader 与 ac792n-ota-loader 目录下,例如 sd_ota_update(SD 卡升级)、usb_ota_update、usb_hid_ota_update、uart_user_update、usb_sec_ota_update / sd_sec_ota_update(安全升级)等,它们在协议层面共用本文档描述的 JL_SU_CMD_* 帧格式。

配置选项

配置项位置类型/取值默认说明
USB_MODE工程 Compiler settings → #defines0 / 1无(按需定义)0 = 串口升级模式;1 = USB HID 升级模式
ut_device_mode(tx, rx, bud)app/src/user.c函数调用无设置串口升级的 TX 脚、RX 脚与波特率
usb_vid / usb_piduboot 工程 USB 配置数值无USB HID 模式下必须与上位机 pc_demo\usb_hid\main.cpp 中的 VID/PID 一致
__DEBUG工程 Compiler settings → #defines宏未定义使能调试打印功能
isd_config.ini配置文件引脚/波特率无方式一:配置调试打印脚与波特率(main 中调用 uart_init(uttx, ut_buad))
打印脚与波特率代码直设main 函数引脚/波特率无方式二:代码中直接设置,例如 PA5、1000000 波特率
USE_UPGRADE_MAGICuser.h宏未定义使能 SDK 软件复位触发升级(配合 nvram 魔数)
I/O 触发引脚main 函数I/O 电平检测无I/O 口检测触发方式下,由电平状态决定是否进入升级流程

以上配置项位置与说明均来自 uboot升级使用说明v1.1.2.md。

API Reference:协议指令参考

指令定义值名称上位机参数(请求)设备回复参数(应答)回复状态位
JL_SU_CMD_DEVICE_INIT0xC0设备初始化file_name[16] + modeupgrade_addr / upgrade_len / upgrade_eoffset / flash_alignsize(各 u32)成功/其他错误
JL_SU_CMD_DEVICE_CHECK0xC1获取设备信息sdk_id (u32)vid[4] / pid[16] / sdk_id (u32)成功/ID 错误
JL_SU_CMD_ERASE0xC2擦除address (u32) + type (u32)无(仅状态)成功/其他错误
JL_SU_CMD_WRITE0xC3写入address (u32) + data_length (u32) + data[]无(仅状态)成功/CRC 错误/其他错误
JL_SU_CMD_FLASH_CRC0xC4Flash CRC 校验address (u32) + len (u32) + block_size (u32)crc[0](u16 列表,共 len/block_size 个)成功/其他错误
JL_SU_CMD_EX_KEY0xC5交换密钥secret_key (u32)rand (u16) / data_length (u16) / data[0](文档未完整展开)成功/其他错误

通用约定:

  • 所有多字节字段小端传输;请求与应答使用相同 cmd 指令号,以 rsp_status 区分方向与结果。
  • 无参数应答仅回 syncdata0/1 + cmd_len + cmd + rsp_status + crc16,cmd_len = 2。
  • 上位机收到 rsp_status 非 JL_SU_CMD_SUSS (0x0) 时必须处理:0x1(CRC 错误)可重发当前包;0x2(SDK ID 错误)应中止升级;0x3(其他错误)按地址/参数对齐规则排查后重试。

Usage Examples

以下示例均为协议文档中的真实结构体定义,展示了各指令参数在代码中的形态。

示例 1:擦除类型宏与擦除参数

#define JL_ERASE_TYPE_PAGE   1   //page擦除
#define JL_ERASE_TYPE_SECTOR 2   //sector
#define JL_ERASE_TYPE_BLOCK  3   //block
struct {
    u32 address;
    u32 type;
} erase;

Source: uboot升级协议流程v1.1.2.md

示例 2:写指令参数(柔性数组承载固件数据)

struct {
    u32 address;        // 烧写FLASH地址
    u32 data_length;    //烧写长度
    u8  data[0];        // 烧写数据
} write;

Source: uboot升级协议流程v1.1.2.md

示例 3:设备初始化应答(区域信息)

struct {
    u32 upgrade_addr;
    u32 upgrade_len;
    u32 upgrade_eoffset;
    u32 flash_alignsize;
} init;

Source: uboot升级协议流程v1.1.2.md

示例 4:设备信息校验应答

struct {
    u8 vid[4];
    u8 pid[16];
    u32 sdk_id;
} device_check;

Source: uboot升级协议流程v1.1.2.md

示例 5:SDK 软件复位触发(上位机/SDK 侧写法)

使用说明文档给出的 SDK 侧触发框架(任意位置添加):

extern u32 nvram_list[];
#define NV_RAM_LIST_ADDR nvram_list

Source: uboot升级使用说明v1.1.2.md

其原理是:SDK 通过 NV_RAM_LIST_ADDR(即 nvram_list)写入升级魔数后执行软复位,uboot 侧检测到魔数即进入升级流程;需配合 user.h 中的 USE_UPGRADE_MAGIC 宏使用。魔数写入的具体值在文档截断处未展示,实现细节请以 uboot 工程源码为准。

故障模式与边界情况

1. CRC 错误(JL_SU_CMD_CRC_ERROR, 0x1)

  • 触发场景:传输链路噪声(串口波特率不匹配、USB 线缆质量差)导致数据包被篡改;或写入后 Flash 数据与预期不符。
  • 处理:上位机应重发当前命令包。CRC-CCITT (XModem) 为 16 位校验,对单包数据量有限的协议足够,但上位机仍应在连续多次 CRC 失败后中止升级,避免无限重试。

2. SDK ID 错误(JL_SU_CMD_SDK_ID_ERROR, 0x2)

  • 触发场景:DEVICE_CHECK 时上位机传入的 sdk_id 与设备不符,或跨机型刷写固件。
  • 处理:这是不可恢复错误,应直接终止升级并提示用户固件与设备不匹配。设计上把 ID 校验放在擦除/写入之前,是为了在破坏 Flash 内容前尽早拦截。

3. 地址/长度对齐问题(其他错误 0x3 的常见来源)

  • DEVICE_INIT 返回的 flash_alignsize 必须用于后续所有 ERASE/WRITE/FLASH_CRC 的地址与长度对齐;未对齐的地址可能触发 Flash 驱动错误,设备回 JL_SU_CMD_OTHER_ERROR。
  • upgrade_eoffset(设备偏移长度)用于处理文件头/区域偏移,上位机计算实际烧写地址时必须计入该偏移。

4. USB HID 枚举失败

  • 触发场景:USB_MODE=1 时 uboot 的 usb_vid/usb_pid 与上位机不一致。
  • 处理:设备无法被枚举,协议无从开始。需同时修改 uboot 工程与 pc_demo\usb_hid\main.cpp 的 VID/PID 保持一致。

5. 升级中途断电 / uboot 自身升级失败

  • uboot 自身升级(uboot_zone)失败可能导致引导程序不可用,属于最高风险路径。工程上通过安全升级工程(sd_sec_ota_update、usb_sec_ota_update)与 EX_KEY 密钥协商来降低风险;协议文档未给出断电恢复(如双备份引导)的细节,实现请以对应安全 OTA 工程源码为准。

6. 并发与多设备

  • 协议为单主机-单设备、请求-应答串行模型,无并发窗口:上位机必须等待上一命令的应答后才能发送下一条。设备端天然串行处理,不存在并发写 Flash 的竞争问题;但上位机不应对同一设备并发下发命令,也不应对 rsp_status 超时处理过短(Flash 擦除耗时随 type 增大,block 擦除明显慢于 page 擦除)。

性能与运维注意

  • 写性能受擦除粒度限制:page(1)→ sector(2)→ block(3)擦除粒度递增、单次擦除耗时递增;上位机应在满足对齐要求的前提下选择尽量大的擦除类型以减少擦除次数。
  • 分块 CRC 校验:FLASH_CRC 按 block_size 分块返回 CRC 列表,校验失败时可定点重刷失败块,避免整包重传——这是大固件升级场景下收敛重试成本的关键设计。
  • 调试打印:使能 __DEBUG 后可通过 isd_config.ini 或代码直设打印脚/波特率;产线模式下建议关闭打印以减小串口带宽占用与时间开销。
  • 串口波特率:由 ut_device_mode(tx, rx, bud) 决定,波特率越高升级越快,但受链路质量约束,需与上位机保持一致。

扩展点

  • 新增指令:在 0xC0 ~ 0xC5 之外扩展指令号,遵循同一帧格式(sync + len + cmd + rsp_status + param + crc16)即可复用现有传输与校验基础设施;参数结构沿用 union 方式扩展。
  • 新区域升级:DEVICE_INIT 的 file_name 字段已抽象出区域概念(app_dir_head、uboot_zone),新增存储区域只需约定新的区域名字符串,无需改动协议。
  • 安全升级:EX_KEY 密钥协商 + sd_sec_ota_update / usb_sec_ota_update 安全工程构成加密升级扩展路径;标准协议不加密,安全升级在其上叠加密钥与密文数据。
  • 通道扩展:传输层(串口/USB HID)与协议层解耦,USB_MODE 宏切换;新增通道(如 SD 卡,见 sd_ota_update)可在不改变 JL_SU_CMD_* 帧格式的前提下接入。

测试情况说明

仓库内未发现针对本协议的自动化单元测试源码;协议正确性主要通过 fw-Bootloader/update_tools/win-uart/ 等上位机工具与真机联调验证。uboot升级使用说明v1.1.2.md 中引用的 pc_demo(含 usb_hid/main.cpp)是上位机侧的行为参考,其收发逻辑可作为协议实现的验证基准。

Related Links

  • uboot 升级使用说明 v1.1.2 —— 工程选择、升级模式、调试与触发方式配置的完整操作手册。
  • fw-Bootloader README —— Bootloader 工程总览。
  • win-uart 升级工具 README —— Windows 串口升级工具说明。
  • 相关 OTA Loader 工程:ac791n-ota-loader/、ac792n-ota-loader/(含 sd_ota_update、usb_ota_update、usb_hid_ota_update、uart_user_update、usb_sec_ota_update、sd_sec_ota_update 等子工程)。
  • 协议流程图原图:uboot_update_0.jpg(主流程)、uboot_update_1.jpg(uboot 自身升级流程)。
Prev
Bootloader 架构与芯片适配
Next
上位机升级工具