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

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

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

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

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

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

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

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

音频编码与录音

本文档介绍 AD24N GP-MCU SDK 中音频编码(Audio Encoding)与录音(Recording)子系统的完整实现:从 ADC 采集链路、编码器抽象框架(ENC_OPS)、IMA ADPCM / MP2 编码器注册,到 toy_record 录音应用与 norfs 文件系统的存储与回放流程。

Purpose and Scope

本页覆盖以下内容:

  • 编码器抽象层:EN_FILE_IO / ENC_DATA_INFO / ENC_OPS 接口定义,以及 IMA ADPCM、MP2 等编码器如何接入(audio_enc_api.h)。
  • 编码管理器(encoder_mge):enc_obj 控制块、kick_encode_isr / kick_wfile_isr 中断驱动流水线、start_encode / stop_encode 的启停语义(encoder_api.c)。
  • ADC 采集物理链路:rec_phy_init / rec_phy_suspend、cbuf_adc 环形缓冲、ANS(环境降噪)可选挂接。
  • 录音应用:toy_record 模块(toy_record.c / toy_record_key.c)以及录音文件写入/回读 NOR Flash 的实现(enc_in_norfs.c)。

本页不覆盖解码器子系统(decoder_api)、音效处理(sound_effect_api)、文件系统通用抽象(vfs/device_mge)的完整细节——这些属于各自的 catalog 页面,仅在数据流经过时提及。

Overview

AD24N 是杰理科技(Jieli Tech)面向 GP-MCU 应用的音频 SoC。其录音链路是典型的"低功耗、低延迟、中断驱动"嵌入式音频设计:麦克风信号经 ADC 采样后写入环形缓冲,编码器在软中断(IRQ_SOFT1/IRQ_SOFT2)上下文中被"踢"(kick)动,以块为单位读取 PCM 数据并输出压缩码流,最终由写文件中断把码流落盘到 NOR Flash。

系统支持两种编码器家族:

  • IMA ADPCM(A 格式):通过 get_ima_code_ops() 获取操作集,ENC_DATA_INFO.br 字段被解释为 blockSize(典型 256/512/1024/2048,超过 2048 会被限制),适合低码率、低算力的语音录音。
  • MP2 家族:get_mp2_ops()(标准 MP2)与 get_mp2standard_ops(),br 字段被解释为 bitrate,用于对音质要求更高的场景。

录音文件以"索引文件"(rec_file_index)形式保存在 norfs 文件系统上,回放时通过 FS_IOCTL_FS_INDEX 按索引打开并交给解码器。

Architecture

flowchart TD
    subgraph sg_HW["硬件层"]
        MIC["麦克风输入"]
        ADC["Audio ADC 通道"]
    end

    subgraph sg_Capture["采集层 (encoder_api.c)"]
        CBUF["cbuf_adc 环形缓冲<br/>(.rec_data 段)"]
        REC_SOUND["rec_sound (sound_out_obj)"]
        ANS["ANS 降噪链路<br/>(可选, ANS_EN)"]
        KICK["kick_encode_api / kick_encode_isr"]
    end

    subgraph sg_ENC["编码管理层 (encoder_mge)"]
        ENC_OBJ["enc_obj 控制块"]
        SOFT1["IRQ_SOFT1 编码中断"]
        SOFT2["IRQ_SOFT2 写文件中断"]
        ENC_OPS["ENC_OPS 操作集"]
    end

    subgraph sg_CODEC["编码器列表 (list/)"]
        ADPCM["a_encoder.c<br/>IMA ADPCM"]
        MP2["mp3_encoder.c / ump3_encoder.c<br/>MP2 家族"]
    end

    subgraph sg_APP["录音应用 (toy_record)"]
        TOY["toy_record.c / toy_record_key.c"]
        NORFS["enc_in_norfs.c<br/>norfs 文件存储"]
    end

    MIC --> ADC
    ADC -->|"regist_audio_adc_channel"| REC_SOUND
    REC_SOUND --> CBUF
    REC_SOUND -->|"link_ans_sound (可选)"| ANS
    ANS --> CBUF
    CBUF -->|"kick 触发"| KICK
    KICK --> SOFT1
    SOFT1 --> ENC_OBJ
    ENC_OBJ --> ENC_OPS
    ENC_OPS --> ADPCM
    ENC_OPS --> MP2
    ENC_OBJ -->|"码流输出"| SOFT2
    SOFT2 --> NORFS
    TOY -->|"Encode_Control 驱动"| ENC_OBJ
    TOY --> NORFS
    NORFS -->|"vfs_mount / vfs_createfile / decoder_io"| ADC

架构解读: 整条链路自下而上分为五层。硬件层(ADC)通过 regist_audio_adc_channel 把采样数据灌入 rec_sound 输出对象;采样数据经(可选的)ANS 链路进入 cbuf_adc 环形缓冲。编码管理层由软中断驱动:kick_encode_api 在 ADC 数据就绪时被调用,触发 kick_encode_isr 从缓冲取 PCM 并调用 ENC_OPS.run 完成压缩;压缩码流再通过写文件中断(IRQ_SOFT2)交给 norfs 落盘。toy_record 应用负责编排整条链路(创建文件 → 启动编码 → 停止编码 → 同步落盘),并通过 rec_file_index 管理录音文件的索引,便于后续回放。

flowchart LR
    subgraph sg_API["公开接口 (audio_enc_api.h)"]
        OPS["ENC_OPS<br/>need_buf / open / run"]
        IO["EN_FILE_IO<br/>input_data / output_data"]
        INFO["ENC_DATA_INFO<br/>sr / br"]
    end

    OPS -->|"get_ima_code_ops()"| ADPCM["IMA ADPCM 编码器"]
    OPS -->|"get_mp2_ops()"| MP2A["MP2 编码器"]
    OPS -->|"get_mp2standard_ops()"| MP2B["MP2 Standard 编码器"]

编码器通过 ENC_OPS 统一抽象暴露:need_buf() 返回编码器所需工作缓冲大小,open() 以缓冲指针、数据信息(采样率/码率)和文件 IO 回调初始化编码器,run() 执行一次编码块。这种"操作集 + 回调"的设计使得编码管理器无需关心具体算法,新增编码器只需实现三个函数并注册操作集。

编码管理器与物理层实现

编码管理器的物理层实现在 sdk/app/bsp/common/encoder/encoder_api.c。其核心是 enc_obj(enc_hdl 全局控制块)与两条中断(IRQ_SOFT1 编码、IRQ_SOFT2 写文件)组成的双缓冲流水线。

ADC 采集物理层初始化

rec_phy_init() 完成环形缓冲初始化与 ADC 通道注册:

cbuffer_t cbuf_adc AT(.rec_data);
u8 adc_buff[512 * 10] AT(.rec_data) ;

void rec_phy_init(void)
{
    memset(&rec_sound, 0, sizeof(rec_sound));

    cbuf_init(&cbuf_adc, &adc_buff[0], sizeof(adc_buff));
    rec_sound.p_obuf = &cbuf_adc;        //cbuf_adc为audio_adc的数据

    sound_out_obj *p_curr_sound = &rec_sound;

#if (defined(ANS_EN) && (ANS_EN))
    cbuf_init(&cbuf_ans, &ans_buff[0], sizeof(ans_buff));   //cbuf_ans 为link
    p_curr_sound = link_ans_sound(p_curr_sound, &cbuf_ans, read_audio_adc_sr());
#endif

    if (p_curr_sound != &rec_sound) {
        stream_sound_init(&rec_sound, kick_encode_api);
        regist_audio_adc_channel(&rec_sound, (void *)kick_sound);
    } else {
        regist_audio_adc_channel(&rec_sound, (void *)kick_encode_api);
    }

    enc_in_sound = p_curr_sound;
    rec_sound.enable |= B_DEC_RUN_EN | B_DEC_FIRST;
}

Source: encoder_api.c

设计意图:cbuf_adc(5 KB,位于 .rec_data 内存段)是 ADC 采样数据与编码器之间的解耦缓冲。当 ANS_EN 编译开关打开时,采集链路会插入 ANS(环境降噪)处理节点:link_ans_sound 返回新的 sound 对象,此时 ADC 数据先写入 cbuf_ans,经 ANS 处理后进入 cbuf_adc,且 ADC 通道的回调切换为 kick_sound(驱动 ANS 处理)。无论是否启用 ANS,最终由 regist_audio_adc_channel 注册的"踢"回调保证编码中断被及时触发。

编码启停控制

start_encode() 与 stop_encode() 控制整条录音流水线的运行:

void start_encode(void)
{
    START_ADC_RUN;
    audio_adc_enable(MIC_PGA_G);
}
void stop_encode(void *pfile, u32 dlen)
{
    enc_obj *obj = enc_hdl;
    u32 err;
    audio_adc_disable();
    STOP_ADC_RUN;
    log_info("stop encode\n");
    if (NULL == enc_hdl) {
        rec_phy_suspend();
        return;
    }
    obj->enable |= B_ENC_STOP;

    log_info("stop encode A\n");
    while (0 != cbuf_get_data_size(obj->p_ibuf)) {
        if (obj->enable & B_ENC_FULL) {
            break;
        }
        kick_encode_isr();
        delay(100);
    }

    log_info("stop encode C\n");
    while (0 != cbuf_get_data_size(obj->p_obuf)) {
        if (obj->enable & B_ENC_FULL) {
            break;
        }
        kick_wfile_isr();
        delay(100);
    }
    log_info("stop encode D\n");
    obj->enable &= ~B_ENC_ENABLE;
    HWI_Uninstall(IRQ_SOFT1_IDX);
    HWI_Uninstall(IRQ_SOFT2_IDX);

    u32 flen = dlen;
    err = vfs_ioctl(pfile, FS_IOCTL_FILE_SYNC, (int)&flen);
    rec_phy_suspend();
}

Source: encoder_api.c

设计意图:stop_encode 是一个"优雅停机"例程——先关闭 ADC 采集(audio_adc_disable + 清除 B_DEC_RUN_EN | B_REC_RUN),再置 B_ENC_STOP 标志,然后主动轮询驱动输入缓冲(PCM)与输出缓冲(码流)逐步排空:只要缓冲里还有数据就反复调用 kick_encode_isr / kick_wfile_isr 推进流水线,直到缓冲清空或 B_ENC_FULL 标志出现(防止因缓冲未及时消费而永久阻塞)。排空完成后卸载两个软中断、调用 FS_IOCTL_FILE_SYNC 将文件数据同步落盘,最后挂起物理层。这一设计保证了停止录音时不会丢帧,且文件内容完整可回放。

录音应用:toy_record 模块

toy_record 是 SDK 中面向"玩具录音"(低成本语音备忘/留言)场景的录音应用,位于 sdk/app/src/voice_func/toy_record/。它由三个文件组成:

文件职责
toy_record.c录音主流程:录音状态机、编码控制、文件生命周期管理
toy_record_key.c按键触发:将物理按键事件翻译为录音开始/停止命令
toy_record.hEncode_Control 控制结构与模块间接口声明

Encode_Control 是贯穿整个录音子系统的核心控制结构,包含设备句柄(device)、文件系统句柄(pfs)、文件句柄(pfile)、设备索引(dev_index)与录音文件索引(rec_file_index)等字段,由录音应用在启动时填充。

录音文件在 norfs 上的创建与回读

录音数据的持久化由 enc_in_norfs.c 负责,它将 Encode_Control 映射为 norfs 文件操作:

int norfs_enc_file_create(Encode_Control *obj)
{
    int err = 0;

    obj->device = device_open(obj->dev_index);
    if (NULL == obj->device) {
        log_info("device_open null!\n");
        return E_DEV_NULL;
    }
    err = vfs_mount(&obj->pfs, obj->device, "norfs");
    if (err) {
        log_info("vfs_mount err:0x%x\n", err);
        device_close(obj->dev_index);
        return err;
    }
    err = vfs_createfile(obj->pfs, &obj->pfile, (u32 *)&obj->rec_file_index);
    if (err) {
        log_info("vfs_createfile err:0x%x\n", err);
        vfs_fs_close(&obj->pfs);
        device_close(obj->dev_index);
        return err;
    }

    log_info("REC FILE INDEX : %d\n", obj->rec_file_index);
    return err;
}

Source: enc_in_norfs.c

设计意图:norfs_enc_file_create 按"设备 → 文件系统 → 文件"的层次依次打开资源,任何一级失败都会逆序释放已获得的资源(device_close / vfs_fs_close),避免句柄泄漏。vfs_createfile 通过出参返回新建文件的索引 rec_file_index——这是 norfs 的按索引寻址模式,后续回放与删除都依赖该索引,而不是路径字符串。

回读侧使用同一套 Encode_Control,按索引打开文件后直接交给解码器:

dec_obj *norfs_enc_file_decode(Encode_Control *obj, u16 dec_type)
{
    int err = 0;

    obj->device = device_open(obj->dev_index);
    if (NULL == obj->device) {
        log_info("device_open null!\n");
        return NULL;
    }
    err = vfs_mount(&obj->pfs, obj->device, "norfs");
    if (err) {
        log_info("vfs_mount err:0x%x\n", err);
        device_close(obj->dev_index);
        return NULL;
    }
    err = vfs_ioctl(obj->pfs, FS_IOCTL_FS_INDEX, (int)&obj->rec_file_index);
    if (err) {
        log_info("vfs_ioctl err:0x%x\n", err);
        goto __norfs_enc_fs_exit;
    }
    err = vfs_openbyindex(obj->pfs, &obj->pfile, obj->rec_file_index);
    if (err) {
        log_info("vfs_createfile err:0x%x\n", err);
        goto __norfs_enc_fs_exit;
    }

    return decoder_io(obj->pfile, dec_type, NULL, 0);

__norfs_enc_fs_exit:
    vfs_fs_close(&obj->pfs);
    device_close(obj->dev_index);
    return NULL;
}

Source: enc_in_norfs.c

设计意图:回放前先用 FS_IOCTL_FS_INDEX 把目标文件索引设置到文件系统,再通过 vfs_openbyindex 打开。错误路径统一收敛到 __norfs_enc_fs_exit 标签做资源释放(goto 集中式错误处理,嵌入式 C 的典型风格)。成功时 decoder_io 直接返回解码器对象,录音→回放复用同一套文件访问抽象。

核心流程:一次完整录音的生命周期

sequenceDiagram
    participant Key as toy_record_key.c<br/>按键处理
    participant App as toy_record.c<br/>Encode_Control
    participant FS as enc_in_norfs.c<br/>norfs 文件系统
    participant PHY as encoder_api.c<br/>rec_phy / enc_obj
    participant CODEC as ENC_OPS<br/>ADPCM / MP2

    Key->>App: 按键事件(开始录音)
    App->>FS: norfs_enc_file_create(obj)
    FS-->>App: pfile + rec_file_index
    App->>PHY: rec_phy_init() / 注册 ADC 通道
    PHY->>CODEC: enc_obj 绑定 ENC_OPS.open(sr, br, IO 回调)
    App->>PHY: start_encode() (audio_adc_enable)
    loop 录音中(ADC 数据就绪)
        PHY->>PHY: kick_encode_isr (IRQ_SOFT1)
        PHY->>CODEC: ENC_OPS.run() 压缩一帧
        CODEC->>PHY: 码流写入 enc_obj.p_obuf
        PHY->>FS: kick_wfile_isr (IRQ_SOFT2) 写盘
    end
    Key->>App: 按键事件(停止录音)
    App->>PHY: stop_encode(pfile, dlen)
    Note over PHY: 排空 p_ibuf / p_obuf,卸载中断<br/>FS_IOCTL_FILE_SYNC 落盘
    App->>FS: 关闭文件 / 卸载文件系统
    App->>PHY: rec_phy_suspend() / 关闭 ADC
    App->>FS: norfs_enc_file_decode(obj, dec_type) 回放
    FS->>App: decoder_io(pfile, dec_type)

流程要点:

  1. 创建文件:按键触发开始录音后,先走 norfs_enc_file_create 建立文件句柄并获得文件索引;失败则直接退出,不会启动 ADC。
  2. 物理层就绪:rec_phy_init 初始化 cbuf_adc 并注册 ADC 通道回调(kick_encode_api),enc_obj 绑定编码器操作集。
  3. 启动采集:start_encode 使能 ADC 与运行标志,采样数据开始流入环形缓冲。
  4. 中断驱动编码:每次 ADC 数据就绪,kick_encode_isr(IRQ_SOFT1)从输入缓冲取 PCM 并调用 ENC_OPS.run 压缩;码流进入输出缓冲后由 kick_wfile_isr(IRQ_SOFT2)写盘。两条中断解耦"编码"与"写文件"两个不同速率的阶段,避免慢速 Flash 写入拖慢编码。
  5. 优雅停机:stop_encode 先停 ADC,再轮询驱动双缓冲排空,最后同步文件并挂起物理层,保证最后一帧不丢失。
  6. 回放:通过 norfs_enc_file_decode 按索引打开文件,交给解码器播放。

编码器接口与数据契约

audio_enc_api.h 定义了编码器与上层之间的全部契约,是新增编码器必须遵循的接口:

typedef struct _EN_FILE_IO_ {
    void *priv;
    u16(*input_data)(void *priv, s16 *buf, u16 len);
    u32(*output_data)(void *priv, u8 *buf, u16 len);
} EN_FILE_IO;

typedef  struct   _ENC_DATA_INFO_ {
    u16 sr;            ///<sample rate
    u16 br;            ///<mp2的时候它是bitrate,但是adpcm的时候,它是blockSize,一般配成256/512/1024/2048,超过2048会被限制成2048
} ENC_DATA_INFO;

typedef struct _ENC_OPS {
    u32(*need_buf)();
    void (*open)(u8 *ptr, ENC_DATA_INFO *data_info, EN_FILE_IO *audioIO);
    u32(*run)(u8 *ptr);
} ENC_OPS;

ENC_OPS *get_ima_code_ops(void);
ENC_OPS *get_mp2_ops(void);
ENC_OPS *get_mp2standard_ops(void);

Source: audio_enc_api.h

接口语义:

  • EN_FILE_IO:编码器的 IO 回调对。input_data 由编码器调用以拉取 PCM(s16 采样),output_data 由编码器调用以吐出压缩码流(u8 字节)。priv 携带上层上下文(通常是 enc_obj),使回调无需全局变量。
  • ENC_DATA_INFO:编码参数。sr 为采样率;br 是多义字段——MP2 家族下是 bitrate,IMA ADPCM 下是 blockSize(256/512/1024/2048,硬件限制上限 2048)。
  • ENC_OPS:编码器操作集。need_buf 返回工作缓冲需求,open 完成初始化(绑定参数与 IO 回调),run 执行一次编码推进。ptr 是编码器私有工作缓冲,由上层按 need_buf 结果分配。

SDK 内置三种操作集工厂函数:get_ima_code_ops()(IMA ADPCM,实现于 list/a_encoder.c)、get_mp2_ops() 与 get_mp2standard_ops()(MP2 家族,实现于 list/mp3_encoder.c / list/ump3_encoder.c)。对应的头文件 a_encoder.h / mp3_encoder.h 位于 sdk/include_lib/encoder/list/,供上层通过 encoder_mge.h 统一调度。

配置选项

录音子系统的行为主要由编译期宏与编码参数决定:

配置项类型默认/示例说明
ANS_EN编译宏0(未定义时关闭)启用 ANS 环境降噪链路;开启后 rec_phy_init 会插入 cbuf_ans 与 link_ans_sound 节点,ADC 通道回调切换为 kick_sound
ENC_DATA_INFO.sru16由应用设定(如 8000/16000)编码采样率,同时用于 read_audio_adc_sr() 对齐 ADC 采样率
ENC_DATA_INFO.bru16ADPCM: 256/512/1024/2048;MP2: bitrateADPCM 下为 blockSize(上限 2048),MP2 下为 bitrate
cbuf_adc / adc_buff环形缓冲512 * 10 字节(.rec_data 段)ADC 采样与编码器之间的解耦缓冲,尺寸决定抗抖动能力
MIC_PGA_Gextern 常量由平台配置麦克风 PGA 增益,start_encode 时通过 audio_adc_enable 生效
dev_index(Encode_Control)设备索引由录音应用指定挂载 norfs 的设备编号,传给 device_open

内存布局说明: cbuf_adc、adc_buff 显式放置在 .rec_data 段,kick_encode_api 放置在 .audio_a.text.cache.L2——这体现了 SDK 对缓存(cache)与 DMA 一致性、以及低延迟中断路径的精细控制:热路径代码驻留 L2 cache 段以减少取指延迟,录音缓冲独立分段以便内存管理器按用途回收。

API 参考

rec_phy_init()

初始化 ADC 采集物理层:清零 rec_sound、初始化 cbuf_adc、按 ANS_EN 决定是否插入 ANS 链路、注册 ADC 通道回调、置位 B_DEC_RUN_EN | B_DEC_FIRST。

  • 无参数,无返回值。
  • 调用时机:每次录音会话开始前调用一次;与 rec_phy_suspend 成对使用。

rec_phy_suspend()

  • 无参数,无返回值。
  • 调用 stream_sound_uninit() 并 unregist_audio_adc_channel(&rec_sound),释放采集通道。

start_encode()

  • 无参数,无返回值。
  • 置位 B_DEC_RUN_EN | B_REC_RUN 并 audio_adc_enable(MIC_PGA_G),启动 ADC 采样。通常在文件创建成功后调用。

stop_encode(void *pfile, u32 dlen)

停止编码并同步落盘。

参数:

  • pfile (void*):录音文件句柄,用于 FS_IOCTL_FILE_SYNC。
  • dlen (u32):期望的同步数据长度。

行为: 关闭 ADC → 置 B_ENC_STOP → 轮询排空输入/输出缓冲(受 B_ENC_FULL 保护)→ 卸载 IRQ_SOFT1_IDX / IRQ_SOFT2_IDX → 文件同步 → rec_phy_suspend。

kick_encode_api(void *obj) / kick_encode_isr()

  • ADC 数据就绪回调,转发到编码中断处理。kick_encode_api 标注为 L2 cache 段热路径。

norfs_enc_file_create(Encode_Control *obj): int

打开设备、挂载 norfs、创建录音文件并获得索引。

参数: obj(Encode_Control*)——输出 pfs/pfile/rec_file_index。

返回: 0 成功;E_DEV_NULL 表示设备打开失败;其他非 0 为 vfs_mount / vfs_createfile 返回的错误码。

norfs_enc_file_decode(Encode_Control *obj, u16 dec_type): dec_obj *

按 rec_file_index 打开录音文件并创建解码器。

参数: obj(Encode_Control*)、dec_type(u16,解码器类型)。

返回: dec_obj * 解码器对象;失败返回 NULL(内部已做资源逆序释放)。

编码器工厂函数

函数返回对应编码器
get_ima_code_ops()ENC_OPS *IMA ADPCM(list/a_encoder.c)
get_mp2_ops()ENC_OPS *MP2(list/mp3_encoder.c)
get_mp2standard_ops()ENC_OPS *MP2 Standard(list/ump3_encoder.c)

故障模式、边界情况与并发

故障模式

场景表现处理方式
device_open 失败norfs_enc_file_create 返回 E_DEV_NULL录音直接中止,不挂载文件系统
vfs_mount 失败返回错误码并 device_close逆序释放设备句柄
vfs_createfile 失败返回错误码vfs_fs_close + device_close,无泄漏
回放打开失败norfs_enc_file_decode 返回 NULL统一 goto __norfs_enc_fs_exit 释放资源
缓冲消费停滞stop_encode 可能死等用 B_ENC_FULL 标志兜底跳出轮询

边界情况

  • blockSize 上限:ADPCM 的 br 超过 2048 会被限制为 2048,防止单个块过大导致缓冲溢出。
  • 空缓冲停机:stop_encode 在 enc_hdl == NULL 时直接 rec_phy_suspend 返回,避免空指针解引用。
  • FPGA 仿真模式:encoder_api.c 中 #if (0 == FPGA) 包裹了全部物理层实现,FPGA 平台下采集/中断路径由仿真环境另行提供。

并发与实时性

  • 编码与写文件分别在 IRQ_SOFT1 / IRQ_SOFT2 两个软中断上下文中执行,天然串行化,无需互斥锁;应用层通过 stop_encode 的轮询循环与中断协同,保证停机过程中缓冲的并发安全。
  • kick_encode_api 被放置在 .audio_a.text.cache.L2 段,确保 ADC 中断回调的取指延迟最小化——这是音频实时性敏感路径的典型优化。
  • 缓冲排空使用 delay(100) 让步,避免在中断上下文或主循环中忙等占用 CPU 过久。

扩展点

  1. 新增编码器:按 ENC_OPS 实现 need_buf/open/run 三函数 + 工厂函数(参考 get_ima_code_ops),在 encoder_api.c 中 #include 对应头文件即可接入现有调度流水线,无需改动 enc_obj 与中断框架。
  2. 启用 ANS 降噪:定义 ANS_EN 编译宏,采集链路自动插入 ANS 节点(cbuf_ans、link_ans_sound),ADC 回调自动切换为 kick_sound;上层调用方式不变。
  3. 更换存储介质:enc_in_norfs.c 全部通过 vfs/device 抽象访问存储,替换 "norfs" 挂载名为其他文件系统(如 fat)即可复用同一套录音流程。
  4. 按键扩展:toy_record_key.c 将按键事件翻译为录音命令,可在该层增加长按/双击等触发语义,不影响编码链路。

相关链接

  • encoder_api.c(编码物理层与启停控制)
  • enc_in_norfs.c(norfs 录音文件创建与回读)
  • audio_enc_api.h(编码器接口契约)
  • encoder_mge.h(编码管理器)
  • a_encoder.c(IMA ADPCM 编码器)
  • mp3_encoder.c / ump3_encoder.c(MP2 编码器)
  • toy_record.c / toy_record_key.c / toy_record.h(录音应用)

相关子系统请参考各自的 catalog 页面:解码器(decoder_api)、音效处理(sound_effect_api)、文件系统与设备管理(vfs / device_mge)。

Prev
音频解码器与 MIDI 播放
Next
音效算法(ANS、变调、变声、混响)