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

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

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

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

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

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

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

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

应用公共框架与配置

AD24N(杰理 GP-MCU SDK)应用公共框架以编译期配置头文件 app_config.h 为枢纽,串联应用层(sdk/app/src/voice_func)与 BSP 公共层(sdk/app/bsp/common),通过统一的 ENABLE/DISABLE 模块开关宏控制按键、红外、存储、USB、电源管理与 OTA 等功能的裁剪与参数。

Purpose and Scope

本页面介绍 AD24N SDK 中"应用公共框架与配置"这一能力的完整机制,包括:

  • 应用层与 BSP 公共层的分层结构与依赖关系;
  • 以 app_config.h 为核心的编译期配置体系(模块开关宏 + 条件编译);
  • 各功能模块(按键、IR、VM 存储、外挂 Flash、SDMMC、USB、PMU 低功耗、OTA 升级)的配置项语义与设计意图;
  • 框架的关键入口文件职责(toy_main.c、app_config.c、app_config_private.h、sdk_cfg.h 等)。

以下内容不属于本页面范围,请参见各自页面:具体解码/编码器实现(sdk/app/bsp/common/decoder、encoder)、USB 协议栈内部细节(sdk/app/bsp/common/usb)、具体按键扫描/键值映射表、以及特定产品(如 voice_enhanced / voice_toy)的私有业务逻辑。本页面只覆盖"框架 + 配置"这一横切主题。

说明:本页面中关于 app_config.h 的描述均直接来自源码阅读;其余文件(toy_main.c、app_config.c 等)仅通过文件发现确认其存在与所在目录,具体实现细节请以对应源码为准。

概述(Overview)

AD24N SDK 采用"应用目录 + 公共 BSP 目录"的经典分层:应用层按产品形态组织(如 voice_func、voice_toy、voice_enhanced),BSP 公共层按外设/子系统组织(key、norflash、power_manage、fs、usb、decoder、encoder、config 等)。

框架的核心设计决策是编译期裁剪(compile-time configuration):所有功能是否启用、采用哪种驱动变体、使用哪个硬件接口,全部由 app_config.h 中的宏在编译期决定,配合 #if/#else 条件编译,不产生运行期动态注册开销,适合资源受限的 MCU 场景。典型宏值只有 ENABLE(1) 与 DISABLE(0),以及少数多选枚举(如 IR 模式、VM 模式、电源模式)。

app_config.h 位于 sdk/app/src/voice_func/,它首先包含 app_modules.h(模块清单),末尾包含 app_config_private.h(产品私有覆盖项),并被 sdk/app/bsp/common 下几乎所有驱动头文件(key.h、norflash.h、usb_config.h 等)反向包含——因此它是整个框架的"配置中枢"。

架构(Architecture)

flowchart TD
    subgraph sg_App["应用层 sdk/app/src/voice_func"]
        ToyMain["toy_main.c<br/>(应用主入口)"]
        AppConfigC["app_config.c<br/>(配置/初始化)"]
        AppConfigH["app_config.h<br/>(配置中枢)"]
        AppModules["app_modules.h<br/>(模块清单)"]
        AppConfigPriv["app_config_private.h<br/>(产品私有配置)"]
        DeviceMge["common/device_mge.h<br/>(设备管理)"]
    end

    subgraph sg_Bsp["BSP 公共层 sdk/app/bsp/common"]
        SdkCfg["sdk_cfg.h<br/>(SDK 级配置)"]
        KeyDrv["key/*<br/>(key_drv_io/ad/matrix/ir/touch)"]
        NorFlash["norflash/norflash.h<br/>(外挂 Flash)"]
        PowerMg["power_manage/app_power_mg.h<br/>(电源管理)"]
        Fs["fs/vfs_fat.h<br/>(文件系统)"]
        Usb["usb/*<br/>(device/host)"]
        UartUpdate["uart_update/uart_update.h<br/>(串口升级)"]
        LibPower["config/lib_power_config.c<br/>(低功耗配置)"]
    end

    ToyMain --> AppConfigC
    ToyMain --> AppModules
    AppConfigH --> AppModules
    AppConfigH --> AppConfigPriv
    AppConfigH --> SdkCfg
    KeyDrv --> AppConfigH
    NorFlash --> AppConfigH
    Usb --> AppConfigH
    AppConfigC --> LibPower
    DeviceMge --> AppConfigH
    UartUpdate --> AppConfigH
    PowerMg --> LibPower
    Fs --> NorFlash

架构说明(依据源码验证的依赖关系):

  • 配置流向(自上而下):app_config.h 是所有驱动头文件的公共依赖——key.h、norflash.h、usb_common_def.h、usb_config.h、usb_audio_interface.h、usb_mic_interface.h 均在文件开头 #include "app_config.h"。这意味着各 BSP 驱动通过读取本文件的宏决定自己的编译分支。
  • 框架入口:应用目录下 toy_main.c(玩具类产品主程序)与 app_config.c(配置实现)构成应用层骨架;app_config.h 先包含 app_modules.h(模块声明清单),再包含 app_config_private.h(允许产品私有化覆盖)。
  • 分层边界:BSP 公共层不反向依赖具体产品,只依赖 app_config.h 的宏契约;产品差异通过不同的 app_config_private.h(voice_func / voice_toy / voice_enhanced 各有一份)注入,实现"一个框架、多产品复用"。

关键概念

概念含义
编译期开关宏ENABLE(1) / DISABLE(0),配合 #if 裁剪代码,零运行期开销
多选枚举宏如 IR 模式(SIMPLE_IR/STANDARD_IR)、VM 模式(NO_VM/USE_NEW_VM/USE_OLD_VM)
条件派生宏如 SPI_HW_NUM 由 TCFG_FLASH_SPI_TYPE_SELECT 推导,SDMMCA_EN 由 TFG_SD_EN 推导
私有覆盖app_config_private.h 在产品目录内提供差异化配置

配置体系详解(Main Content)

1. 开关宏约定

app_config.h 第 5-9 行定义了两组等价开关宏,全工程统一使用:

#define ENABLE_THIS_MOUDLE                  1
#define DISABLE_THIS_MOUDLE                 0

#define ENABLE                              1
#define DISABLE                             0

Source: app_config.h

设计意图:统一"0/1"语义,避免各模块自行发明 TRUE/FALSE 或 ON/OFF 造成混用;ENABLE_THIS_MOUDLE 系列是为"本模块是否参与编译"预留的语义区分(注意源码中的历史拼写 MOUDLE,属既有命名,沿用即可)。

2. 按键模块(KEY)

#define KEY_IO_EN                           0   ///<IO按键使能
#define KEY_AD_EN                           1   ///<AD按键使能
#define KEY_MATRIX_EN                       0   ///<矩阵按键使能
#define KEY_IR_EN                           0   ///<IR按键使能
#define KEY_TOUCH_EN                        0   ///<触摸按键使能

Source: app_config.h

五种按键驱动(IO/AD/矩阵/红外/触摸)彼此独立使能,对应 BSP 公共层的 key/key_drv_io.h、key/key_drv_ad.h、key/key_matrix.h、key/key_ir.h、key/key_touch.h。设计上支持多按键类型共存(例如 AD 键 + 触摸键同时工作),实际驱动组合由条件编译生成。示例配置 KEY_AD_EN=1 表示当前工程使用 AD 按键。

3. 红外模式(IR)

#define SIMPLE_IR                           1   //简易红外驱动
#define STANDARD_IR                         2   //标准NEC红外驱动
#define SEL_IR_MODE                         STANDARD_IR

Source: app_config.h

SEL_IR_MODE 是典型的多选枚举:SIMPLE_IR 提供精简协议解析(代码量小、占用少),STANDARD_IR 使用标准 NEC 红外协议(兼容性更好)。选择驱动变体的方式是把枚举值赋给 SEL_IR_MODE,驱动内部 #if SEL_IR_MODE == STANDARD_IR 分支编译。

4. 存储介质 VM 模式

#define NO_VM                               0
#define USE_NEW_VM                          1
#define USE_OLD_VM                          2
#define SYS_MEMORY_SELECT                   USE_NEW_VM

Source: app_config.h

VM(Value Memory)是芯片内置的掉电非易失参数区。SYS_MEMORY_SELECT 三选一:NO_VM 不使用、USE_NEW_VM 使用新版 VM 管理(推荐,SYS_MEMORY_SELECT 默认值)、USE_OLD_VM 兼容旧版 VM。选型直接影响系统参数(如音量、均衡、配对信息)的读写接口,切换需同步迁移上层调用。

5. 外挂 Flash(EXFLASH / SPI)

#define TCFG_FLASH_SPI_TYPE_SELECT          1//1:flash 选择硬件spi; 0:flash use soft_spi
#define SPI_SD_IO_REUSE                     DISABLE//SPI_FLASH与SD卡模块IO复用使能

#define TFG_SPI_UNIDIR_MODE_EN              DISABLE//外挂flash运行1bit模式
#if TFG_SPI_UNIDIR_MODE_EN
#define HW_SPI_WORK_MODE                    SPI_MODE_UNIDIR_1BIT
#define SOFT_SPI_WORK_MODE                  SPI_MODE_UNIDIR_1BIT//只支持双向或单线
#define SPI_READ_DATA_WIDTH                 1
#else
#define HW_SPI_WORK_MODE                    SPI_MODE_BIDIR_1BIT
#define SOFT_SPI_WORK_MODE                  SPI_MODE_BIDIR_1BIT//只支持双向或单线
#define SPI_READ_DATA_WIDTH                 2
#endif

#if TCFG_FLASH_SPI_TYPE_SELECT
#define SPI_HW_NUM                          1
#else
#define SPI_HW_NUM                          0
#endif

Source: app_config.h

外挂 Flash 配置展示了框架的条件派生宏模式:

  • TCFG_FLASH_SPI_TYPE_SELECT:选择硬件 SPI(1)或软件 SPI(0)驱动外挂 Flash;
  • SPI_SD_IO_REUSE:外挂 Flash 与 SD 卡模块是否复用 IO(复用可省引脚,但需保证二者不同时访问);
  • TFG_SPI_UNIDIR_MODE_EN:外挂 Flash 是否运行 1bit 单向模式;启用后 HW_SPI_WORK_MODE/SOFT_SPI_WORK_MODE 变为 SPI_MODE_UNIDIR_1BIT、SPI_READ_DATA_WIDTH=1,否则为 SPI_MODE_BIDIR_1BIT 双向模式、SPI_READ_DATA_WIDTH=2;
  • SPI_HW_NUM:由 TCFG_FLASH_SPI_TYPE_SELECT 自动推导(1=硬件 SPI 编号 1,0=软件 SPI),上层无需重复配置,避免"主开关与派生态不一致"。

6. SDMMC

#if defined(TFG_SD_EN) && (TFG_SD_EN)
#define SDMMCA_EN
#endif

Source: app_config.h

SDMMC 使能采用"外部宏触发内部宏"方式:若产品已定义 TFG_SD_EN 且为真,则派生定义 SDMMCA_EN 打开 SDMMC-A 控制器。这种写法让 SD 卡能力可被上层(如 SD_UPDATE_EN)或板级配置(board_cfg.h)先置位,框架再统一收敛。

7. USB 模块

#if HAS_USB_EN
#define TCFG_PC_ENABLE                      1//DISABLE  //PC模块使能
#define TCFG_USB_MSD_CDROM_ENABLE           DISABLE
#define TCFG_UDISK_ENABLE                   1//DISABLE     //U盘模块使能
#define TCFG_HID_HOST_ENABLE                DISABLE
#define TCFG_ADB_ENABLE                     DISABLE     //该功能暂不支持
#define TCFG_AOA_ENABLE                     DISABLE     //该功能暂不支持
#define TCFG_PUSH_CODE_ENABLE               DISABLE     //该功能需要关闭OTG使能
#else
/* 全部 DISABLE 的对称分支 */
#endif

#define TCFG_USB_PORT_CHARGE                DISABLE     //使能为USB充电模式
#define TCFG_OTG_USB_DEV_EN                 BIT(0)      //USB0 = BIT(0)  USB1 = BIT(1)
#define TCFG_USB_DM_MULTIPLEX_WITH_SD_DAT0  DISABLE     //USBDM与SD_DAT0是否复用

Source: app_config.h

USB 配置遵循主开关 HAS_USB_EN + 子功能开关两级结构:

  • HAS_USB_EN 为真时,TCFG_PC_ENABLE、TCFG_UDISK_ENABLE 等子开关默认打开,HID_HOST、ADB、AOA、PUSH_CODE 默认关闭;
  • TCFG_PUSH_CODE_ENABLE 有硬性约束——该功能需要关闭 OTG 使能(源码注释明确),代码在启用它时会 #undef TCFG_OTG_MODE 并置 0(第 126-132 行),防止外设冲突;
  • TCFG_OTG_USB_DEV_EN 用位域表示启用哪一路 USB(BIT(0)=USB0,BIT(1)=USB1),是"位图式"配置的典型用法;
  • TCFG_USB_DM_MULTIPLEX_WITH_SD_DAT0 控制 USBDM 与 SD_DAT0 复用,注释提示若该 USB 口用于充电,TCFG_OTG_MODE 还需或上 TCFG_OTG_MODE_CHARGE(第 112-117 行)——这是 IO 复用场景下必须人工保证的一致性约束。

在 TCFG_PC_ENABLE || TCFG_UDISK_ENABLE 分支内,框架会包含 usb_std_class_def.h、usb_common_def.h 并重定义 TCFG_OTG_MODE(第 101-110 行):

#undef TCFG_OTG_MODE
#define TCFG_OTG_MODE                       (TCFG_OTG_MODE_HOST|TCFG_OTG_MODE_SLAVE|TCFG_OTG_MODE_CHARGE|OTG_DET_DP_ONLY)

Source: app_config.h

8. PMU 低功耗配置

#define TCFG_LOWPOWER_POWER_SEL             PWR_LDO15                    //电源模式设置,可选DCDC和LDO
#define TCFG_LOWPOWER_BTOSC_DISABLE         0                            //低功耗模式下BTOSC是否保持
#define TCFG_LOWPOWER_LOWPOWER_SEL          1//DEEP_SLEEP_EN                //SNIFF状态下芯片是否进入powerdown
#define TCFG_LOWPOWER_PATTERN               SOFT_MODE//SOFT_BY_POWER_MODE   //选择软关机的方式
#define TCFG_LOWPOWER_VDDIOM_LEVEL          VDDIOM_VOL_30V
#define TCFG_LOWPOWER_VDDIOW_LEVEL          VDDIOW_VOL_28V               //弱VDDIO等级配置
#define TCFG_LOWPOWER_OSC_TYPE              OSC_TYPE_LRC
#define TCFG_LOWPOWER_SOFF                  1
#define TCFG_LOWPOWER_OVERLAY               0

Source: app_config.h

低功耗参数组由 TCFG_LOWPOWER_* 前缀统一命名,涵盖电源拓扑(PWR_LDO15 表示 LDO 1.5V 内核供电,可换 DCDC)、睡眠行为(SNIFF 下是否 powerdown)、软关机方式(SOFT_MODE)、IO 电压等级(VDDIOM_VOL_30V/VDDIOW_VOL_28V)与低频时钟选择(OSC_TYPE_LRC)。BSP 侧实现位于 sdk/app/bsp/common/power_manage/app_power_mg.h 与 sdk/app/bsp/common/config/lib_power_config.c。该组配置直接决定整机待机电流与唤醒路径,是产品功耗调优的第一入口。

9. OTA / 升级配置

/*---------------UPDATE---------------------*/
#define TFG_DEV_UPGRADE_SUPPORT             ENABLE
#define TFG_UPGRADE_FILE_NAME               "/update.ufw"
#define TESTBOX_UART_UPDATE_EN                 0
#define CONFIG_APP_OTA_EN                      0
#define TESTBOX_BT_UPDATE_EN                   0
//  SD卡设备升级
#define SD_UPDATE_EN                           1
//  U盘设备升级
#define UDISK_UPDATE_EN                        1

Source: app_config.h

升级能力支持多通道并存:设备升级总开关 TFG_DEV_UPGRADE_SUPPORT、升级固件路径 /update.ufw、串口(testbox UART)、蓝牙(testbox BT)、SD 卡(SD_UPDATE_EN)、U 盘(UDISK_UPDATE_EN)。示例工程同时打开 SD 与 U 盘升级通道,串口/蓝牙/OTA 默认关闭。升级文件系统侧依赖 sdk/app/bsp/common/fs/vfs_fat.h,串口通道依赖 sdk/app/bsp/common/uart_update/uart_update.h。

框架关键文件职责

文件目录职责
app_config.hsdk/app/src/voice_func/全局配置中枢:模块开关 + 参数宏(本页核心)
app_config_private.hvoice_func / voice_toy / voice_enhanced 各一份产品私有配置覆盖项,被 app_config.h 末尾包含
app_config.csdk/app/src/voice_func/配置项/初始化相关实现
toy_main.csdk/app/src/voice_func/应用主入口(玩具类产品)
app_modules.hsdk/app/src/voice_func/应用模块清单,被 app_config.h 首先包含
sdk_cfg.hsdk/app/bsp/common/SDK 级公共配置
lib_power_config.csdk/app/bsp/common/config/低功耗参数实现
device_mge.hsdk/app/src/voice_func/common/设备管理接口(依赖 app_config.h)

各文件具体函数签名与实现细节请直接查看对应源码;本页仅对其在框架中的角色进行归纳。

核心流程(Core Flow)

编译期配置生效流程

框架的"配置 → 生效"完全发生在编译期:宏定义在 app_config.h,被各 BSP 驱动头文件反向包含,驱动源码内用 #if 分支决定编入哪些代码。运行期只看到编译产物,没有配置解析开销。

sequenceDiagram
    participant Dev as 开发者/产品配置
    participant AppCfg as app_config.h
    participant Priv as app_config_private.h
    participant Mod as app_modules.h
    participant Drv as BSP 驱动 (key/norflash/usb/...)
    participant Lib as 公共库 (lib_power_config 等)

    Dev->>AppCfg: 修改 ENABLE/DISABLE 与参数宏
    AppCfg->>Mod: #include "app_modules.h" (模块清单)
    AppCfg->>Priv: #include "app_config_private.h" (私有覆盖)
    AppCfg->>Drv: 驱动头文件 #include "app_config.h"
    Drv->>Drv: #if KEY_AD_EN / #if SEL_IR_MODE==STANDARD_IR 等分支
    Drv->>Lib: 依赖派生宏 (SPI_HW_NUM/SDMMCA_EN) 选择实现
    Lib-->>Drv: 编译产物 (仅含使能代码)
    Drv-->>Dev: 固件按配置裁剪/装配

应用启动骨架流程

基于文件发现(toy_main.c 为应用主入口、app_config.c 为配置实现),典型启动顺序如下;其中 toy_main.c 内的具体函数名以实际源码为准:

flowchart TD
    Start([上电/复位]) --> BoardCfg["board_cfg.h 板级初始化"]
    BoardCfg --> SysInit["系统时钟/内存(VM)初始化"]
    SysInit --> KeyInit{"KEY_AD_EN == 1?"}
    KeyInit -->|"是"| KeyAd["初始化 AD 按键驱动"]
    KeyInit -->|"否"| FlashInit{"TCFG_FLASH_SPI_TYPE_SELECT?"}
    KeyAd --> FlashInit
    FlashInit -->|"1: 硬件 SPI"| HwSpi["SPI_HW_NUM = 1<br/>初始化硬件 SPI 外挂 Flash"]
    FlashInit -->|"0: 软件 SPI"| SoftSpi["SPI_HW_NUM = 0<br/>初始化软件 SPI 外挂 Flash"]
    HwSpi --> FsInit["文件系统挂载 (vfs_fat)"]
    SoftSpi --> FsInit
    FsInit --> UsbInit{"HAS_USB_EN && TCFG_UDISK_ENABLE?"}
    UsbInit -->|"是"| UsbOn["枚举 OTG 模式<br/>TCFG_OTG_USB_DEV_EN 位域选择 USB 口"]
    UsbInit -->|"否"| PmuInit["低功耗参数生效<br/>(TCFG_LOWPOWER_*)"]
    UsbOn --> PmuInit
    PmuInit --> Loop["主循环/事件分发"]

设计意图:每个判断点对应 app_config.h 中的一个宏,框图与宏一一对应,开发者调配置时能直接推断行为变化。

使用示例(Usage Examples)

示例 1:裁剪按键类型(开关宏用法)

在 app_config.h 中只保留需要的按键驱动,其余置 0,编译器将不生成对应扫描代码:

#define KEY_IO_EN                           0   ///<IO按键使能
#define KEY_AD_EN                           1   ///<AD按键使能
#define KEY_MATRIX_EN                       0   ///<矩阵按键使能
#define KEY_IR_EN                           0   ///<IR按键使能
#define KEY_TOUCH_EN                        0   ///<触摸按键使能

Source: app_config.h

示例 2:切换红外协议变体(枚举宏用法)

将 SEL_IR_MODE 从 STANDARD_IR 改为 SIMPLE_IR 即切换到简易红外驱动,无需改动任何驱动源码:

#define SIMPLE_IR                           1   //简易红外驱动
#define STANDARD_IR                         2   //标准NEC红外驱动
#define SEL_IR_MODE                         STANDARD_IR

Source: app_config.h

示例 3:升级通道使能(多通道并存)

#define TFG_DEV_UPGRADE_SUPPORT             ENABLE
#define TFG_UPGRADE_FILE_NAME               "/update.ufw"
#define SD_UPDATE_EN                           1
#define UDISK_UPDATE_EN                        1

Source: app_config.h

配置选项(Configuration Options)

以下为 app_config.h 中已确认的核心配置项(类型均为编译期宏;默认值为当前工程取值):

配置项类型/可选值默认值说明
ENABLE / DISABLE0 / 1—全局开关语义常量
KEY_IO_EN0 / 10IO 按键使能
KEY_AD_EN0 / 11AD 按键使能
KEY_MATRIX_EN0 / 10矩阵按键使能
KEY_IR_EN0 / 10IR 按键使能
KEY_TOUCH_EN0 / 10触摸按键使能
SEL_IR_MODESIMPLE_IR(1) / STANDARD_IR(2)STANDARD_IR红外驱动变体
SYS_MEMORY_SELECTNO_VM(0) / USE_NEW_VM(1) / USE_OLD_VM(2)USE_NEW_VMVM 参数区方案
TCFG_FLASH_SPI_TYPE_SELECT0 / 111=硬件 SPI,0=软件 SPI
SPI_SD_IO_REUSEENABLE / DISABLEDISABLE外挂 Flash 与 SD 卡 IO 复用
TFG_SPI_UNIDIR_MODE_ENENABLE / DISABLEDISABLE外挂 Flash 1bit 单向模式
SPI_HW_NUM0 / 1(派生)由 TCFG_FLASH_SPI_TYPE_SELECT 推导使用的 SPI 编号
SDMMCA_EN定义/未定义(派生)由 TFG_SD_EN 推导SDMMC-A 使能
TCFG_PC_ENABLEENABLE / DISABLE1(HAS_USB_EN 时)PC 模块使能
TCFG_UDISK_ENABLEENABLE / DISABLE1(HAS_USB_EN 时)U 盘模块使能
TCFG_HID_HOST_ENABLEENABLE / DISABLEDISABLEHID 主机使能
TCFG_ADB_ENABLEENABLE / DISABLEDISABLEADB(暂不支持)
TCFG_AOA_ENABLEENABLE / DISABLEDISABLEAOA(暂不支持)
TCFG_PUSH_CODE_ENABLEENABLE / DISABLEDISABLE推送码(需关闭 OTG)
TCFG_USB_PORT_CHARGEENABLE / DISABLEDISABLEUSB 充电模式
TCFG_OTG_USB_DEV_EN位域 BIT(0)/BIT(1)BIT(0)启用的 USB 口
TCFG_USB_DM_MULTIPLEX_WITH_SD_DAT0ENABLE / DISABLEDISABLEUSBDM 与 SD_DAT0 复用
TCFG_OTG_MODE位或组合(HOST/SLAVE/CHARGE/DP_ONLY)三模式组合OTG 工作模式
TCFG_LOWPOWER_POWER_SELPWR_LDO15 等PWR_LDO15电源模式(LDO/DCDC)
TCFG_LOWPOWER_LOWPOWER_SEL0 / DEEP_SLEEP_EN1SNIFF 下是否 powerdown
TCFG_LOWPOWER_PATTERNSOFT_MODE 等SOFT_MODE软关机方式
TCFG_LOWPOWER_VDDIOM_LEVELVDDIOM_VOL_30V 等VDDIOM_VOL_30VVDDIO 主电平
TCFG_LOWPOWER_VDDIOW_LEVELVDDIOW_VOL_28V 等VDDIOW_VOL_28V弱 VDDIO 电平
TCFG_LOWPOWER_OSC_TYPEOSC_TYPE_LRC 等OSC_TYPE_LRC低功耗时钟
TFG_DEV_UPGRADE_SUPPORTENABLE / DISABLEENABLE设备升级总开关
TFG_UPGRADE_FILE_NAME字符串"/update.ufw"升级固件路径
SD_UPDATE_EN0 / 11SD 卡升级
UDISK_UPDATE_EN0 / 11U 盘升级
CONFIG_APP_OTA_EN / TESTBOX_UART_UPDATE_EN / TESTBOX_BT_UPDATE_EN0 / 10蓝牙/串口 OTA 通道

故障模式、边界与一致性(Failure Modes & Edge Cases)

条件编译导致的"幽灵配置"

框架所有开关都是编译期宏,不存在运行期配置校验。风险场景:

  • 两个宏同时置 1 但驱动互斥(如 KEY_IR_EN=1 且 SEL_IR_MODE 未赋值)时,可能编译出重复或错误的驱动代码;
  • 修改宏后未全量重新编译(依赖头文件缓存),固件行为与配置不符——这是本框架最高频的排障点,应确保改动 app_config.h 触发所有依赖文件的重新编译(源码中 key.h、norflash.h、usb_config.h 等都直接 include 它)。

IO 复用一致性约束(源码注释明确要求)

  • SPI_SD_IO_REUSE(DISABLE 默认):外挂 Flash 与 SD 卡复用 IO 时,二者不能同时工作,需上层保证访问互斥;
  • TCFG_USB_DM_MULTIPLEX_WITH_SD_DAT0:USBDM 与 SD_DAT0 复用时,若该 USB 口同时作为充电口(LDO5V_IN 接此口),TCFG_OTG_MODE 必须或上 TCFG_OTG_MODE_CHARGE,否则充电与 USB 数据功能互相干扰(见 app_config.h#L112-L117 注释);
  • TCFG_PUSH_CODE_ENABLE 与 OTG 互斥:源码在启用推送码时强制 #undef TCFG_OTG_MODE 并置 0(app_config.h#L126-L132),开发者不应手动同时开启。

未定义宏的默认行为

以 SDMMCA_EN 为例,#if defined(TFG_SD_EN) && (TFG_SD_EN) 的写法保证了 TFG_SD_EN 未定义时安全地不使能 SDMMC——框架对"未定义 = 关闭"的语义依赖较强,新增模块时应沿用 defined(x) && (x) 防御式写法,避免直接 #if TFG_SD_EN 在未定义时产生 #if 0 之外的非预期行为。

VM 方案切换风险

SYS_MEMORY_SELECT 在 USE_NEW_VM / USE_OLD_VM / NO_VM 间切换会改变参数区的读写布局,已有用户数据的固件切换方案可能导致参数解析错误或数据丢失,属不可热切换配置,需在量产前定版。

性能与运维(Performance & Operational Notes)

  • 零运行期开销:所有裁剪在编译期完成,无配置表解析、无动态分支,适合 MCU 资源受限场景;代价是每次配置变更需全量重编译。
  • 代码体积控制:默认关闭 HID_HOST、ADB、AOA、PUSH_CODE、触摸/矩阵/IO 按键等较大驱动,仅保留 KEY_AD_EN、标准 IR、U 盘/PC、SD+U 盘升级,示例工程体现"按需裁剪"的基线。
  • 低功耗调优入口:TCFG_LOWPOWER_* 组(电源模式、SNIFF powerdown、软关机方式、IO 电平、LRC 时钟)是待机电流与唤醒速度的平衡点,调参后应回归验证唤醒路径。

扩展点(Extension Points)

  1. 产品私有配置:在各自产品目录(如 voice_toy/、voice_enhanced/)维护 app_config_private.h,app_config.h 末尾统一包含,实现"公共框架 + 产品覆盖";新增产品只需提供自己的私有头文件。
  2. 模块清单:app_modules.h 是应用模块注册清单,新增应用模块(如新的业务 service)应在此声明并在 toy_main.c 中挂接初始化。
  3. 驱动族扩展:按键(key_drv_*)、IR(SIMPLE_IR/STANDARD_IR)、VM(新旧两版)均采用"枚举宏选变体"模式,新增驱动变体时遵循同一模式即可被框架复用。
  4. 升级通道:TFG_DEV_UPGRADE_SUPPORT 下可挂接新通道(当前已有 testbox UART、testbox BT、SD、U 盘),通道开关以 *_UPDATE_EN 形式加入配置组。

测试与验证建议

  • 修改任一配置宏后执行全量编译,确认无 #if 分支残留告警;
  • 对按键/IR/存储配置组合做冒烟测试(至少覆盖"仅 AD 键 + 标准 IR + 硬件 SPI"基线组合);
  • 升级通道(SD/U 盘)验证应覆盖"无升级文件、升级文件损坏、升级中途断电"三种场景,因为 TFG_UPGRADE_FILE_NAME 固定为 /update.ufw,升级流程对文件系统依赖较强。

相关链接(Related Links)

  • app_config.h(配置中枢)
  • app_config.c(配置实现)
  • toy_main.c(应用主入口)
  • app_config_private.h(voice_func 私有配置)
  • sdk_cfg.h(SDK 级配置)
  • lib_power_config.c(低功耗配置实现)
  • app_power_mg.h(电源管理接口)
  • key.h / key_drv_ad.h(按键框架)
  • norflash.h(外挂 Flash)
  • vfs_fat.h(文件系统)
  • uart_update.h(串口升级)
  • device_mge.h(设备管理)

相关目录:解码器实现见 sdk/app/bsp/common/decoder/,编码器见 sdk/app/bsp/common/encoder/,USB 协议栈见 sdk/app/bsp/common/usb/——这些子系统的具体细节属于各自页面,本页不展开。

API 参考(宏契约,即本框架的"接口")

由于本框架是编译期配置体系,app_config.h 中的宏定义即为面向所有 BSP 驱动与上层模块的公共"API"。以下归纳其三类契约模式:

1. 布尔开关宏(ENABLE / DISABLE 语义)

#define KEY_AD_EN                           1   ///<AD按键使能
#define TCFG_UDISK_ENABLE                   1   ///<U盘模块使能
#define SD_UPDATE_EN                        1   ///<SD卡设备升级
  • 取值:ENABLE(1) 或 DISABLE(0)
  • 契约:驱动/模块以 #if KEY_AD_EN 分支编译;未定义时按"关闭"处理(推荐用 defined(x) && (x) 防御式判断,如 SDMMCA_EN 的写法)
  • 典型误用:取值为 2 或以上非 0/1 值,导致 #if 与 #if defined 语义不一致

2. 多选枚举宏(选择驱动变体)

#define SEL_IR_MODE                         STANDARD_IR
#define SYS_MEMORY_SELECT                   USE_NEW_VM
#define TCFG_LOWPOWER_POWER_SEL             PWR_LDO15
  • 取值:预定义枚举常量(如 SIMPLE_IR/STANDARD_IR、NO_VM/USE_NEW_VM/USE_OLD_VM)
  • 契约:驱动内以 #if SEL_IR_MODE == STANDARD_IR 选择实现;新变体必须先在常量定义区声明,再在驱动分支中处理
  • 注意:切换变体属于"换实现"而非"开关",涉及行为/协议变化,需回归测试

3. 派生宏(主开关自动推导)

#if TCFG_FLASH_SPI_TYPE_SELECT
#define SPI_HW_NUM                          1
#else
#define SPI_HW_NUM                          0
#endif
  • 契约:派生宏由主开关推导,上层只配置主开关、只读派生宏,禁止反向修改,从机制上防止主从配置漂移

4. 约束型宏(存在硬性互斥)

宏约束强制措施
TCFG_PUSH_CODE_ENABLE必须关闭 OTG源码内 #undef TCFG_OTG_MODE 并置 0
TCFG_USB_DM_MULTIPLEX_WITH_SD_DAT0充电口场景需或上 TCFG_OTG_MODE_CHARGE注释约定(人工保证)
SPI_SD_IO_REUSE复用 IO 需上层访问互斥注释约定(人工保证)
SYS_MEMORY_SELECT方案切换不可热迁移已有 VM 数据文档约定(量产前定版)

契约总结:开关宏是"编译期接口",其正确性由条件编译保证、由开发者维护;新增模块时遵循"常量定义 → 派生推导 → 分支使用 → 注释约束"四步,即可与现有框架风格保持一致。

Prev
语音功能状态机 voice_func