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

    • 项目概述与芯片支持
    • 环境搭建与工具链
    • 工程与构建系统
    • 烧录与升级工具
    • 文档与硬件资料
  • 系统架构与芯片平台

    • 芯片平台与启动流程
    • 预编译库与头文件体系
    • 消息、定时器与中断服务
    • 通用外设驱动
  • 存储与文件系统

    • 文件系统实现
    • 存储设备驱动
    • VM 参数存储系统
  • 音频处理

    • 音频解码器
    • 音频编码器
    • MIDI 合成与播放
    • 音效、变速变调与降噪
  • 语音玩具应用

    • 应用框架与状态机
    • 音乐播放与外部音源
    • MIDI 乐器模式
    • 录音应用
    • 待机、电源管理与 USB 从机
  • 小音箱应用

    • 应用框架与模式管理
    • 播放源:音乐、FM、录音与 LineIn
  • 应用层与示例工程

    • 通用 MCU 应用
  • 固件更新与补丁

    • 固件升级机制
    • AD14N 主动降噪补丁

烧录与升级工具

本文介绍 fw-AD1NN_GP-MCU_SDK(AD15N 系列)的固件烧录与升级机制:PC 端 USB 升级工具如何通过 USB MSD(Mass Storage Device)私有 SCSI 命令与芯片交互、UART 升级通道的初始化与引脚配置,以及芯片侧 UPGRADE_STATE 状态机如何决定进入升级模式还是正常运行。

Purpose and Scope

本页覆盖 SDK 中与"烧录/升级"相关的芯片侧实现与工具链使用方法:

  • USB 升级工具(强制升级工具)与芯片的通信协议 —— 私有 SCSI 命令 0xF4(FLASH 操作)与 0xFC(掩码升级);
  • 升级入口状态 UPGRADE_STATE(USB 硬键 / USB 软键 / UART 键)与 NVRAM 启动状态记录机制;
  • UART 升级通道(uart_update)的引脚配置、DMA 缓冲与初始化接口;
  • PC 端工具的获取方式与基本烧录流程(源自仓库 README.md)。

以下内容不属于本页范围,由其他目录页覆盖:文件系统(FAT/NORFS/SYDF)内部布局、外挂 Flash 驱动(norflash/)、量产工具 burner_1tuo2 的裸片烧写协议细节。

Overview

AD15N 系列芯片(CPU_SH55,以及兼容的 AD14N/SH54、AD17N/SH57、AD18N/CH58)支持两种主要的固件烧录/升级路径:

  1. USB 升级(强制升级工具):PC 上位机通过 USB 线与目标板连接。芯片在 USB Device(MSD + CDROM)模式下暴露私有 SCSI 命令接口,上位机借此直接读写内部 FLASH(0xF4),或写入"软键升级"标志后复位(0xFC),使芯片重启后自动进入升级模式。这是开发阶段最常用的烧录方式。
  2. UART 升级(串口升级):通过 UART 引脚进入升级模式,uart_update 模块提供数据收发与 DMA 缓冲,常用于无 USB 连接或生产调试场景。

设计上,SDK 采用**"状态记录 + 复位跳转"**的策略:升级请求不是直接在运行时切换 FLASH 读写路径,而是通过 nvram_set_boot_state() 将意图写入 NVRAM,再触发 chip_reset();芯片复位后由 Boot 代码读取该状态,决定进入升级模式。这样升级模式运行在干净的启动环境中,避免与应用程序的复杂状态耦合。

flowchart TD
    subgraph sg_PC["PC 上位机"]
        USB_Tool["USB 升级工具 (强制升级)"]
        Prod_Tool["生产烧写工具 (1拖2)"]
    end

    subgraph sg_Chip["目标芯片 (AD15N/SH55)"]
        subgraph sg_USB["USB Device 栈"]
            MSD["MSD (U盘) + CDROM"]
            SCSI["private_scsi_cmd<br/>私有SCSI命令"]
            FLASH_OP["scsi_flash_operations<br/>0xF4 FLASH读写"]
            MASK_UP["go_mask_usb_updata<br/>0xFC 掩码升级"]
        end
        subgraph sg_UART["UART 升级通道"]
            UART_INIT["uart_update_init<br/>引脚+DMA初始化"]
            UART_DATA["uart_update_data_deal<br/>数据解析"]
        end
        NVRAM["NVRAM 启动状态<br/>nvram_set_boot_state"]
        BOOT["Boot 代码<br/>读取状态决定启动路径"]
        APP["应用程序固件"]
    end

    USB_Tool -->|"USB线 / SCSI CBW"| MSD
    Prod_Tool -->|"USB线 / 批量烧写"| MSD
    MSD --> SCSI
    SCSI -->|"0xF4"| FLASH_OP
    SCSI -->|"0xFC"| MASK_UP
    MASK_UP -->|"写状态 + 复位"| NVRAM
    NVRAM --> BOOT
    BOOT -->|"UPGRADE_USB_SOFT_KEY"| MSD
    BOOT -->|"正常运行"| APP
    UART_Tool["串口调试/升级工具"] -->|"UART TX/RX"| UART_INIT
    UART_INIT --> UART_DATA

架构说明:上位机工具(USB 升级工具、生产烧写工具)通过 USB 枚举为 MSD/CDROM 复合设备;芯片侧 private_scsi_cmd() 是私有命令分发入口,将 0xF4 路由到 FLASH 操作、0xFC 路由到掩码升级。掩码升级与 UART 升级都只是"设置状态 + 复位",真正的升级模式由 Boot 代码在复位后进入。

USB 升级机制

编译开关与入口

USB 升级代码位于 sdk/app/bsp/common/usb/device/msd_upgrade.c,受两级宏控制:外层 TCFG_PC_ENABLE(PC 模式总开关),内层 TCFG_PC_UPDATE(升级功能开关)。两者同时使能时,文件才参与编译:

#if TCFG_PC_ENABLE

#if TCFG_PC_UPDATE
...
#else
u32 private_scsi_cmd(const struct usb_device_t *usb_device, struct usb_scsi_cbw *cbw)
{
    return FALSE;
}
#endif //PC_UPDATE_ENABLE

#endif

Source: msd_upgrade.c

当 TCFG_PC_UPDATE 未开启时,private_scsi_cmd() 退化为直接返回 FALSE 的空实现——设计意图是:不开启升级功能的量产固件不暴露任何私有命令,避免被异常指令干扰(安全与健壮性考量)。

升级状态枚举

typedef enum {
    UPGRADE_NULL = 0,
    UPGRADE_USB_HARD_KEY,
    UPGRADE_USB_SOFT_KEY,
    UPGRADE_UART_KEY,
} UPGRADE_STATE;

Source: msd_upgrade.c

四种状态分别对应:无升级请求(正常运行)、USB 硬键触发(如按住按键上电)、USB 软键触发(上位机发 0xFC 命令)、UART 键触发(串口升级)。该枚举值被写入 NVRAM,Boot 代码在复位后读取判断启动路径。

掩码升级流程(0xFC)

AT(.volatile_ram_code)
static void go_mask_usb_updata()
{
    local_irq_disable();
    /* ram_protect_close(); */
    /* hw_mmu_disable(); */
    nvram_set_boot_state(UPGRADE_USB_SOFT_KEY);

    /* JL_CLOCK->PWR_CON |= (1 << 4); */
    chip_reset();
    /* cpu_reset(); */
    while (1);
}

Source: msd_upgrade.c

关键设计点:

  • AT(.volatile_ram_code):把函数放入易失性 RAM 段执行,避免在掩码升级/复位场景下依赖可能被改写或未初始化的 Flash 代码路径,保证复位前最后一段代码稳定可执行;
  • local_irq_disable():先关中断,防止复位过程中被中断打扰导致状态写入不完整;
  • nvram_set_boot_state(UPGRADE_USB_SOFT_KEY):将升级意图写入 NVRAM(掉电保持),这是整个机制的核心——复位后 Boot 代码据此进入升级模式;
  • chip_reset() + while(1):触发复位并停在此处兜底,若复位失败不会继续执行应用代码造成混乱。

私有 SCSI 命令分发(0xF4 / 0xFC)

u32 private_scsi_cmd(const struct usb_device_t *usb_device, struct usb_scsi_cbw *cbw)
{
    void *fd = NULL;
    u32 lba;
    u8 ack[16];
    switch (cbw->operationCode) {

#if TCFG_USB_MSD_CDROM_ENABLE
    // FLASH操作接口
    case 0xF4:
        //log_info("res_upgrade\n");
        scsi_flash_operations(usb_device, cbw);
        break;
#endif
    case 0xFC:
        go_mask_usb_updata();
        break;

    default:
        return FALSE;
    }

    return TRUE;
}

Source: msd_upgrade.c

该函数接收 USB 栈解析出的 SCSI CBW(Command Block Wrapper),按 operationCode 分发:

  • 0xF4:FLASH 操作接口,仅在 TCFG_USB_MSD_CDROM_ENABLE(CDROM 复合功能)开启时可用,转交 scsi_flash_operations() 执行具体的 FLASH 读写——这也是 USB 升级工具直接烧写固件的主通道(该函数实现位于 MSD 模块,本页未展开);
  • 0xFC:掩码升级,直接调用 go_mask_usb_updata();
  • 其他命令码返回 FALSE,表示"不是我能处理的私有命令",交由标准 SCSI 处理流程,保证与标准 U 盘/CDROM 行为兼容。

UART 升级机制

UART 升级模块位于 sdk/app/bsp/common/uart_update/,提供串口升级通道的初始化与数据解析接口:

#ifndef _UART_UPDATE_
#define _UART_UPDATE_
#include "typedef.h"
#include "uart_dev.h"

#define DMA_BUF_LEN			32

#ifdef CPU_SH54
#define TCFG_UART_UPDATE_PORT		IO_PORTA_09//SH54
#endif

#ifdef CPU_SH55
#define TCFG_UART_UPDATE_PORT		IO_PORTB_09//SH55
#endif

void uart_update_data_deal(u8 *data, u8 len);
void uart_update_data_init(const uart_bus_t *ut);

void uart1_tx_rx_switch(u8 port, u8 status);
void uart_update_init(void);

#endif

Source: uart_update.h

要点:

  • DMA_BUF_LEN = 32:串口升级使用 DMA 收发,单次缓冲 32 字节,配合中断逐包处理升级数据;
  • 引脚差异:TCFG_UART_UPDATE_PORT 按芯片型号区分——SH54(AD14N)用 IO_PORTA_09,SH55(AD15N)用 IO_PORTB_09。硬件设计时必须核对目标板实际引脚;
  • 接口职责:uart_update_data_init() 绑定 UART 总线并初始化 DMA;uart_update_data_deal() 处理每包升级数据;uart1_tx_rx_switch() 用于切换 UART1 的 TX/RX 引脚复用;uart_update_init() 为总入口(引脚配置 + 通道初始化)。

核心流程:USB 升级全过程

下图展示从 PC 端 USB 升级工具到芯片进入升级模式的完整时序:

sequenceDiagram
    participant PC as USB 升级工具 (PC)
    participant USB as USB Device 栈 (MSD/CDROM)
    participant SCSI as private_scsi_cmd
    participant NVRAM as NVRAM 启动状态
    participant BOOT as Boot 代码
    participant FLASH as 内部 FLASH

    PC->>USB: 枚举 MSD/CDROM 设备
    USB-->>PC: 设备就绪 (SCSI 命令可用)
    PC->>SCSI: CBW opCode=0xF4 (FLASH 操作)
    SCSI->>FLASH: scsi_flash_operations 读写
    FLASH-->>SCSI: 数据/状态
    SCSI-->>PC: CSW 响应
    PC->>SCSI: CBW opCode=0xFC (掩码升级)
    SCSI->>NVRAM: go_mask_usb_updata: nvram_set_boot_state(UPGRADE_USB_SOFT_KEY)
    SCSI->>BOOT: chip_reset()
    BOOT->>NVRAM: 读取 boot state
    alt state == UPGRADE_USB_SOFT_KEY
        BOOT->>USB: 进入升级模式,等待 0xF4 FLASH 写入
    else state == UPGRADE_NULL
        BOOT->>FLASH: 正常启动应用固件
    end

流程解读:开发阶段烧录时,USB 升级工具先通过 0xF4 命令直接读写 FLASH 完成固件写入(首次烧录/裸片场景);0xFC 掩码升级用于让运行中的设备"主动"重启进入升级模式——设备先关中断、写 NVRAM 状态、复位,Boot 代码随后读取状态决定启动路径。两条通道合起来覆盖了"首次烧录 + 在线升级"两种典型场景。

配置选项

选项类型默认/取值说明
TCFG_PC_ENABLE宏0/1PC 模式总开关,关闭时整个 msd_upgrade.c 不参与编译
TCFG_PC_UPDATE宏0/1USB 升级功能开关,关闭时 private_scsi_cmd() 返回 FALSE,不暴露私有命令
TCFG_USB_MSD_CDROM_ENABLE宏0/1决定 0xF4 FLASH 操作接口是否注册(需 CDROM 复合功能)
TCFG_UART_UPDATE_PORTIO 枚举IO_PORTA_09(SH54) / IO_PORTB_09(SH55)UART 升级引脚,按芯片型号编译期确定
DMA_BUF_LEN宏32UART 升级 DMA 单次收发缓冲长度(字节)

说明:上述宏定义于工程配置头文件(如 usb_config.h 及板级 config),具体数值随工程模板(*_voice_toy.cbp / *_mcu.cbp)而异。

API 参考

u32 private_scsi_cmd(const struct usb_device_t *usb_device, struct usb_scsi_cbw *cbw)

USB MSD 私有 SCSI 命令分发入口,供 USB 协议栈在处理非标准命令时回调。

参数:

  • usb_device (const struct usb_device_t *):当前 USB 设备实例,用于后续 FLASH 操作的数据传输;
  • cbw (struct usb_scsi_cbw *):SCSI 命令块包装,含 operationCode 字段。

返回:

  • TRUE:命令已被本模块处理(0xF4/0xFC);
  • FALSE:未识别的命令码,交给标准 SCSI 流程。

副作用:

  • 0xFC 会写入 NVRAM 并触发芯片复位,调用后不会返回;
  • 0xF4 仅在 TCFG_USB_MSD_CDROM_ENABLE 开启时注册。

static void go_mask_usb_updata(void)

掩码升级动作:关中断 → nvram_set_boot_state(UPGRADE_USB_SOFT_KEY) → chip_reset() → while(1) 兜底。

注意: 该函数被标注 AT(.volatile_ram_code),位于易失性 RAM,复位前执行,永不返回。

void uart_update_init(void)

UART 升级总初始化入口(配置 TCFG_UART_UPDATE_PORT 引脚与 UART 通道)。

void uart_update_data_deal(u8 *data, u8 len)

处理一包 UART 升级数据(长度由 DMA 中断给出,受 DMA_BUF_LEN 约束)。

void uart_update_data_init(const uart_bus_t *ut)

绑定指定 UART 总线并初始化 DMA 收发通道。

void uart1_tx_rx_switch(u8 port, u8 status)

切换 UART1 TX/RX 引脚复用状态,用于升级模式与正常运行模式间复用同一组引脚。

失败模式与边界情况

  • 0xFC 后未进入升级模式:升级标志写在 NVRAM 后依赖 chip_reset() 生效。若复位前应用代码崩溃、NVRAM 写入失败(如掉电瞬间),设备可能直接正常启动。应对:重新执行掩码升级或改用 USB 硬键(UPGRADE_USB_HARD_KEY)进入升级模式——硬键方式不依赖 NVRAM 的运行时写入。
  • 裸片/首次烧录:全新芯片无任何固件或 NVRAM 状态,USB 软键(0xFC)无从谈起,必须使用 USB 升级工具的直接 FLASH 操作(0xF4)或生产烧写工具(burner_1tuo2,代理商处获取)完成首次编程。这也是 README 中区分"USB 升级工具"与"生产烧写工具"的原因。
  • 私有命令被误用:量产固件若意外开启 TCFG_PC_UPDATE,任何 USB 主机都可发送 0xFC 使设备复位进入升级模式(拒绝服务风险)。设计上通过编译开关隔离,量产配置应关闭该宏。
  • 引脚冲突:TCFG_UART_UPDATE_PORT 与普通 UART/GPIO 功能共用引脚,若应用代码同时占用会导致升级通道异常。uart1_tx_rx_switch() 的存在表明引脚在升级与正常运行间复用,切换时机错误会导致收发失败。
  • DMA 缓冲溢出:DMA_BUF_LEN=32 固定缓冲,若上位机单包数据超过 32 字节且 uart_update_data_deal 未做分片处理,会产生丢包——实现中需要逐包解析,实际数据协议应遵守缓冲上限。

并发与一致性

  • 中断与复位竞态:go_mask_usb_updata() 先 local_irq_disable() 再写 NVRAM、复位,正是为了避免中断服务程序在"写状态 → 复位"窗口内打断导致状态不一致;
  • USB 栈并发:private_scsi_cmd() 在 USB 中断/任务上下文中被调用,0xFC 路径不依赖任何锁(直接复位),而 0xF4 的 FLASH 操作与文件系统(FAT/NORFS/SYDF)共享内部 Flash 控制器,若应用同时读写文件系统可能产生竞争——升级操作通常在专用模式下进行(见 Boot 状态机)。

操作指南(来自仓库 README)

  1. 准备 USB 升级工具(申请链接见 README.md),安装驱动并连接目标板;
  2. 用 Code::Blocks 打开对应工程(如 AD15N_mcu.cbp),Build → Build(Ctrl+F9)编译;
  3. 编译成功后,将生成的固件通过 USB 升级工具烧录到目标板;
  4. 烧录前确保目标板已进入编程模式(USB 连接 / 按键进入);
  5. 量产场景使用生产烧写工具(代理商处获取)进行 1 拖 2 批量烧写。
# 编译示例(命令行方式,见 README 4.4 节)
cd sdk
make
# 编译产物通过 USB 升级工具烧录,工具获取见 README 3.3 节

Source: README.md

扩展点

  • 新增私有 SCSI 命令:在 private_scsi_cmd() 的 switch (cbw->operationCode) 中增加 case 分支即可扩展私有协议,返回 TRUE 表示已消费该命令;
  • 新增升级状态:扩展 UPGRADE_STATE 枚举,配合 nvram_set_boot_state() 写入,由 Boot 侧对应处理(需同步修改 Boot 代码,本仓库 sdk/app/bsp 之外的 Boot 工程不在本页范围);
  • UART 升级协议适配:通过替换 uart_update_data_deal() 的实现来适配自定义串口升级协议,无需改动 USB 路径。

Related Links

  • README.md — 工具安装与烧录流程
  • msd_upgrade.c — USB 掩码升级与私有 SCSI 命令
  • uart_update.h — UART 升级接口与引脚配置
  • uart_update.c — UART 升级实现
  • 外部文档:USB 升级工具使用说明(强制升级工具)、量产烧写工具
Prev
工程与构建系统
Next
文档与硬件资料