杰理 SDK 文档中心
首页
首页
  • 入门指南

    • SDK 概述与芯片平台
    • 环境搭建与开发工具链
    • 编译、烧录与快速开始
  • 应用层开发

    • 语音玩具应用 voice_toy
    • 扩音器应用 voice_enhanced
    • 语音功能状态机 voice_func
    • 应用公共框架与配置
  • 音频子系统

    • 音频解码器与 MIDI 播放
    • 音频编码与录音
    • 音效算法(ANS、变调、变声、混响)
    • 音频输出、功放与硬件重采样
  • 存储与文件系统

    • 文件系统层(FAT、NOR_FS、SYDF 等)
    • 存储设备与设备管理
    • 参数存储 VM 与保留区
  • 系统机制

    • 消息与事件机制
    • 电源管理与低功耗
    • 固件升级机制
    • 外设驱动(按键、红外、SPI、USB)
    • 实时时钟与定时器
  • 构建系统与工具

    • 构建系统(Makefile 与 Code::Blocks)
    • 编译后处理与语音资源打包
  • 硬件平台与文档

    • 芯片平台与启动流程
    • 硬件文档、规格书与原理图

编译后处理与语音资源打包

本文档介绍 AD24N SDK(杰理科技 GP-MCU 平台)中 sdk/app/post_build 目录下的编译后处理(post-build)流水线与语音资源打包机制:从 ELF 固件分段提取、反汇编/符号输出、多段 bin 合并,到调用 isd_download.exe 将应用与各语音资源目录烧入 NOR Flash,以及最终生成 UFW 升级固件的完整流程。

Purpose and Scope

本页覆盖以下内容:

  • download.bat 后处理脚本的完整执行流程(ELF → 段提取 → 合并 → 下载 → UFW 生成)
  • download_bat.c 脚本源码模板及其对外置 Flash 烧写(-wflash)参数的注释约定
  • 语音资源目录(dir_a、dir_song、dir_eng、dir_poetry、dir_story、dir_bin_f1x、dir_midi、dir_notice)的打包与烧录方式
  • 配套工具(isd_download.exe、ufw_maker.exe、flash_wp_tool.exe、fw_add.exe)的职责
  • 提示音生成工具(sdk/make_prompt.bat、sdk/tools/make_prompt.bat)与库合并工具(sdk/tools/utils/do_merge_libs.bat)的定位

本页不涉及:具体音频格式转换算法、uboot 引导流程(uboot.boot 的生成)、Flash 分区布局设计、以及各个语音目录内音频素材的采集/录制流程——这些属于独立话题,请参考对应目录下的工具与文档。

Overview

AD24N SDK 的构建产物是 sdk.elf(LLVM/pi32 工具链链接产物)。由于 MCU 固件需要按段(section)分别处理——代码段直接可执行、数据段需初始化、调试数据与低功耗覆盖层各有用途——SDK 提供了一组 llvm-* 工具与批处理脚本构成的"编译后处理"流水线,将 ELF 拆分为多个二进制段,再拼接为最终烧录镜像 app.bin。

语音资源的打包则采用"目录即分区"的约定:isd_download.exe 的 -res 参数接收一组目录名(dir_a dir_song dir_eng ...),工具会遍历这些目录,将其中文件组织成 Flash 上的资源分区。此外脚本还演示了三种典型的量产/升级路径:

  1. NOR Flash 直接烧录(-tonorflash):通过 UART 将 uboot、app 与语音资源整体烧入 NOR Flash;
  2. 外置 Flash 二次烧写(-wflash,注释中说明):将单个资源文件烧到外部 SPI Flash 的指定地址;
  3. UFW 升级固件生成(ufw_maker.exe -fw_to_ufw):将 jl_isd.fw 转换为可 OTA/升级的 update.ufw。

这套流程的核心设计意图是解耦:编译阶段只负责产出带完整调试信息的 ELF;后处理脚本负责"段提取 → 合并 → 烧录"等与目标硬件/量产强相关的操作,使得同一份 ELF 可以按不同量产需求(内嵌资源、外置 Flash、升级包)重复使用。

Architecture

下图展示编译后处理与语音资源打包的整体架构与数据流:

flowchart TD
    subgraph sg_Build["编译阶段 (Toolchain)"]
        LD["llvm-ld / 链接器"] --> ELF["sdk.elf"]
    end

    subgraph sg_PostBuild["post-build 后处理 (download.bat)"]
        OBJDUMP["llvm-objdump.exe"]
        OBJCOPY["llvm-objcopy.exe"]
        OBJSIZE["llvm-objsizedump.exe"]
        ELF --> OBJDUMP
        ELF --> OBJCOPY
        ELF --> OBJSIZE
        OBJDUMP --> LST["sdk.lst 反汇编"]
        OBJDUMP --> SYM["sdk.symbol.txt 符号表"]
        OBJSIZE --> TXT["sdk.txt 段大小/内存占用"]
        OBJCOPY -->|"段提取 .app_code/.data/.debug_data/.lowpower_overlay"| BINS["sdk.bin / data.bin / debug_data.bin / lowpower_overlay.bin"]
        BINS -->|"copy /b 拼接"| APP["app.bin"]
    end

    subgraph sg_Voice["语音资源打包 (voice_enhanced)"]
        APP --> APP2["voice_enhanced/app.bin"]
        DIRS["dir_a dir_song dir_eng dir_poetry<br/>dir_story dir_bin_f1x dir_midi midi_cfg dir_notice"]
        ISD["isd_download.exe"]
        APP2 --> ISD
        DIRS --> ISD
        ISD -->|"-tonorflash 烧录"| FLASH[(NOR Flash)]
        UFW["ufw_maker.exe"] -->|"-fw_to_ufw jl_isd.fw"| UFWOUT["update.ufw 升级固件"]
    end

    subgraph sg_ExtFlash["外置 Flash 烧写 (-wflash 注释约定)"]
        WFLASH["-wflash dir_song 0 [PA05_1B_NULL]"]
        WFLASH --> SPI["SPI1 端口 A/B/C/D"]
    end

    ISD -.->|"可选"| WFLASH

架构要点说明:

  • 编译与后处理分离:sdk.elf 是唯一输入,后处理脚本只依赖 C:\JL\pi32\bin 下的 LLVM 工具,不依赖编译器的链接细节;
  • 段(section)粒度处理:.app_code 为可执行代码段,.data 为需初始化的数据段,.debug_data 为调试数据,.lowpower_overlay 为低功耗覆盖层——四者通过 copy /b 按固定顺序拼接成 app.bin,顺序即地址布局,因此不得随意调整;
  • 资源目录即分区:-res 后的目录顺序决定了语音资源在 NOR Flash 中的排列顺序,midi_cfg 是 MIDI 配置文件目录;
  • 量产可选择性:-wflash(外置 Flash)与 UFW 升级包是两条独立分支,与主烧录流程解耦,由注释中的示例给出用法。

编译后处理流水线详解

后处理入口是 download.bat。脚本首先 cd /d %~dp0 切换到自身所在目录,确保所有相对路径(ELF、工具、资源目录)都相对于脚本位置解析——这是批处理脚本最常见的路径陷阱,先切目录是避免"当前工作目录不确定"问题的标准做法。

工具链定位与环境探测

set OBJDUMP=C:\JL\pi32\bin\llvm-objdump.exe
set OBJCOPY=C:\JL\pi32\bin\llvm-objcopy.exe
set OBJSIZEDUMP=C:\JL\pi32\bin\llvm-objsizedump.exe

if exist %OBJDUMP% (
set NAME=sdk
)

Source: download.bat

三组 LLVM 工具路径被硬编码为 C:\JL\pi32\bin,这是杰理 pi32 工具链的标准安装位置。if exist %OBJDUMP% 探测工具是否存在,存在则将固件名设为 sdk(对应 sdk.elf)。这个探测的目的是:只有工具链可用时才执行后处理,避免在纯文档/配置环境下误触发烧录。

ELF 段提取与调试产物生成

if exist %NAME%.elf (

%OBJDUMP% -section-headers %NAME%.elf
%OBJDUMP% -d -print-imm-hex -print-dbg %NAME%.elf > %NAME%.lst
%OBJSIZEDUMP% -lite -skip-zero -enable-dbg-info %NAME%.elf > %NAME%.txt

%OBJCOPY% -O binary -j .app_code %NAME%.elf %NAME%.bin
%OBJCOPY% -O binary -j .data %NAME%.elf data.bin
%OBJCOPY% -O binary -j .debug_data %NAME%.elf debug_data.bin
%OBJCOPY% -O binary -j .lowpower_overlay %NAME%.elf lowpower_overlay.bin

%OBJDUMP% -section-headers %NAME%.elf
%OBJDUMP% -t %NAME%.elf > %NAME%.symbol.txt

Source: download.bat

各步骤职责:

命令产物用途
llvm-objdump -section-headers终端输出打印段头,便于人工核对段布局
llvm-objdump -d -print-imm-hex -print-dbgsdk.lst反汇编列表(立即数以十六进制显示、含调试信息),用于崩溃定位与代码审查
llvm-objsizedump -lite -skip-zero -enable-dbg-infosdk.txt各段大小与内存占用统计,用于 RAM/ROM 预算检查
llvm-objcopy -O binary -j .app_codesdk.bin可执行代码段二进制
llvm-objcopy -O binary -j .datadata.bin初始化数据段二进制
llvm-objcopy -O binary -j .debug_datadebug_data.bin调试数据段二进制
llvm-objcopy -O binary -j .lowpower_overlaylowpower_overlay.bin低功耗覆盖层二进制
llvm-objdump -tsdk.symbol.txt完整符号表,用于地址反查(函数/变量↔地址)

注意 download_bat.c 模板中还有一行被注释掉的 cache_ram 段提取(/* %OBJCOPY% -O binary -j .cache_ram ... */),说明部分变体固件还会包含 .cache_ram 段,当前 SH58 工程未启用——模板与实机脚本的差异保留了可追溯性。

app.bin 多段合并

copy /b %NAME%.bin+data.bin+debug_data.bin+lowpower_overlay.bin app.bin
copy app.bin voice_enhanced/app.bin

Source: download.bat

copy /b 以二进制模式将四个段文件按固定顺序拼接为 app.bin。设计意图:

  • 段顺序(.app_code → .data → .debug_data → .lowpower_overlay)与链接脚本中的地址布局一致,isd_download.exe 会按 -app app.bin 0x40000 指定的起始地址(0x40000)将整块写入 Flash;
  • 如果某个段在链接时为空,objcopy 仍会输出一个空文件,copy /b 拼接后内容不变——这是该方案在"段可选"场景下仍能保持地址对齐的原因;
  • 紧接着 copy app.bin voice_enhanced/app.bin 将合并结果复制到语音打包目录,供下一步烧录使用,保持工作目录整洁。

语音资源打包与烧录(isd_download.exe)

烧录命令解析

cd voice_enhanced
isd_download.exe -tonorflash -dev sh58 -boot 0x304000 -div8 -wait 300 -uboot uboot.boot -app app.bin 0x40000 -res dir_a dir_song dir_eng dir_poetry dir_story dir_bin_f1x dir_midi midi_cfg dir_notice

Source: download.bat

参数含义:

参数值说明
-tonorflash—烧录目标为 NOR Flash(区别于外置 Flash / RAM 下载)
-devsh58目标芯片型号 SH58
-boot0x304000uboot 引导区在 Flash 中的地址
-div8—分频系数 8,UART 下载时序参数
-wait300等待/超时参数(毫秒级)
-ubootuboot.boot引导程序镜像文件
-appapp.bin 0x40000应用镜像及其烧录起始地址
-res目录列表语音资源目录,按序打包为 Flash 资源分区

download_bat.c 模板中还保留了 -format vm / -format all(格式化虚拟区/整片)与 -reboot 500(烧录后延迟 500ms 复位)的注释示例,量产时可取消注释启用。

语音资源目录的组织约定

voice_enhanced/ 下每个 dir_* 目录对应一类语音资源(目录结构):

目录资源类型
dir_a通用提示音(Alert/Tone)
dir_song歌曲/旋律
dir_eng英文语音
dir_poetry诗词资源
dir_story故事资源
dir_bin_f1x二进制资源(F1x 系列)
dir_midi + midi_cfgMIDI 播放资源及其配置文件
dir_notice通知/公告语音
dir_ex_flash外置 Flash 相关资源(与 -wflash 配合)

设计意图:目录名即分区标识。isd_download.exe 遍历 -res 列表时,按目录名生成资源表并写入 Flash 的资源区;应用固件通过资源名(目录名)在运行时索引这些分区。因此新增语音资源 = 新增目录或文件 + 更新 -res 参数,无需改动固件代码的 Flash 地址宏。

UFW 升级固件生成

ufw_maker.exe -fw_to_ufw jl_isd.fw
copy jl_isd.ufw update.ufw
del jl_isd.ufw

ping /n 2 127.1>null
IF EXIST null del null

Source: download.bat

ufw_maker.exe 将杰理固件格式 jl_isd.fw(由 isd_download.exe 在烧录过程中生成)转换为可分发升级的 UFW 格式,并统一命名为 update.ufw(OTA 升级约定的文件名)。末尾的 ping /n 2 127.1>null 是批处理中常见的延时技巧(约 1 秒),用于等待工具刷新文件句柄后清理临时文件。

Core Flow — 从构建产物到量产固件的完整时序

sequenceDiagram
    participant Dev as 开发者
    participant Elf as sdk.elf
    participant Obj as llvm-objcopy/objdump
    participant Bat as download.bat
    participant Isd as isd_download.exe
    participant Flash as NOR Flash
    participant Ufw as ufw_maker.exe

    Dev->>Bat: 双击/CI 执行 download.bat
    Bat->>Elf: 探测工具链 & sdk.elf 存在?
    alt 工具链或 ELF 缺失
        Bat-->>Dev: 跳过后处理(静默退出)
    else 正常路径
        Bat->>Obj: 反汇编 + 段大小统计 + 符号表
        Obj-->>Bat: sdk.lst / sdk.txt / sdk.symbol.txt
        Bat->>Obj: 提取 .app_code/.data/.debug_data/.lowpower_overlay
        Obj-->>Bat: 4 个段 bin
        Bat->>Bat: copy /b 拼接为 app.bin
        Bat->>Isd: 进入 voice_enhanced 并调用 -tonorflash 烧录
        Isd->>Flash: 写 uboot@0x304000 / app@0x40000 / 语音资源分区
        Isd-->>Bat: 生成 jl_isd.fw
        Bat->>Ufw: -fw_to_ufw jl_isd.fw
        Ufw-->>Bat: update.ufw(升级固件)
        Bat-->>Dev: 流程结束(可选 -reboot 复位)
    end

时序要点:后处理脚本是"顺序执行"的批处理,任何一步失败(工具缺失、ELF 不存在、烧录失败)都会中断后续步骤——这既是简单可靠的设计,也意味着量产环境必须保证工具路径与串口/芯片连接就绪。

外置 Flash 烧写(-wflash)约定

download_bat.c 源码模板中对 -wflash 命令有详细的注释约定(见 download_bat.c):

@rem -wflash dir_song 0 [PA05_1B_NULL]
@rem //   dir_song : 要烧写的文件名(文件需在download.bat文件夹下)
@rem //   0        : 文件烧录到外置flash的起始地址
@rem //   [PA05_1B_NULL]: PA05:外置flash片选引脚(注意:不能选USBDP/USBDM)
@rem //                  1B  :spi1 ,B端口
@rem //                  NULL: power_io & spi1_data_width,power_io连接到外置flash vcc引脚 可控制flash电源;spi1_data_width:0:单线;1:双向

Source: download_bat.c

该命令的三段式参数设计:

  1. 文件名:要烧写的资源文件(如 dir_song 目录下的文件),须位于 download.bat 所在目录;
  2. 起始地址:文件在外置 Flash 中的偏移;
  3. 引脚描述串 [PA05_1B_NULL]:由三部分组成——
    • 片选引脚(如 PA05,禁止使用 USBDP/USBDM,否则影响 USB 功能);
    • SPI 端口(1B = SPI1 B 端口;1A = SPI1 A 端口);
    • power_io 与 spi1_data_width:power_io 接外置 Flash VCC 可控制供电;spi1_data_width 为 0 表示单线模式、1 表示双向模式。

注释还给出了 SPI 端口与引脚映射(download_bat.c):

SPI 端口CLK / DO / DI 引脚
APB00 / PB01 / PB02
BPA14 / PA15 / PA13
CPA06 / PA07 / PA08
DPB08 / PB09 / PB07

设计意图:外置 Flash 烧写与 NOR Flash 主烧录走的是同一条 SPI 下载链路(isd_download.exe),因此引脚描述串必须精确匹配硬件连接。power_io 支持意味着可以完全控制外置 Flash 的电源时序,这是低功耗产品(语音玩具等)的常见需求——掉电时切断 Flash 电源以降低静态功耗。

配套工具与目录说明

voice_enhanced/ 目录还包含以下工具/文件:

文件作用
fw_add.exe固件附加/合并工具(用于在固件中附加资源或校验信息)
flash_wp_tool.exeFlash 写保护工具(配合 flash_write_protect/ 使用)
flash_write_protect/flash_list_to_bin_v3.bat将 Flash 列表(0xC8671A_v3.xlsx、0xEF4017_v3.xlsx)转换为写保护参数 bin 的脚本,输出 inside_flash/flash_params_v3.bin
flash_write_protect/inside_flash/flash_params_v3.bin写保护参数文件,量产时烧入芯片用于保护关键 Flash 区域
app_ld.c应用链接配置(段布局相关)
maskrom_stubs.ldMaskROM 桩符号链接脚本

此外,SDK 根目录还提供提示音生成工具 sdk/make_prompt.bat(及 sdk/tools/make_prompt.bat)——用于将音频素材批量转换为固件可用的提示音资源,是 dir_notice/dir_a 等目录的素材来源;sdk/tools/utils/do_merge_libs.bat 用于合并静态库,属于构建期工具而非后处理范畴。

使用示例

示例 1:标准量产烧录流程(download.bat 核心命令)

以下为 AD24N SH58 工程的后处理主命令,展示了"段提取 → 合并 → 烧录 → 升级包"的完整链路:

%OBJCOPY% -O binary -j .app_code %NAME%.elf %NAME%.bin
%OBJCOPY% -O binary -j .data %NAME%.elf data.bin
%OBJCOPY% -O binary -j .debug_data %NAME%.elf debug_data.bin
%OBJCOPY% -O binary -j .lowpower_overlay %NAME%.elf lowpower_overlay.bin
copy /b %NAME%.bin+data.bin+debug_data.bin+lowpower_overlay.bin app.bin
copy app.bin voice_enhanced/app.bin

cd voice_enhanced
isd_download.exe -tonorflash -dev sh58 -boot 0x304000 -div8 -wait 300 -uboot uboot.boot -app app.bin 0x40000 -res dir_a dir_song dir_eng dir_poetry dir_story dir_bin_f1x dir_midi midi_cfg dir_notice

Source: download.bat

示例 2:外置 Flash 资源烧写(来自脚本模板注释)

当产品带外置 SPI Flash(如语音玩具扩展存储)时,取消注释并使用如下命令将单个资源烧到外置 Flash 指定地址:

@rem -wflash dir_song 0 [PA05_1B_NULL]
@rem 含义:将 dir_song 文件烧到外置 flash 起始地址 0,
@rem       片选 PA05(禁止 USBDP/USBDM),SPI1 B 端口,
@rem       power_io 可控电源,spi 双向模式

Source: download_bat.c

示例 3:UFW 升级固件生成

ufw_maker.exe -fw_to_ufw jl_isd.fw
copy jl_isd.ufw update.ufw
del jl_isd.ufw

Source: download.bat

配置选项

后处理流程的"配置"通过脚本内参数与目录结构表达,汇总如下:

配置项位置类型/默认值说明
OBJDUMP/OBJCOPY/OBJSIZEDUMPdownload.bat 头部 set路径,C:\JL\pi32\bin\llvm-*.exeLLVM 工具链路径,需与实际安装位置一致
NAMEdownload.batsdk目标 ELF 文件名(不含扩展名),由工具链探测决定
-devisd_download 参数sh58目标芯片型号
-bootisd_download 参数0x304000uboot 区起始地址
-app ... 0x40000isd_download 参数app.bin @ 0x40000应用镜像及烧录地址
-res 目录列表isd_download 参数9 个目录语音资源分区(顺序即 Flash 布局)
-div8 / -wait 300isd_download 参数—UART 下载时序参数,不同波特率/分频需调整
-format vm / -format all注释保留默认关闭烧录前格式化虚拟区/整片 Flash
-reboot 500注释保留默认关闭烧录完成后延时复位
-wflash 文件 地址 [引脚串]注释保留默认关闭外置 Flash 二次烧写

故障模式、边界情况与注意事项

以下故障模式与处理要点均从脚本源码与注释中可验证:

  1. 工具链路径错误:set OBJDUMP=... 为硬编码绝对路径。若 LLVM 工具未安装在 C:\JL\pi32\bin,if exist 探测失败,NAME 不会被赋值,后续 if exist %NAME%.elf 判断失效——脚本静默跳过整个后处理,不会报错,需要人工检查输出产物是否存在。
  2. ELF 缺失:if exist %NAME%.elf 保护了不存在 ELF 时(如纯资源工程)的执行,避免误烧旧镜像。
  3. 烧录失败无重试:isd_download.exe 失败后脚本直接退出(批处理无错误码检查),量产环境需配合外部工具(CI/产测软件)轮询 update.ufw/jl_isd.fw 产物判断成功。
  4. 段拼接顺序敏感:copy /b 的四段顺序必须与链接脚本 .app_code → .data → .debug_data → .lowpower_overlay 的地址排布一致,任何顺序调整都会导致烧录后固件错位。
  5. 片选引脚冲突:-wflash 的片选引脚禁止使用 USBDP/USBDM(注释明确标注),否则 USB 下载功能与外置 Flash 争用引脚导致烧录失败。
  6. 资源目录必须存在:-res 列出的目录(如 dir_song)在 isd_download.exe 执行时必须存在且可读,缺失会导致资源分区打包失败。
  7. 延时清理:ping /n 2 127.1>null 的 1 秒延时用于等待 ufw_maker.exe 关闭文件句柄,删除 jl_isd.ufw 时若文件仍被占用会残留临时文件——这是批处理无进程等待原语下的实用妥协。

并发与一致性说明

  • 后处理脚本为单进程顺序执行,无并发逻辑;量产时多台机器并行烧录是各自独立的进程实例,互不影响;
  • app.bin 与 update.ufw 是幂等产物:同一 ELF 多次运行脚本产出相同的烧录镜像,方便重复烧录与升级验证;
  • Flash 写保护参数(flash_params_v3.bin)由 flash_list_to_bin_v3.bat 依据 Excel 列表生成,保护区域的变更必须重新生成参数并整体烧录,避免"部分更新"导致保护配置不一致。

扩展点

  • 新增语音资源:在 voice_enhanced/ 下新建 dir_xxx 目录并加入 -res 列表即可,无需改动固件代码;
  • 新增段:仿照 .cache_ram 注释示例,在 download.bat 中增加 llvm-objcopy -j .xxx 提取并在 copy /b 拼接链中按地址顺序插入;
  • 外置 Flash 资源:通过 -wflash 与 dir_ex_flash 目录组合,可将资源与主固件分离部署,适配可插拔存储产品;
  • 升级渠道:UFW 产物 update.ufw 可直接对接杰理 OTA 升级链路,量产/售后共用同一后处理脚本。

Related Links

  • download.bat(后处理主脚本)
  • download_bat.c(脚本源码模板,含 -wflash 注释约定)
  • voice_enhanced 语音资源目录
  • flash_list_to_bin_v3.bat(Flash 写保护参数生成)
  • make_prompt.bat(提示音生成工具)
  • do_merge_libs.bat(静态库合并工具)
Prev
构建系统(Makefile 与 Code::Blocks)