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

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

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

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

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

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

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

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

语音功能状态机 voice_func

语音功能状态机 voice_func 是 AD24N SDK 应用层(app/src/voice_func)的核心状态机框架,负责组织语音玩具/语音增强产品在空闲(idle)、音乐(music)、MIDI、扩音(speaker)、LineIn、录音(record)、升级(update)、USB 从机(usb_slave)、软关机(softoff)等运行状态之间的切换与调度。

Purpose and Scope

本页面向语音功能状态机 voice_func 这一应用层子系统,覆盖:

  • voice_func 模块的整体目录结构与各子模块职责(toy_idle、toy_music、toy_midi、toy_speaker、toy_linein、toy_record、toy_update、toy_usb_slave、toy_softoff);
  • 状态机入口 toy_main 与公共支撑模块(common_msg、device_mge、idle_deal、simple_play_file)的角色划分;
  • 应用配置(app_config)与 CPU 配置(cpu/sh58/cpu_config)在状态机中的位置;
  • 状态机各状态之间的迁移关系与消息流转机制。

不属于本页范围、由兄弟页面负责的主题:

  • 具体应用工程的组装方式,参见 voice_toy(语音玩具应用)与 voice_enhanced(扩音器应用)相关页面;
  • 底层驱动、协议栈与 HAL 层实现;
  • 生产烧录与后处理脚本(post_build)。

说明:本次文档生成的源代码探索预算(6 次工具调用)已全部用于确认 voice_func 的目录结构、工程引用关系与模块清单;toy_main.c 等核心实现文件的具体函数签名与逐行逻辑未能继续读取,凡涉及实现细节处均明确标注"实现细节未在本次读取范围内",不臆造代码。

Overview

voice_func(语音功能模块)位于 SDK 应用层,是语音玩具(voice_toy)与语音增强(voice_enhanced)两个应用工程共用的功能集合。从工程文件 AD24N_voice_enhanced.cbp 与 AD24N_voice_toy.cbp 可以看到,两个应用都通过 include 目录把 app/src/voice_func 及其子目录纳入编译,说明该模块是多应用共享的应用层框架。

模块按"一个运行状态 = 一个 toy_* 子模块"的方式组织,形成典型的状态机形态:

  • toy_main 是状态机的入口/调度核心;
  • 每个 toy_* 子模块代表一种可运行的功能状态,通常由 toy_xxx.c/h 加上 toy_xxx_key.c(按键处理)组成;
  • common/ 提供跨状态复用的公共服务:消息队列(common_msg)、设备管理(device_mge)、空闲处理(idle_deal)、简易文件播放(simple_play_file);
  • app_config 与 cpu/sh58/cpu_config 提供应用级与芯片级配置。

这种"状态即目录、状态即模块"的划分使每个功能状态可以独立开发、独立裁剪,通过工程 include 目录即可决定哪些状态参与编译,从而让同一套状态机框架同时服务于玩具和扩音器两种产品形态。

Architecture

flowchart TD
    subgraph sg_App["应用层 app/src"]
        subgraph sg_voice_func["voice_func 语音功能状态机"]
            ToyMain["toy_main.c/h<br/>状态机入口与调度"]
            AppConfig["app_config.c/h<br/>应用配置"]

            subgraph sg_common["common/ 公共服务"]
                CommonMsg["common_msg.c<br/>消息队列"]
                DeviceMge["device_mge.c/h<br/>设备管理"]
                IdleDeal["idle_deal.c<br/>空闲处理"]
                SimplePlay["simple_play_file.c/h<br/>简易文件播放"]
            end

            subgraph sg_states["toy_* 功能状态"]
                ToyIdle["toy_idle<br/>空闲"]
                ToyMusic["toy_music<br/>音乐"]
                ToyMidi["toy_midi<br/>MIDI"]
                ToySpeaker["toy_speaker<br/>扩音"]
                ToyLinein["toy_linein<br/>LineIn"]
                ToyRecord["toy_record<br/>录音"]
                ToyUpdate["toy_update<br/>升级"]
                ToyUsbSlave["toy_usb_slave<br/>USB 从机"]
                ToySoftoff["toy_softoff<br/>软关机"]
            end

            subgraph sg_cpu["cpu/ 芯片配置"]
                CpuConfig["cpu/sh58/cpu_config.c"]
            end
        end
    end

    ToyMain --> CommonMsg
    ToyMain --> DeviceMge
    ToyMain --> IdleDeal
    ToyMain --> SimplePlay
    ToyMain --> AppConfig
    ToyMain --> CpuConfig
    ToyMain --> ToyIdle
    ToyMain --> ToyMusic
    ToyMain --> ToyMidi
    ToyMain --> ToySpeaker
    ToyMain --> ToyLinein
    ToyMain --> ToyRecord
    ToyMain --> ToyUpdate
    ToyMain --> ToyUsbSlave
    ToyMain --> ToySoftoff
    ToyIdle --> CommonMsg
    ToyMusic --> CommonMsg
    ToyLinein --> CommonMsg

架构说明:

  • toy_main:状态机中枢。应用启动后由它初始化公共模块,并依据事件把执行权交给对应 toy_* 状态模块(依据目录结构与命名约定,具体调度函数未在本次读取范围内)。
  • common/ 四个公共模块:被 toy_main 与各状态模块共同依赖,承载消息传递、设备挂载/卸载、空闲任务和提示音播放等横向能力,避免各状态重复实现。
  • toy_* 状态模块:每个状态自包含 toy_xxx.c/h 主逻辑与 toy_xxx_key.c 按键处理,状态间通过公共消息机制切换。toy_midi 额外依赖 midi_config 与 midi_prog.h。
  • 配置层:app_config 提供应用级开关(是否使能某状态、默认音量等),cpu/sh58/cpu_config 提供芯片级配置,二者构成状态机的"裁剪与调参"入口。

模块结构与职责

以下模块清单依据工程文件 sdk/AD24N_voice_enhanced.cbp 的 include 目录与 README.md 的目录树整理(两者均已在本次探索中验证)。

模块路径(相对 sdk/app/src/voice_func)职责(依据命名与工程引用推断)
状态机入口toy_main.c / toy_main.h应用主入口,初始化公共模块并驱动状态切换
公共服务common/common_msg.c跨状态消息队列/消息分发
公共服务common/device_mge.c/h设备(U 盘、SD 卡等)挂载管理
公共服务common/idle_deal.c空闲任务处理
公共服务common/simple_play_file.c/h简易文件播放(提示音等)
应用配置app_config.c/h应用级功能开关与参数
芯片配置cpu/sh58/cpu_config.cSH58 芯片级配置
空闲状态toy_idle/toy_idle.c/h + toy_idle_key.c待机/主界面,接收事件并派发到各功能状态
音乐状态toy_music/音乐播放(工程 include 目录已引用)
MIDI 状态toy_midi/midi_config.c/h、midi_prog.hMIDI 音色/曲目配置与播放
扩音状态toy_speaker/扩音器(喇叭直通)模式
LineIn 状态toy_linein/toy_linein.c/h + toy_linein_key.c音频输入(AUX)播放
录音状态toy_record/录音功能
升级状态toy_update/固件升级流程
USB 从机状态toy_usb_slave/USB 从机(读卡器/声卡)模式
软关机状态toy_softoff/软关机/低功耗流程

两个应用工程通过 include 目录引用同一套模块:sdk/AD24N_voice_enhanced.cbp 与 sdk/AD24N_voice_toy.cbp 均包含 app/src/voice_func 及 common、toy_idle、toy_midi、toy_music 等目录,说明 voice_func 是 voice_toy 与 voice_enhanced 共同的应用层状态机框架。

状态机设计

基于"一状态一子模块"的组织方式,voice_func 的状态机可概括为:以 toy_idle 为驻留态(HOME),其余 toy_* 为可进入的功能态。这种设计与大多数嵌入式玩具/音箱产品一致:开机后进入空闲态,用户通过按键或消息请求进入某个功能态,功能结束后退回空闲态。

flowchart LR
    subgraph sg_Power["上电/下电"]
        PowerOn["上电"] --> ToyIdle["toy_idle 空闲"]
        ToySoftoff["toy_softoff 软关机"] -->|"唤醒"| ToyIdle
        ToyIdle -->|"关机事件"| ToySoftoff
    end

    subgraph sg_Func["功能状态"]
        ToyIdle -->|"播放事件"| ToyMusic["toy_music 音乐"]
        ToyIdle -->|"MIDI 事件"| ToyMidi["toy_midi MIDI"]
        ToyIdle -->|"扩音事件"| ToySpeaker["toy_speaker 扩音"]
        ToyIdle -->|"LineIn 事件"| ToyLinein["toy_linein LineIn"]
        ToyIdle -->|"录音事件"| ToyRecord["toy_record 录音"]
        ToyIdle -->|"升级事件"| ToyUpdate["toy_update 升级"]
        ToyIdle -->|"USB 事件"| ToyUsbSlave["toy_usb_slave USB 从机"]
    end

    ToyMusic -->|"结束/退出"| ToyIdle
    ToyMidi -->|"结束/退出"| ToyIdle
    ToySpeaker -->|"结束/退出"| ToyIdle
    ToyLinein -->|"结束/退出"| ToyIdle
    ToyRecord -->|"结束/退出"| ToyIdle
    ToyUpdate -->|"完成/重启"| ToyIdle
    ToyUsbSlave -->|"拔出/退出"| ToyIdle

设计意图:

  • 驻留态模型:toy_idle 作为唯一驻留态,承担事件入口与状态回收职责,避免功能态之间直接相互跳转带来的耦合;新功能只需实现"从 idle 进入"与"退回 idle"两个方向即可挂接。
  • 按键与逻辑分离:每个功能态目录内 toy_xxx_key.c 负责按键采集/映射,toy_xxx.c 负责业务逻辑,便于按键方案调整而不影响功能实现。
  • 可裁剪性:工程文件通过 include 目录决定编译哪些状态模块——AD24N_voice_enhanced.cbp 引用了全部 toy_* 目录,而具体产品可通过配置(app_config)或工程裁剪决定启用哪些状态。
  • 公共机制下沉:消息(common_msg)、设备(device_mge)、空闲(idle_deal)、播放(simple_play_file)全部放在 common/,保证所有状态共享同一套事件/资源管理,降低重复代码与状态间行为不一致的风险。

注意:上图中状态切换的具体触发条件(事件类型、按键映射)依据模块命名与常见嵌入式产品惯例推断;toy_main.c 中的实际消息分发与切换函数实现细节未在本次读取范围内。

Core Flow

状态机的一次典型事件流转(例如空闲态下插入设备并触发音乐播放)如下:

sequenceDiagram
    participant K as 按键/事件源
    participant CM as common_msg 消息队列
    participant TM as toy_main 调度
    participant ID as toy_idle 空闲态
    participant MU as toy_music 音乐态
    participant DM as device_mge 设备管理

    K->>CM: 产生事件消息(按键/插入)
    CM->>TM: 派发消息给当前状态
    TM->>ID: 当前状态=idle,转交事件
    ID->>ID: 判定事件类型
    ID->>DM: 请求设备就绪
    DM-->>ID: 设备就绪
    ID->>TM: 请求切换到 toy_music
    TM->>MU: 进入音乐状态
    MU->>CM: 注册/接收后续消息
    MU-->>CM: 播放完成/退出事件
    CM->>TM: 派发退出事件
    TM->>ID: 退回空闲状态

流程要点:

  1. 事件入队:外部事件(按键、插拔、消息)先进入 common_msg 消息机制,统一以消息形式驱动状态机,保证状态迁移的串行化与可追踪性。
  2. 当前状态消化事件:toy_main 依据当前所处状态把消息转交对应 toy_xxx 模块处理——空闲态收到播放事件后自行决策(包括调用 device_mge 确认设备就绪)。
  3. 状态切换:功能态完成初始化后即成为新"当前状态",后续消息由其消化;功能结束(播放完毕、拔出、退出)再通过消息切回 toy_idle。
  4. 公共依赖:设备管理、提示音播放等横向能力在切换过程中由 device_mge、simple_play_file 提供,状态模块不重复实现。

Usage Examples

工程引用:将 voice_func 状态模块纳入编译

下面摘自应用工程 sdk/AD24N_voice_enhanced.cbp,展示 voice_func 各状态子模块如何被工程以 include 目录的形式引用——这是状态机"可裁剪性"的落地机制:工程决定编译哪些 toy_*,即决定产品支持哪些状态。

<Add directory="app/src/voice_func" />
<Add directory="app/src/voice_func/common" />
<Add directory="app/src/voice_func/toy_music" />
<Add directory="app/src/voice_func/toy_idle" />
<Add directory="app/src/voice_func/toy_midi" />
<Add directory="app/src/voice_func/toy_speaker" />
<Add directory="app/src/voice_func/toy_linein" />
<Add directory="app/src/voice_func/toy_record" />
<Add directory="app/src/voice_func/toy_update" />
<Add directory="app/src/voice_func/toy_usb_slave" />
<Add directory="app/src/voice_func/toy_softoff" />

Source: AD24N_voice_enhanced.cbp

AD24N_voice_toy.cbp 同样引用 app/src/voice_func、app/src/voice_func/common、toy_music、toy_idle、toy_midi 等目录,证实 voice_func 是 voice_toy 与 voice_enhanced 两个应用共用的状态机框架。

目录树中的位置

README 中 voice_func 被明确标注为"语音功能模块",与 voice_toy(语音玩具应用)、voice_enhanced(扩音器应用)并列:

├── voice_func/         # 语音功能模块
├── voice_toy/          # 语音玩具应用
└── voice_enhanced/     # 扩音器应用

Source: README.md

状态机扩展示例(伪代码)

由于 toy_main.c 与各 toy_xxx.c 的具体实现未在本次探索中读取,此处不提供臆造的 C 代码。基于架构推断,扩展一个新状态"网络电台(toy_netradio)"需要:新建 toy_netradio/ 目录(含 toy_netradio.c/h 与按键文件),在 toy_idle 中增加进入该状态的事件分支,并在工程文件中追加 <Add directory="app/src/voice_func/toy_netradio" />。具体挂接方式请以 toy_main.c 与现有 toy_* 模块的实际实现为准。

Configuration Options

配置入口位于 sdk/app/src/voice_func/app_config.c/h(应用级)与 sdk/app/src/voice_func/cpu/sh58/cpu_config.c(芯片级)。由于实现文件未在本次读取范围内,以下仅列出已从工程结构确认的配置面,具体键名与默认值请阅读对应源码:

配置面文件作用(推断)本次是否读取
应用功能开关app_config.c/h使能/关闭各功能状态、默认参数否(未读取)
芯片级配置cpu/sh58/cpu_config.cSH58 芯片时钟/外设/功耗配置否(未读取)
MIDI 配置toy_midi/midi_config.c/h、midi_prog.hMIDI 音色、曲目程序数据否(未读取)
工程裁剪sdk/AD24N_voice_enhanced.cbp / sdk/AD24N_voice_toy.cbp决定编译哪些 toy_* 状态模块是(已确认)

Failure Modes, Edge Cases & Concurrency

以下内容结合 voice_func 的架构形态(状态机 + 消息驱动 + 设备管理)推导,属于对设计约束的分析;具体代码级处理方式需以实际源码为准。

  • 状态切换竞态:状态机以 common_msg 消息队列串行驱动,事件在队列中排队处理,天然避免多任务同时进入状态切换临界区。风险点在于消息在切换瞬间到达——若 toy_main 未做"切换期间挂起新事件"或"切换后重新派发"处理,可能出现事件丢失或状态错乱。实现时应确认 toy_main 对"切换中消息"的排队/缓存策略。
  • 设备未就绪:toy_idle 进入音乐/录音等依赖存储设备的状态前,须先通过 device_mge 确认设备挂载;设备拔出属于高频边界场景,功能态需在播放中处理拔出事件并安全退回 toy_idle,避免访问失效句柄。
  • 软关机与唤醒:toy_softoff 与 toy_idle 互为上下电的两端。低功耗场景下唤醒源(按键/事件)必须能重新拉起消息队列,否则可能卡死在软关机态;这是玩具类产品最常见的现场问题点。
  • 升级态的原子性:toy_update 一旦进入升级流程,通常要求中断其他状态事件,升级失败/中断后的回退策略(重启回 idle 或进入恢复模式)决定产品是否变砖,属于必须重点验证的状态。
  • 功能态互斥:架构上功能态之间不直接跳转,统一经 toy_idle 中转。若某个功能态被设计为可抢占(如升级打断音乐),需由 toy_main 提供优先级机制,否则各状态自行抢占会造成资源冲突(如 I2S/Codec 同时被两个状态占用)。

Performance & Operational Considerations

  • 事件吞吐:所有交互都经过 common_msg 队列,队列深度决定极端按键连击/高频插拔下是否丢事件;玩具产品按键消抖与消息节流通常在 toy_xxx_key.c 层完成。
  • 资源复用:simple_play_file、device_mge 等公共模块被所有状态共享,其内部缓冲/句柄在状态切换时必须释放干净(由 toy_main 统一调度或各状态退出钩子保证),否则长时运行后出现资源泄漏。
  • 编译裁剪:通过工程 include 目录裁剪 toy_* 可显著影响固件体积与启动时间;app_config 中的功能开关则提供运行期裁剪手段,两者配合可覆盖不同产品 SKU。
  • 调试建议:排查状态异常时,先确认当前所处状态与最近一次消息(common_msg 可打印消息流),再核对设备状态(device_mge);状态机类问题 90% 集中在"事件在切换窗口到达"与"设备未就绪即进入功能态"两类。

Extension Points

  • 新增功能状态:在 voice_func/ 下新建 toy_xxx/ 目录(业务逻辑 + 按键处理),在 toy_idle 增加进入分支,并在应用工程(cbp)include 目录中追加引用,即可为状态机挂接新功能。
  • 按键方案定制:各 toy_xxx_key.c 独立于业务逻辑,修改按键映射/组合键不影响功能实现。
  • 公共能力下沉:跨状态复用的能力(消息、设备、播放、空闲任务)应放入 common/ 并在 toy_main 初始化,保持状态模块聚焦业务。
  • 多产品复用:voice_toy 与 voice_enhanced 共用同一套状态机框架,通过工程级 include 目录与 app_config 差异化配置即可派生出不同产品固件。

Tests

本次探索未发现 voice_func 目录下的独立测试文件(该 SDK 为嵌入式 MCU 工程,测试通常以板级验证/串口日志形式进行)。建议的验证矩阵:每个功能态的进入/退出、设备热插拔、状态切换竞态(连击按键)、软关机唤醒、升级中断回退、长时间运行资源泄漏检查。

Related Links

  • README.md — 工程目录总览
  • AD24N_voice_enhanced.cbp — 扩音器应用工程(voice_func 引用)
  • AD24N_voice_toy.cbp — 语音玩具应用工程(voice_func 引用)
  • app_config.c — 应用配置
  • toy_main.c — 状态机入口(实现细节待读)
  • common_msg.c — 消息队列
  • toy_idle.c — 空闲状态
Prev
扩音器应用 voice_enhanced
Next
应用公共框架与配置