杰理 SDK 文档中心
首页
首页
  • 项目概览

    • AD16N 系列芯片与 SDK 能力总览
  • 快速开始

    • 环境搭建与编译工具链
    • 编译构建指南
    • 烧录与固件升级
  • SDK 工程架构

    • SDK 目录结构与模块分层
    • 构建系统与批处理工具
    • BSP 板级支持包
  • mbox_flash 小音箱应用

    • 应用初始化与启动流程
    • 应用配置系统
    • 按键、UI 与用户交互
  • 音频子系统

    • 音频解码框架与调度
    • 音频格式解码器实现
    • MIDI 合成与播放
    • 音频编码与录音
    • EQ/DRC 与音效处理
    • DAC/ADC 音频接口与采样
  • 存储与文件系统

    • 媒体 IO 抽象层 MIO
    • 存储设备驱动
    • 文件系统支持
  • 平台系统库

    • 系统基础服务
    • CPU 平台与运行库
    • 固件升级与更新机制
    • 蓝牙与扩展连接接口
  • 电源与低功耗管理

    • 电源管理与低功耗设计
    • 锂电池充电管理
  • 硬件与文档参考

    • SDK 文档中心与版本发布记录
    • 芯片数据手册与硬件设计参考

应用配置系统

AD16N 蓝牙音频 SoC 的 mbox_flash 应用固件配置体系,由编译期宏配置层(app_config.h)、运行期常量配置层(app_config.c)与公共配置接口层(config.h)共同构成,集中管理系统时钟、外设、电源、音频、存储、USB、日志与中断等全部应用级参数。

Purpose and Scope

本页面向「mbox_flash 应用(4-mbox-flash-app)」目录下的应用配置系统,说明:

  • app_config.h 中所有 TCFG_* / TFG_* / KEY_* / ALINK_* 等编译期宏的用途与设计意图;
  • app_config.c 中运行期常量(中断优先级、日志标签、更新通道开关、MIDI/编解码参数)的语义;
  • config.h 提供的公共日志、调试 IO 宏接口;
  • 配置如何被预处理器分发到驱动层与应用模块(编译期数据流),以及更新通道等运行期开关如何影响固件行为。

以下内容不属于本页范围,请参见对应页面:

  • 配置工具的在线 EQ 调音流程属于「配置工具 / 在线调试」相关页面;
  • USB 设备/主机协议栈细节属于 USB 相关页面;
  • 更新/OTA 的具体协议实现属于升级相关页面。

Overview

嵌入式固件的“配置系统”与传统后台服务的配置中心不同:AD16N SDK 在编译期通过大量 #define 宏将硬件选型(引脚、时钟、外设使能)静态固化进固件,在运行期通过 const 全局变量向 SDK 库导出中断优先级、日志开关、更新通道等参数。这样的设计源于 MCU 固件的三个约束:

  1. 零运行时开销:硬件引脚、时钟分频等一旦上电就必须正确,编译期常量可让编译器在优化时直接内联、消除分支;
  2. 库与应用的解耦:SDK 以静态库(libs.a)形式发布,库代码通过 extern const 引用应用侧符号,应用通过定义这些符号决定库行为(类似于弱符号覆盖机制);
  3. 单点维护:所有板级差异集中到 app_config.h / app_config.c 两个文件,换板、换方案时只需修改配置而无需改动库代码。

配置系统的三大组成:

层次文件机制作用
编译期宏层app_config.h#define + 条件编译 #if引脚、时钟、外设使能、存储介质、USB class 等板级参数
运行期常量层app_config.cconst int/u8/bool 全局符号中断优先级、日志标签、更新通道、编解码参数
公共接口层config.h宏 + extern 声明log_init 等日志接口、IO 调试宏、_OTP_CONST_ 条件修饰

Architecture

flowchart TD
    subgraph sg_Header["编译期配置层 app_config.h"]
        H_SYS["TCFG_* 系统宏<br/>时钟 / Cache / UART / 按键 / 电源"]
        H_AUD["音频宏<br/>DAC / MIC / 自动mute / EQ / ALINK"]
        H_STO["存储宏<br/>FLASH / SD / VM / ICACHE RAM"]
        H_USB["USB 宏<br/>PC / UDISK / CDROM / Device Class"]
        H_UI["UI 与更新宏<br/>LED / LCD / 升级支持"]
    end

    subgraph sg_Runtime["运行期常量层 app_config.c"]
        R_IRQ["IRQ_*_IP 中断优先级"]
        R_LOG["log_tag_const_* 日志标签开关"]
        R_UPD["CONFIG_UPDATE_* 更新通道使能"]
        R_MISC["MIDI / 编解码 / RTC / USB slave 参数"]
    end

    subgraph sg_Consumers["消费模块(SDK 库与应用)"]
        C_INIT["init_app.c 系统初始化"]
        C_APP["app.c 应用主流程"]
        C_TOOL["cfg_tools.c 在线EQ调音"]
        C_DEV["device 设备驱动 / flash_init"]
        C_KEY["key 按键驱动"]
        C_AUD["audio 音频通路"]
    end

    subgraph sg_API["公共接口层 config.h"]
        A_LOG["log_init / log_uninit / log_u8hex"]
        A_IO["IO_DEBUG_* 调试IO宏"]
        A_OTP["_OTP_CONST_ 条件修饰"]
    end

    H_SYS --> C_INIT
    H_SYS --> C_KEY
    H_AUD --> C_AUD
    H_AUD --> C_TOOL
    H_STO --> C_DEV
    H_USB --> C_APP
    H_UI --> C_APP
    R_IRQ --> C_INIT
    R_LOG --> C_APP
    R_UPD --> C_APP
    R_MISC --> C_AUD
    A_LOG --> C_APP
    A_IO --> C_INIT

架构说明:

  • **编译期配置层(app_config.h)**是配置系统的核心入口,被 SDK 中几乎所有模块通过 #include "app_config.h" 引用。它的宏按功能域分组:TCFG_* 前缀为“T 系列配置”(T 取自 Tool/Board),TFG_* 为 Flash/升级相关,ALINK_* 为音频链路相关。
  • **运行期常量层(app_config.c)**定义带 const 修饰的全局符号。SDK 静态库通过 extern 引用这些符号(例如 IRQ_USB_IP 决定 USB 中断抢占优先级),因此这些“变量”实际在链接期即被固化为常量。
  • **公共接口层(config.h)**为应用提供统一的日志与调试宏,其 DEBUG_EN 由 UART_DEBUG 宏驱动,是 app_config.h 中 UART 配置的下游消费者。
  • 底层库(libs.a)与驱动模块均直接依赖以上配置符号,因此修改配置后必须重新编译整个固件;不存在运行期热加载配置的机制。

配置分层详解

编译期宏配置层(app_config.h)

app_config.h 顶部定义了统一开关语义:ENABLE_THIS_MOUDLE / DISABLE_THIS_MOUDLE、ENABLE / DISABLE,以及哨兵值 NO_CONFIG_PORT (-1),所有模块使能宏统一使用 0/1 语义,避免混用 true/false 与 0/1 带来的可读性问题。

#define ENABLE_THIS_MOUDLE			    1
#define DISABLE_THIS_MOUDLE			    0

#define ENABLE						    1
#define DISABLE						    0

#define NO_CONFIG_PORT					(-1)

Source: app_config.h

系统时钟与 Cache

/*---------系统时钟配置---------------------*/
#define TCFG_SYS_PLL_CLK                    96000000
#define TCFG_PLL_SEL                        PLL_D1p0_192M
#define TCFG_PLL_DIV                        PLL_DIV2
#define TCFG_HSB_DIV                        HSB_DIV1

/*---------Cache Configuration--------------*/
#define CPU_USE_CACHE_WAY_NUMBER            4//cache_way范围:2~4

Source: app_config.h

系统主频通过“PLL 源选择 + 分频”两级组合得到:PLL_D1p0_192M 表示 PLL 输出 192 MHz,PLL_DIV2 二分频得到 96 MHz 系统时钟(TCFG_SYS_PLL_CLK 为注释性声明,实际生效值由分频组合决定)。CPU_USE_CACHE_WAY_NUMBER 指定 CPU 使用 4 路 cache(范围 2~4),直接影响 RAM 可用容量与代码执行性能——这是“性能与容量”权衡的典型配置点。

UART 调试口

#define TCFG_UART_TX_PORT  			    IO_PORTA_05     //串口打印发送脚配置
// #define TCFG_UART_RX_PORT  			    IO_PORTA_06     //串口打印接收脚配置
#define TCFG_UART_BAUDRATE  			1000000         //串口打印波特率配置

Source: app_config.h

mbox_flash 方案为单 TX 调试口(RX 被注释),波特率 1 Mbps,用于 log_init() 初始化的调试串口。该宏同时通过 UART_DEBUG 联动 config.h 中的 DEBUG_EN,决定日志宏是否编译进固件。

按键输入矩阵

#define KEY_DOUBLE_CLICK_EN		            DISABLE//使能按键多击
#define KEY_IO_EN         	                0//<IO按键使能
#define KEY_AD_EN			                1//<AD按键使能
#define KEY_MIC_EN                          0//<耳机按键使能
#define KEY_MATRIX_EN			            0//<矩阵按键使能
#define KEY_IR_EN			                0//<IR按键使能
#define KEY_TOUCH_EN			            0//<触摸按键使能
#define KEY_LPTOUCH_EN			            0
//AD KEY
#define AD_KEY_IO		                    IO_PORTA_08

Source: app_config.h

按键子系统采用“通道选择 + 引脚绑定”模式:KEY_*_EN 决定启用哪些物理通道(IO/AD/MIC/矩阵/IR/触摸/低功耗触摸),对应通道再绑定具体引脚(如 AD_KEY_IO = IO_PORTA_08)。mbox_flash 默认仅使能 AD 按键,触摸与矩阵通道均关闭,以节省引脚资源。

电源、低功耗与软关机

#define TCFG_VDDIOM_LEVEL		            VDDIOM_VOL_32V
#define POWER_WAKEUP_IO			            AD_KEY_IO
#define POWER_WAKEUP_EDGE			        FALLING_EDGE

#define TCFG_CONFIG_LOWPOWER_SEL            ENABLE

#define TCFG_SHUTDOWN_TIME         5000 //uint:ms

Source: app_config.h

POWER_WAKEUP_IO 直接复用 AD_KEY_IO,即 AD 按键同时承担唤醒源职责,下降沿触发——这是硬件设计上“一 IO 两用”的典型体现。TCFG_CONFIG_LOWPOWER_SEL = ENABLE 开启低功耗模式,TCFG_SHUTDOWN_TIME = 5000ms 定义无操作后软关机延时。

充电管理

#define TCFG_CHARGE_ENABLE			        0//ENABLE
#define TCFG_CHARGE_FULL_V					CHARGE_FULL_V_4199
#define TCFG_CHARGE_FULL_MA					CHARGE_FULL_mA_DIV10
#define TCFG_CHARGE_MA						CHARGE_mA_90
#define TCFG_CHARGE_TRICKLE_MA              CHARGE_mA_20

Source: app_config.h

mbox_flash 方案默认关闭片内充电(TCFG_CHARGE_ENABLE = 0),但保留完整的充电参数占位:满电电压 4.199V、恒流 90mA、涓流 20mA。这些 CHARGE_* 枚举来自 PMU 驱动,枚举值经宏转发,保证应用层与库层使用同一套电压/电流档位定义。

音频通路(DAC / MIC / 自动 mute / 淡入淡出 / EQ)

#define SR_DEFAULT                          32000
#define AMM_RS_INSIDE_ENABLE                0
#define AMM_RS_OUTSIDE_ENABLE               1
#define AMM_DIFF_ENABLE                     0

#define TCFG_AUDIO_AUTO_MUTE_ENABLE         0//不支持
#define TCFG_AUTO_MUTE_ENERGY               5//自动mute能量阈值
#define TCFG_AUTO_MUTE_TIME                 1000//自动mute的时间
#define TCFG_AUTO_UNMUTE_ENERGY             10//自动解除mute能量阈值
#define TCFG_AUTO_UNMUTE_TIME               50//自动解除mute的时间

#define TCFG_DAC_VOL_FADE_EN                DISABLE//硬件DAC淡入淡出
#define DAC_SOFT_FADE_EN                    DISABLE//软件运算淡入淡出
#define TCFG_DAC_VOL_FADE_STEP              1//0和1一样效果,配置范围0~15
#define TCFG_DAC_VOL_FADE_SLOW              15//配置范围0~15

#define TCFG_CFG_TOOL_ENABLE                DISABLE//配置工具使能,需要在线调试eq时打开,默认关闭
#define TCFG_COMM_TYPE                      TCFG_USB_COMM//暂时只支持USB通信调音

Source: app_config.h

音频配置展示了“功能开关 + 阈值参数”的配置模式:

  • AMM_RS_* 决定麦克风回采(reference sound)路径:mbox_flash 使用外侧回采(AMM_RS_OUTSIDE_ENABLE = 1),即采集环境声用于回声抑制;
  • 自动 mute 功能在 mbox_flash 上不支持(TCFG_AUDIO_AUTO_MUTE_ENABLE = 0),但阈值/时间参数已预留,换方案板时只需使能开关;
  • DAC 数字音量淡入淡出提供硬件(TCFG_DAC_VOL_FADE_EN)与软件(DAC_SOFT_FADE_EN)两种实现,STEP/SLOW 控制爬坡速率(step 范围 0~15,slow 范围 0~15),用于消除音量突变爆音;
  • TCFG_CFG_TOOL_ENABLE 控制在线 EQ 调音工具,默认关闭;开启后 config.h 同层联动的 USB_DEVICE_CLASS_CONFIG 会切换为 CDC_CLASS|AUDIO_CLASS|HID_CLASS(见下文 USB 章节),即一个宏改变 USB 枚举组合,体现宏配置的联动性。

AUDIO_LINK(音频链路)

#define ALINK_MODE_TYPE						ALINK_MD_IIS
#define ALINK_ROLE_TYPE						ALINK_ROLE_MASTER
#define ALINK_CLK_MODE_TYPE 				ALINK_CLK_FALL_UPDATE_RAISE_SAMPLE
#define ALINK_BIT_WIDE_TYPE 				ALINK_LEN_16BIT
#define ALINK_SCLK_PER_FRAME_TYPE			ALINK_FRAME_64SCLK
#define ALINK_DMA_LEN 						ALNK_BUF_POINTS_NUM * 2 * 2 * 2
#define ALINK_SR_DEFAULT 					ALINK_SR_32000
#define ALINK_MAX_CHANNEL					4
#define ALINK_MCLK_IO 						IO_PORTA_02
#define ALINK_SCLK_IO 						IO_PORTA_10
#define ALINK_LCLK_IO 						IO_PORTA_09
#define ALINK_DATA_IO0 						IO_PORTA_14
#define ALINK_DATA_IO1 						IO_PORTA_15
#define ALINK_DATA_IO2 						NULL
#define ALINK_DATA_IO3 						NULL

Source: app_config.h

AUDIO_LINK 是 AD16N 与外部 Codec/功放之间的数字音频总线。mbox_flash 配置为 I2S 主机(ALINK_MD_IIS + ALINK_ROLE_MASTER),16bit、32kHz、每帧 64 SCLK,支持最多 4 通道。ALINK_DMA_LEN 由 ALNK_BUF_POINTS_NUM 派生(128 点 × 2CH × 2Byte × 双缓冲),配置引脚则采用 IO_PORTx_yy 形式,NULL 表示未使用的数据通道——音频链路数据宽度与 DMA 缓冲深度在此一次性定型,运行期不可改。

存储介质(FLASH / SD / VM)

#define VM_SFC_ENABLE                       ENABLE
#define USE_NEW_VM     						1
#define USE_OLD_VM     						2
#define SYS_MEMORY_SELECT  					USE_NEW_VM

#if RUN_APP_CUSTOM
#define TFG_EXT_FLASH_EN				    ENABLE
#else
#define TFG_EXT_FLASH_EN				    DISABLE
#endif
#define TFG_SPI_HW_NUM					    1
#define TFG_SPI_UNIDIR_MODE_EN              DISABLE//外挂flash单线模式
#define TFG_SPI_WORK_MODE				    SPI_MODE_BIDIR_1BIT
#define TFG_SPI_CS_PORT_SEL				    IO_PORTB_00
#define TFG_SPI_CLK_PORT_SEL			    IO_PORTB_01
#define TFG_SPI_DO_PORT_SEL				    IO_PORTB_02
#define TFG_SPI_DI_PORT_SEL				    IO_PORTB_03

Source: app_config.h

存储配置体现了条件编译的复用策略:RUN_APP_CUSTOM(由构建系统传入)决定是否使能外挂 Flash 与 SD 卡——同一份 app_config.h 通过外部宏开关服务两种衍生方案。VM(Value Memory,键值存储)选择新版本(USE_NEW_VM),VM_SFC_ENABLE 表示 VM 数据区放在 SFC(SPI Flash Controller)管理的外挂 Flash 上。SPI 引脚 IO_PORTB_00~03 为外挂 Flash 的 CS/CLK/DO/DI 四线。

USB 从机配置

#if ((HAS_USB_EN) && (0 == RUN_APP_RC))
#define TCFG_PC_ENABLE						ENABLE  //PC模块使能
#define TCFG_UDISK_ENABLE					ENABLE //U盘模块使能
#define POWERDOWN_UDISK_MODE_EN             ENABLE //U盘插入时可进入pdown
#else
#define TCFG_PC_ENABLE						DISABLE
#define TCFG_UDISK_ENABLE					DISABLE
#define POWERDOWN_UDISK_MODE_EN             DISABLE
#endif
#define TCFG_USB_PORT_CHARGE                DISABLE
#define TCFG_OTG_USB_DEV_EN                 BIT(0)

#if TCFG_PC_ENABLE
#define USB_DEVICE_EN       //Enable USB SLAVE MODE
#endif
#if TCFG_UDISK_ENABLE
#define	USB_DISK_EN        //是否可以读U盘
#endif

#if TCFG_CFG_TOOL_ENABLE
#define  USB_DEVICE_CLASS_CONFIG            (CDC_CLASS|AUDIO_CLASS|HID_CLASS)
#elif defined(CONFIG_APP_OTA_EN) && (CONFIG_APP_OTA_EN == 1)
#define  USB_DEVICE_CLASS_CONFIG            (AUDIO_CLASS|HID_CLASS|CUSTOM_HID_CLASS)
#else
#define  USB_DEVICE_CLASS_CONFIG            (AUDIO_CLASS|HID_CLASS|MASSSTORAGE_CLASS)
#endif

Source: app_config.h

USB 配置是三层联动的典型:

  1. 能力层:HAS_USB_EN(全局 USB 能力)与 RUN_APP_RC(方案类型)共同决定 PC/U 盘模块是否使能,并进一步派生出 USB_DEVICE_EN / USB_DISK_EN 两个次级宏,供驱动层 #ifdef 使用;
  2. Class 层:USB_DEVICE_CLASS_CONFIG 按优先级(在线调音工具 > OTA 升级 > 默认)选择 USB 枚举的 Class 组合——同一硬件根据固件用途呈现为不同的 USB 设备形态(声卡+U 盘 / 声卡+HID 升级口 / 声卡+CDC 调音口);
  3. 电源层:TCFG_USB_PORT_CHARGE 与 POWERDOWN_UDISK_MODE_EN 决定 USB 口是否参与充电及插入 U 盘时的低功耗策略。

UI 与更新

#define TFG_DEV_UPGRADE_SUPPORT             ENABLE
#define TFG_UPGRADE_FILE_NAME               "/update.ufw"

#if RUN_APP_CUSTOM
#define LED_5X7						        ENABLE
#else
#define LED_5X7						        DISABLE
#endif
#define LCD_4X8_EN                          0
#if (LED_5X7)
#define UI_ENABLE                           ENABLE
#else
#define UI_ENABLE                           DISABLE
#endif

Source: app_config.h

TFG_DEV_UPGRADE_SUPPORT = ENABLE 开启设备升级,升级固件文件固定为根目录 /update.ufw。UI 层通过 LED_5X7/LCD_4X8_EN 派生总开关 UI_ENABLE,且 LED 5×7 点阵仅在 RUN_APP_CUSTOM 定制方案上使能——UI 使能逻辑完全由显示硬件存在性推导,避免“开了 UI 但无显示器件”的无效代码。

运行期常量配置层(app_config.c)

app_config.c 定义被 SDK 库引用的 const 全局符号。与宏不同,这些符号必须以外部链接可见(非 static),库才能通过 extern 引用。

中断优先级

//系统使用到的
const int IRQ_IRTMR_IP   = 6;
const int IRQ_AUDIO_IP   = 5;
const int IRQ_DECODER_IP = 0;
const int IRQ_WFILE_IP   = 2;
const int IRQ_RF_QUEUE_IP   = 2;
const int IRQ_ADC_IP     = 3;
const int IRQ_ENCODER_IP = 1;
const int IRQ_TICKTMR_IP = 3;
const int IRQ_USB_IP	 = 4;
const int IRQ_SD_IP		 = 3;
const int IRQ_CTMU_IP	 = 2;
const int IRQ_STREAM_IP  = 4;
const int IRQ_SPEAKER_IP = 1;
const int IRQ_LEDC_IP    = 1;
const int IRQ_SLCD_IP    = 2;
const int IRQ_PMU_TMR1_IP = 3;
const int IRQ_ALINK_IP	 = 3;
//系统还未使用到的
const int IRQ_UART0_IP   = 3;
const int IRQ_UART1_IP   = 3;
const int IRQ_ALINK0_IP  = 3;

Source: app_config.c

中断优先级采用数字越小优先级越高的嵌入式惯例(IRQ_DECODER_IP = 0 最高)。设计意图:解码器实时性最强(音频流不能断),故分配最高优先级;日志/调试相关(IRQ_UART0_IP = 3)居中;IRQ_BT_TIMEBASE_IP = 6 等 BT 相关中断在 mbox_flash 非蓝牙方案中预留。文件注释明确区分“系统使用到”与“系统还未使用到”,为裁剪提供依据。

日志标签总开关

const char libs_debug AT(.LOG_TAG_CONST) = TRUE; //打印总开关
#define  CONFIG_DEBUG_LIBS(X)   (X & libs_debug)

const char log_tag_const_i_MAIN AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIBS(1);
const char log_tag_const_d_MAIN AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIBS(1);
const char log_tag_const_e_MAIN AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIBS(1);
const char log_tag_const_c_MAIN AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIBS(1);

const char log_tag_const_i_KEYM AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIBS(1);
const char log_tag_const_d_KEYM AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIBS(0);
const char log_tag_const_e_KEYM AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIBS(0);

Source: app_config.c

日志系统通过 AT(.LOG_TAG_CONST) 段属性把每个模块的 i/d/e/c(info/debug/error/close)四个级别标签放入专用段,CONFIG_DEBUG_LIBS(X) 与 libs_debug 总开关做与运算:总开关关掉时,所有模块日志全部关闭。模块级可按需单独开 debug(如 d_MAIN 开、d_KEYM 关),在不重新编译库的前提下(符号在链接期解析)实现日志裁剪。

更新通道使能

const int CONFIG_UPDATE_STORAGE_DEV_EN = 1;
const int CONFIG_UPDATE_TESTBOX_UART_EN = 1;
const int CONFIG_UPDATE_APP_OTA_EN = 1;
const int CONFIG_UPDATE_TESTBOX_BLE_EN = 1;

Source: app_config.c

mbox_flash 同时使能四条升级通道:本地存储设备升级(STORAGE_DEV)、测试盒 UART 升级(TESTBOX_UART)、App OTA 升级(APP_OTA)、测试盒 BLE 升级(TESTBOX_BLE)。这些 const int 符号由升级库在运行期读取,决定固件启动时轮询哪些升级源——与 app_config.h 中的 TFG_DEV_UPGRADE_SUPPORT(总开关)形成“编译期总开关 + 运行期通道选择”的两级控制。

MIDI / 编解码 / 杂项参数

#if (DECODER_MIDI_EN || DECODER_MIDI_KEYBOARD_EN)
const int MAINTRACK_USE_CHN  = 0;    //0:用track号来区分  1:用channel号来区分
const int MAX_DEC_PLAYER_CNT = 8;    //midi乐谱解码最大同时发声的key数,范围[1,31]
const int MAX_CTR_PLAYER_CNT = 8;    //midi琴最大同时发声的key数,范围[1,31]
const int NOTE_OFF_TRIGGER   = 0;    //midi琴note_off回调
const int MIDI_OUT_CHANNEL = 2;          //midi输出声道1or2
const int MIDI_CTRL_OUT_CHANNEL = 2;     //midi琴输出声道1or2
#endif

#if RTC_EN
const int config_rtc_enable = 1;
#else
const int config_rtc_enable = 0;
#endif

const bool config_usbslave_ctl_mic = 1;
bool const config_decoder_auto_mutex = 1;
const u8 config_no_osc_enable = 0;//ini:PLL=LRC;

Source: app_config.c

  • MIDI 参数被 DECODER_MIDI_EN || DECODER_MIDI_KEYBOARD_EN 条件包裹,解码器未使能时整个段不参与编译——条件编译同样适用于运行期常量文件,避免无意义符号占用空间;
  • config_rtc_enable 由 RTC_EN 宏推导为 1/0 常量,与库中 #if config_rtc_enable 运行时分支配合,使同一份库适配有无 RTC 的芯片;
  • config_usbslave_ctl_mic 使能 USB 从机麦克风控制(声卡模式录音路径);
  • config_no_osc_enable = 0 关闭无晶振模式(该模式下 PLL 由 LRC 时钟驱动,省 BOM 但精度受限)。

公共配置接口层(config.h)

config.h 是应用可见的公共配置接口头,被 includes.h 体系统一引用,提供日志与调试设施:

#if UART_DEBUG
#define  DEBUG_EN
#endif

extern const char libs_debug;

#ifdef DEBUG_EN
#define log_init(x)           debug_uart_init(x)
#define log_uninit()          uart_uninit()
#define log_u8hex(x)          put_u8hex(x)
#else
#define log_init(...)
#define log_uninit()
#define log_u8hex(...)
#endif
#define log(...)

#define     IO_DEBUG_0(i,x)       {JL_PORT##i->DIR &= ~BIT(x), JL_PORT##i->OUT &= ~BIT(x);}
#define     IO_DEBUG_1(i,x)       {JL_PORT##i->DIR &= ~BIT(x), JL_PORT##i->OUT |= BIT(x);}
#define     IO_DEBUG_TOGGLE(i,x)  {JL_PORT##i->DIR &= ~BIT(x), JL_PORT##i->OUT ^= BIT(x);}

#ifdef D_IS_FLASH_SYSTEM
#define _OTP_CONST_
#else
#define _OTP_CONST_  const
#endif

Source: config.h

设计意图:

  • 日志宏按 UART_DEBUG 自动失效:未定义 UART_DEBUG 时,log_init(...) 等宏被展开为空操作,调用点零开销,无需逐处 #ifdef——这是“配置驱动接口裁剪”的典型手法;
  • extern const char libs_debug 与 app_config.c 中的定义对应,构成库对应用符号的引用闭环;
  • IO_DEBUG_* 宏直接操作 GPIO 寄存器(DIR 置输出 + OUT 置位/清零/翻转),用于示波器打点测时序,是低层调试利器;
  • _OTP_CONST_ 根据 D_IS_FLASH_SYSTEM 决定常量是否真正放入 const 段——Flash 系统(D_IS_FLASH_SYSTEM)可直接把只读数据放 Flash 省 RAM,普通系统则退化为 const。

核心配置流

配置从“开发者修改”到“固件行为生效”的完整链路:

flowchart LR
    Dev["开发者修改宏/常量"] --> H["app_config.h 宏定义"]
    Dev --> C["app_config.c const 符号"]
    H --> P["预处理器 #if / #ifdef / #define 展开"]
    P --> K["SDK 库源码条件编译"]
    P --> A["应用模块条件编译"]
    C --> L["链接器符号解析 extern"]
    K --> B["固件镜像 .fw"]
    A --> B
    L --> B
    B --> F["烧录到 SPI Flash"]
    F --> R["运行期行为<br/>时钟/外设/中断/日志/升级通道"]

关键结论:宏路径(左路)在预处理期决定“代码是否存在”,符号路径(右路)在链接期决定“参数取值”。两条路径最终都固化进二进制,因此配置系统的任何修改都必须触发全量重新编译 + 重新烧录。

配置联动示例:开启在线 EQ 调音

flowchart TD
    Start["TCFG_CFG_TOOL_ENABLE = ENABLE"] --> U1["USB_DEVICE_CLASS_CONFIG<br/>= CDC|AUDIO|HID"]
    Start --> U2["TCFG_COMM_TYPE = TCFG_USB_COMM"]
    U1 --> D1["USB 枚举为 声卡+CDC+HID"]
    U2 --> D2["cfg_tools.c 走 USB 收发调音指令"]
    D1 --> E["PC 端 EQ 助手可连接"]
    D2 --> E

这一个宏开启后触发 USB Class 切换与通信通道选择两级联动,最终让 PC 端调音工具可连接——展示配置宏之间“总开关驱动派生宏”的联动设计,换方案时只需改一处。

使用示例

示例 1:为定制方案启用外挂 Flash 与 SD 卡

app_config.h 通过 RUN_APP_CUSTOM 一键切换存储介质配置,无需改动任何库代码:

#if RUN_APP_CUSTOM
#define TFG_EXT_FLASH_EN				    ENABLE
#else
#define TFG_EXT_FLASH_EN				    DISABLE
#endif
...
#if RUN_APP_CUSTOM
#define TFG_SD_EN				            ENABLE
#else
#define TFG_SD_EN				            DISABLE
#endif

Source: app_config.h

示例 2:切换 USB 设备形态

默认(音乐播放器形态)枚举为 AUDIO|HID|MASSSTORAGE,开启 OTA 后变为 AUDIO|HID|CUSTOM_HID:

#if TCFG_CFG_TOOL_ENABLE
#define  USB_DEVICE_CLASS_CONFIG            (CDC_CLASS|AUDIO_CLASS|HID_CLASS)  //在线EQ调试助手
#elif defined(CONFIG_APP_OTA_EN) && (CONFIG_APP_OTA_EN == 1)
#define  USB_DEVICE_CLASS_CONFIG            (AUDIO_CLASS|HID_CLASS|CUSTOM_HID_CLASS)  //ota升级
#else
#define  USB_DEVICE_CLASS_CONFIG            (AUDIO_CLASS|HID_CLASS|MASSSTORAGE_CLASS)  //默认配置
#endif

Source: app_config.h

示例 3:运行期读取更新通道开关

升级库在启动阶段轮询各更新源时读取 CONFIG_UPDATE_* 常量,应用只需修改 app_config.c 即可增删升级通道:

const int CONFIG_UPDATE_STORAGE_DEV_EN = 1;
const int CONFIG_UPDATE_TESTBOX_UART_EN = 1;
const int CONFIG_UPDATE_APP_OTA_EN = 1;
const int CONFIG_UPDATE_TESTBOX_BLE_EN = 1;

Source: app_config.c

配置选项参考

系统级配置(app_config.h)

配置项类型默认值说明
TCFG_SYS_PLL_CLKint96000000目标系统时钟(Hz),实际由 PLL 组合决定
TCFG_PLL_SELenumPLL_D1p0_192MPLL 输出源选择(192MHz)
TCFG_PLL_DIVenumPLL_DIV2PLL 分频(二分频 → 96MHz)
TCFG_HSB_DIVenumHSB_DIV1高速总线分频
CPU_USE_CACHE_WAY_NUMBERint4CPU cache 路数,范围 2~4
TCFG_UART_TX_PORTIOIO_PORTA_05调试串口发送脚
TCFG_UART_BAUDRATEint1000000调试串口波特率
TCFG_VDDIOM_LEVELenumVDDIOM_VOL_32VIO 电源电压档位
POWER_WAKEUP_IOIOAD_KEY_IO低功耗唤醒 IO
POWER_WAKEUP_EDGEenumFALLING_EDGE唤醒触发沿
TCFG_CONFIG_LOWPOWER_SEL0/1ENABLE低功耗模式使能
TCFG_SHUTDOWN_TIMEint5000软关机延时(ms)

按键配置(app_config.h)

配置项类型默认值说明
KEY_DOUBLE_CLICK_EN0/1DISABLE按键多击使能
KEY_IO_EN0/10IO 按键使能
KEY_AD_EN0/11AD 按键使能(mbox_flash 默认通道)
KEY_MIC_EN0/10耳机按键使能
KEY_MATRIX_EN0/10矩阵按键使能
KEY_IR_EN0/10IR 按键使能
KEY_TOUCH_EN0/10触摸按键使能
KEY_LPTOUCH_EN0/10低功耗触摸按键使能
AD_KEY_IOIOIO_PORTA_08AD 按键采样脚

音频配置(app_config.h)

配置项类型默认值说明
SR_DEFAULTint32000默认采样率(Hz)
AMM_RS_INSIDE_ENABLE0/10内侧回采使能(回声抑制)
AMM_RS_OUTSIDE_ENABLE0/11外侧回采使能
TCFG_AUDIO_AUTO_MUTE_ENABLE0/10自动 mute 使能(mbox_flash 不支持)
TCFG_AUTO_MUTE_ENERGYint5自动 mute 能量阈值
TCFG_AUTO_UNMUTE_ENERGYint10自动解除 mute 能量阈值
TCFG_DAC_VOL_FADE_EN0/1DISABLE硬件 DAC 音量淡入淡出
DAC_SOFT_FADE_EN0/1DISABLE软件音量淡入淡出
TCFG_DAC_VOL_FADE_STEPint1淡入淡出步进(0~15)
TCFG_DAC_VOL_FADE_SLOWint15淡入淡出慢速系数(0~15)
TCFG_CFG_TOOL_ENABLE0/1DISABLE在线 EQ 配置工具使能
TCFG_COMM_TYPEenumTCFG_USB_COMM调音通信通道(USB)

AUDIO_LINK 配置(app_config.h)

配置项类型默认值说明
ALINK_MODE_TYPEenumALINK_MD_IIS音频链路模式(I2S)
ALINK_ROLE_TYPEenumALINK_ROLE_MASTER主/从角色(主机)
ALINK_CLK_MODE_TYPEenumALINK_CLK_FALL_UPDATE_RAISE_SAMPLE时钟沿采样模式
ALINK_BIT_WIDE_TYPEenumALINK_LEN_16BIT位宽 16bit
ALINK_SCLK_PER_FRAME_TYPEenumALINK_FRAME_64SCLK每帧 SCLK 数
ALINK_SR_DEFAULTenumALINK_SR_32000链路采样率
ALINK_MAX_CHANNELint4最大通道数
ALINK_MCLK_IOIOIO_PORTA_02主时钟引脚

存储与 USB 配置(app_config.h)

配置项类型默认值说明
VM_SFC_ENABLE0/1ENABLEVM 数据区放 SFC Flash
SYS_MEMORY_SELECTenumUSE_NEW_VMVM 版本选择(新/旧)
TFG_EXT_FLASH_EN0/1依 RUN_APP_CUSTOM外挂 Flash 使能
TFG_SD_EN0/1依 RUN_APP_CUSTOMSD 卡使能
TFG_SPI_HW_NUMint1SPI 硬件编号
TFG_SPI_WORK_MODEenumSPI_MODE_BIDIR_1BITSPI 工作模式(双向 1bit)
TFG_DEV_UPGRADE_SUPPORT0/1ENABLE设备升级总开关
TFG_UPGRADE_FILE_NAMEstring"/update.ufw"升级固件路径
TCFG_PC_ENABLE0/1ENABLEPC 模块(声卡)使能
TCFG_UDISK_ENABLE0/1ENABLEU 盘模块使能
TCFG_USB_PORT_CHARGE0/1DISABLEUSB 口充电使能
TCFG_OTG_USB_DEV_ENbitBIT(0)USB 设备口选择(USB0)
USB_DEVICE_CLASS_CONFIG位或AUDIO|HID|MASSSTORAGEUSB 枚举 Class 组合

运行期常量配置(app_config.c)

符号类型默认值说明
IRQ_DECODER_IPint0解码器中断优先级(最高)
IRQ_AUDIO_IPint5音频中断优先级
IRQ_USB_IPint4USB 中断优先级
IRQ_BT_TIMEBASE_IPint6BT 时基中断优先级
config_usbslave_ctl_micbool1USB 从机麦克风控制使能
config_decoder_auto_mutexbool1解码器自动互斥
config_rtc_enableint依 RTC_ENRTC 使能(推导常量)
config_no_osc_enableu80无晶振模式使能
CONFIG_UPDATE_STORAGE_DEV_ENint1本地存储升级通道
CONFIG_UPDATE_TESTBOX_UART_ENint1测试盒 UART 升级通道
CONFIG_UPDATE_APP_OTA_ENint1App OTA 升级通道
CONFIG_UPDATE_TESTBOX_BLE_ENint1测试盒 BLE 升级通道
libs_debugcharTRUE日志打印总开关

API 参考(config.h)

log_init(x)

初始化调试串口(debug_uart_init(x))。UART_DEBUG 未定义时展开为空操作。

参数: x — UART 配置(波特率等,由 TCFG_UART_* 宏驱动)

说明: 由 UART_DEBUG → DEBUG_EN 条件编译控制是否真实生效。

log_uninit()

关闭调试串口(uart_uninit())。未定义 DEBUG_EN 时为空操作。

log_u8hex(x)

以十六进制输出单字节(put_u8hex(x)),用于调试打印二进制数据。

IO_DEBUG_0(i, x) / IO_DEBUG_1(i, x) / IO_DEBUG_TOGGLE(i, x)

直接操作 GPIO 寄存器拉低/拉高/翻转指定 IO,用于示波器测时序。i 为端口号(如 A),x 为位号(如 5 → PA05)。宏内部自动将 IO 方向置为输出。

_OTP_CONST_

条件常量修饰符:D_IS_FLASH_SYSTEM 定义为空(数据可直接驻留 Flash),否则展开为 const。用于 OTP/Flash 启动系统节省 RAM。

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

配置错误导致的失败模式

失败模式触发场景表现与排查
引脚冲突多个模块宏绑定同一 IO(如 ALINK_MCLK_IO 与按键 IO 复用)外设工作异常/时序错乱;交叉核对各 IO_PORTx_yy 宏
时钟超频/欠频TCFG_PLL_SEL/TCFG_PLL_DIV 组合超出芯片规格系统挂死、USB 枚举失败;检查 TCFG_SYS_PLL_CLK 与分频乘积
中断优先级冲突两个实时模块同优先级抢占音频卡顿/数据丢失;参考 app_config.c 注释的“使用到/未使用到”分区调整
存储介质缺失使能 TFG_SD_EN/TFG_EXT_FLASH_EN 但硬件未贴片启动卡在存储初始化;用 log_tag_const_*_FLASH 日志定位
升级通道误开CONFIG_UPDATE_* 全开且固件无对应源启动时逐个轮询升级源造成延时;按方案裁剪通道
USB Class 冲突同时使能 TCFG_CFG_TOOL_ENABLE 与 CONFIG_APP_OTA_ENUSB_DEVICE_CLASS_CONFIG 按优先级取第一个分支,行为不确定;避免同时开启

边界情况

  • RUN_APP_CUSTOM 派生依赖:TFG_EXT_FLASH_EN、TFG_SD_EN、LED_5X7 都依赖 RUN_APP_CUSTOM。若构建系统未传入该宏,#if RUN_APP_CUSTOM 按 0 处理,全部走默认分支——未定义即关闭是 C 预处理器的隐性默认,换方案时最容易踩坑;
  • NO_CONFIG_PORT (-1) 哨兵:用于表示“无配置引脚”的端口场景,与合法 IO 编号区分,避免把 -1 当真实引脚操作;
  • 注释掉 RX 口:TCFG_UART_RX_PORT 被注释而非置空,说明该方案仅需 TX 单线打印,若需双向通信须同时恢复 RX 定义;
  • 枚举越界:CHARGE_*、VDDIOM_VOL_*、ALINK_* 等枚举值必须取自有定义范围,误写数值可能被驱动静默忽略。

并发与一致性

  • 配置均为编译期/链接期固化,运行期无并发读写问题——这既是优势(无竞态、无缓存一致性问题)也是约束(无法热更新);
  • 中断优先级常量在系统启动早期由库读取并配置 NVIC,此后不可变;多中断并发时,优先级编排(见 IRQ_*_IP)直接决定音频/解码/USB 的抢占时序,配置错误表现为偶发音频断流或 USB 丢包;
  • libs_debug 与各 log_tag_const_* 位于 .LOG_TAG_CONST 专用段,日志打印在中断上下文中只读该符号,无写入路径,天然线程安全。

性能与运维考虑

  • cache 路数权衡:CPU_USE_CACHE_WAY_NUMBER 增大提升代码执行性能但减少 RAM(cache RAM 与普通 RAM 互斥),mbox_flash 取 4 路上限;调试 RAM 不足时可降为 2;
  • ICACHE RAM 复用:ICACHE_RAM_TO_RAM_ENABLE 可将 ICACHE RAM 挪用为普通 RAM(mbox_flash 默认关闭,预留 8192 字节档位),是“性能换容量”的最终手段;
  • 日志段开销:log_tag_const_* 即使值为 0 也占用 .LOG_TAG_CONST 段空间,量产固件应把不必要模块置 0 以压缩日志段;
  • 升级轮询延时:四条 CONFIG_UPDATE_* 通道全开时,启动需依次探测存储/UART/OTA/BLE 升级源,量产方案建议只保留实际使用的通道以减少启动时间;
  • 编译耦合:任何配置修改都会触发大范围重编译(app_config.h 被几乎所有模块包含),建议修改集中在功能分支提交前,避免频繁全量构建。

扩展点

  1. 新增板级方案:复制 mbox_flash 目录结构,通过构建系统传入新的 RUN_APP_* 宏(如 RUN_APP_CUSTOM),在 app_config.h 中按该宏条件分支配置存储/USB/UI——现有文件已示范 #if RUN_APP_CUSTOM 双分支写法;
  2. 新增日志模块标签:在 app_config.c 仿照 log_tag_const_*_XXX 格式添加模块标签,并在该模块源码中引用,即可获得独立日志开关;
  3. 新增升级通道:仿照 CONFIG_UPDATE_* 增加 const int 符号并配套轮询逻辑,通道使能与 TFG_DEV_UPGRADE_SUPPORT 总开关分层管理;
  4. 新增外设:在 app_config.h 增加 TCFG_* 引脚/使能宏,驱动层以 #if 引用,保持“配置集中、消费分散”的既有模式;
  5. VM 版本切换:SYS_MEMORY_SELECT 可在新/旧 VM 实现间切换(USE_NEW_VM/USE_OLD_VM),用于兼容历史数据格式。

测试与验证

  • 配置的正确性主要由板级冒烟测试验证:时钟(TCFG_SYS_PLL_CLK 对应实际主频)、UART 打印(TCFG_UART_*)、按键(KEY_*)、USB 枚举(USB_DEVICE_CLASS_CONFIG 对应的设备形态)、升级通道(CONFIG_UPDATE_*)均可在开机日志中直接观测;
  • 日志系统本身即测试工具:log_tag_const_*_FLASH、_SPI1、_USB 等模块标签可在不重编库的前提下单独打开(置 1),用于驱动层问题定位;
  • IO_DEBUG_* 宏为硬件时序测量提供打点能力,配合示波器验证中断响应与 DMA 时序;
  • 在线 EQ 配置工具(TCFG_CFG_TOOL_ENABLE)开启后可对音频通路做量产前的调音验证,验证完成后必须关闭(其 USB Class 分支与 OTA 分支互斥)。

Related Links

  • app_config.h(编译期宏配置主文件)
  • app_config.c(运行期常量配置主文件)
  • config.h(公共配置接口)
  • cpu_config.c(uc03 方案 CPU 配置)
  • cfg_tools.c(在线 EQ 配置工具实现)
  • init_app.c(系统初始化消费配置)
  • app.c(应用主流程消费配置)
  • usb_config.h(USB 协议栈配置)
  • isd_config_ini.c(post_build 阶段 ini 配置生成)
Prev
应用初始化与启动流程
Next
按键、UI 与用户交互