应用公共框架与配置
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.h | sdk/app/src/voice_func/ | 全局配置中枢:模块开关 + 参数宏(本页核心) |
app_config_private.h | voice_func / voice_toy / voice_enhanced 各一份 | 产品私有配置覆盖项,被 app_config.h 末尾包含 |
app_config.c | sdk/app/src/voice_func/ | 配置项/初始化相关实现 |
toy_main.c | sdk/app/src/voice_func/ | 应用主入口(玩具类产品) |
app_modules.h | sdk/app/src/voice_func/ | 应用模块清单,被 app_config.h 首先包含 |
sdk_cfg.h | sdk/app/bsp/common/ | SDK 级公共配置 |
lib_power_config.c | sdk/app/bsp/common/config/ | 低功耗参数实现 |
device_mge.h | sdk/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 / DISABLE | 0 / 1 | — | 全局开关语义常量 |
KEY_IO_EN | 0 / 1 | 0 | IO 按键使能 |
KEY_AD_EN | 0 / 1 | 1 | AD 按键使能 |
KEY_MATRIX_EN | 0 / 1 | 0 | 矩阵按键使能 |
KEY_IR_EN | 0 / 1 | 0 | IR 按键使能 |
KEY_TOUCH_EN | 0 / 1 | 0 | 触摸按键使能 |
SEL_IR_MODE | SIMPLE_IR(1) / STANDARD_IR(2) | STANDARD_IR | 红外驱动变体 |
SYS_MEMORY_SELECT | NO_VM(0) / USE_NEW_VM(1) / USE_OLD_VM(2) | USE_NEW_VM | VM 参数区方案 |
TCFG_FLASH_SPI_TYPE_SELECT | 0 / 1 | 1 | 1=硬件 SPI,0=软件 SPI |
SPI_SD_IO_REUSE | ENABLE / DISABLE | DISABLE | 外挂 Flash 与 SD 卡 IO 复用 |
TFG_SPI_UNIDIR_MODE_EN | ENABLE / DISABLE | DISABLE | 外挂 Flash 1bit 单向模式 |
SPI_HW_NUM | 0 / 1(派生) | 由 TCFG_FLASH_SPI_TYPE_SELECT 推导 | 使用的 SPI 编号 |
SDMMCA_EN | 定义/未定义(派生) | 由 TFG_SD_EN 推导 | SDMMC-A 使能 |
TCFG_PC_ENABLE | ENABLE / DISABLE | 1(HAS_USB_EN 时) | PC 模块使能 |
TCFG_UDISK_ENABLE | ENABLE / DISABLE | 1(HAS_USB_EN 时) | U 盘模块使能 |
TCFG_HID_HOST_ENABLE | ENABLE / DISABLE | DISABLE | HID 主机使能 |
TCFG_ADB_ENABLE | ENABLE / DISABLE | DISABLE | ADB(暂不支持) |
TCFG_AOA_ENABLE | ENABLE / DISABLE | DISABLE | AOA(暂不支持) |
TCFG_PUSH_CODE_ENABLE | ENABLE / DISABLE | DISABLE | 推送码(需关闭 OTG) |
TCFG_USB_PORT_CHARGE | ENABLE / DISABLE | DISABLE | USB 充电模式 |
TCFG_OTG_USB_DEV_EN | 位域 BIT(0)/BIT(1) | BIT(0) | 启用的 USB 口 |
TCFG_USB_DM_MULTIPLEX_WITH_SD_DAT0 | ENABLE / DISABLE | DISABLE | USBDM 与 SD_DAT0 复用 |
TCFG_OTG_MODE | 位或组合(HOST/SLAVE/CHARGE/DP_ONLY) | 三模式组合 | OTG 工作模式 |
TCFG_LOWPOWER_POWER_SEL | PWR_LDO15 等 | PWR_LDO15 | 电源模式(LDO/DCDC) |
TCFG_LOWPOWER_LOWPOWER_SEL | 0 / DEEP_SLEEP_EN | 1 | SNIFF 下是否 powerdown |
TCFG_LOWPOWER_PATTERN | SOFT_MODE 等 | SOFT_MODE | 软关机方式 |
TCFG_LOWPOWER_VDDIOM_LEVEL | VDDIOM_VOL_30V 等 | VDDIOM_VOL_30V | VDDIO 主电平 |
TCFG_LOWPOWER_VDDIOW_LEVEL | VDDIOW_VOL_28V 等 | VDDIOW_VOL_28V | 弱 VDDIO 电平 |
TCFG_LOWPOWER_OSC_TYPE | OSC_TYPE_LRC 等 | OSC_TYPE_LRC | 低功耗时钟 |
TFG_DEV_UPGRADE_SUPPORT | ENABLE / DISABLE | ENABLE | 设备升级总开关 |
TFG_UPGRADE_FILE_NAME | 字符串 | "/update.ufw" | 升级固件路径 |
SD_UPDATE_EN | 0 / 1 | 1 | SD 卡升级 |
UDISK_UPDATE_EN | 0 / 1 | 1 | U 盘升级 |
CONFIG_APP_OTA_EN / TESTBOX_UART_UPDATE_EN / TESTBOX_BT_UPDATE_EN | 0 / 1 | 0 | 蓝牙/串口 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)
- 产品私有配置:在各自产品目录(如
voice_toy/、voice_enhanced/)维护app_config_private.h,app_config.h末尾统一包含,实现"公共框架 + 产品覆盖";新增产品只需提供自己的私有头文件。 - 模块清单:
app_modules.h是应用模块注册清单,新增应用模块(如新的业务 service)应在此声明并在toy_main.c中挂接初始化。 - 驱动族扩展:按键(
key_drv_*)、IR(SIMPLE_IR/STANDARD_IR)、VM(新旧两版)均采用"枚举宏选变体"模式,新增驱动变体时遵循同一模式即可被框架复用。 - 升级通道:
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 数据 | 文档约定(量产前定版) |
契约总结:开关宏是"编译期接口",其正确性由条件编译保证、由开发者维护;新增模块时遵循"常量定义 → 派生推导 → 分支使用 → 注释约束"四步,即可与现有框架风格保持一致。