Audio In

概述

音频采集模块,数据来源支持数字麦(PDM)H_ADCECHO(内循环来自于 aout 的回声数据);采集到的音频数据存储至内存或者输出至其他模块使用。

输入源

  • ADC

  • PDM

  • ECHO_PCM

功能模块

  • 去直流滤波器(DC Filter)

  • 录制通路音量调节

  • 增益粗调

  • 增益细调

存储 PCM FIFO

  • PCM0 FIFO

  • PCM1 FIFO

  • PCM2 FIFO

功能特性

ADC

  • ADC 输入时钟选择,参考结构体 GX_HAL_AIN_ADC_CLK

    • H_ADC CLK 0

    重要

    注意:APUS ADC 数量配置最大只支持一路,配置时只有 GX_HAL_AIN_ADC_CLK_0

    示例代码

        GX_HAL_AIN_INPUT_ADC adc = {
            .adc_clk_sel = GX_HAL_AIN_ADC_CLK_0,  //ADC clk 选择 clk0,该芯片只支持 adc_clk_0
        };
        gx_hal_ain_adc_set_input(&adc);
    

PDM

当选择数据输入来源于 PDM 时,需要配置管脚复用功能,对应管脚功能分别配置为 PDM_CLK 和 PDM_DATA。

  • 时钟模式选择,参考结构体 GX_HAL_AIN_PDM_CLK_MODE

    • master 模式

    • slave 模式(时钟来自于外部)

    重要

    注意:选择 PDM 时钟模式为 slave 模式时,需要调用时钟配置接口 gx_clk_mod_set_src(GX_CLK_MOD_PDM, GX_CLK_MOD_AUD_SYS_PDM);

  • 输入时钟选择,参考结构体 GX_HAL_AIN_PDM_CLK

    • 1024KHz

    • 2048KHz

    • 3072KHz

    • 6144KHz

    重要

    注意:选择 PDM 时钟模式为 slave 模式时,为保证数据正确,输入时钟的配置必须与外部提供的时钟一致。

    示例代码

        /*PDM 时钟模式为 master*/
        GX_HAL_AIN_INPUT_PDM pdm = {
            .pdm_clk_mode = GX_HAL_AIN_PDM_CLK_MASTER, //PDM 时钟模式 master 模式
            .pdm_clk_sel = GX_HAL_AIN_PDM_CLK_6144K,  //PDM 时钟 6.144M
        };
        gx_hal_ain_pdm_set_input(&pdm);
    
        /*PDM 时钟模式为 slave*/
        GX_HAL_AIN_INPUT_PDM pdm = {
            .pdm_clk_mode = GX_HAL_AIN_PDM_CLK_SLAVE, //PDM 时钟模式 slave 模式
            .pdm_clk_sel = GX_HAL_AIN_PDM_CLK_6144K,  //PDM 时钟 6.144M(根据外部提供的时钟进行配置)
        };
        if (pdm.pdm_clk_mode == GX_HAL_AIN_PDM_CLK_SLAVE) {
            gx_clk_mod_set_src(GX_CLK_MOD_PDM, GX_CLK_MOD_AUD_SYS_PDM);
        }
        gx_hal_ain_pdm_set_input(&pdm);
    

ECHO

  • 输入采样率选择,参考结构体 GX_HAL_AIN_ECHO_PCM_FS

    • 16KHz

    • 32KHz

    • 48KHz

    重要

    注意:echo 采样率选择需要和 audio out 模块采样率配置对应

    示例代码

        GX_HAL_AIN_INPUT_ECHO echo = {
            .echo_pcm_fs = GX_HAL_AIN_ECHO_PCM_FS_48K,  //ECHO 输入采样率 48KHz
        };
        gx_hal_ain_echo_set_input(&echo);
    

DC Filter

去直流滤波器,可选择是否开启,也可配置滤波器参数。

去直流滤波器使能配置在 GX_HAL_AIN_CHANNEL_CFG 结构体下的 dcf_enable。

通过函数 gx_hal_ain_dcf_set_params 配置滤波器参数。

备注

无特殊需求不需要改动。

增益粗调

增益粗调的调整步进为 6dB,只能增大音量,不能减小音量(每增加 6dB 即为音量放大两倍,如果音量增加 n*6dB 即为音量放大 2^n 倍)

需要调整时配置结构体 GX_HAL_AIN_GAIN 的 coarse 成员

  • 0 为无增益,1 为增加 6dB,向上配置步进为 6dB,最大可配置 9(增加 54dB)。

增益细调

增益细调,最小精度为 0.001dB

计算公式是:fine = 8192*pow(10, (fine_vol_dB/20.0));

  • fine = 8192:无增益无衰减(默认值)

  • 8192 < fine < 32747:音量放大 0~12dB

  • 0 < fine < 8192:音量衰减 0~78dB

    重要

    注意:fine 配置为 0 时为静音。计算公式中的 fine_vol_dB 为需要调整的音量大小(如 10dB 或 -5dB)。

需要调整时配置结构体 GX_HAL_AIN_GAIN 的 fine 成员。

示例代码

    GX_HAL_AIN_GAIN gain = {
        .fine = 8192,  //增益细调,8192 为默认值无增益无衰减
        .coarse = 0,   //增益粗调,0 为默认值无增益无衰减
    };
    gx_hal_ain_pcmw_set_gain(&gain, 1);

Route PCM

  • route 通道参数相关配置,参考结构体 GX_HAL_AIN_CHANNEL_CFG

    示例代码

        GX_HAL_AIN_CHANNEL_CFG ch_cfg = {
            .source = GX_HAL_AIN_CHN_SRC_ADC,  //PCM 数据来源选择来源于 ADC
            .endian = GX_HAL_AIN_PCM_ENDIAN_LITTLE_16BIT,  //PCM 数据存储大小端为 16bit 小端存储
            //... 其余成员使用时按需配置
        };
        gx_hal_ain_pcmw_start(&ch_cfg, 3);
    
  • PCM 录制相关配置见 \ref GX_HAL_AIN_PCMW_CFG(配置函数 \ref gx_hal_ain_pcmw_start)

    • 存储位宽 GX_HAL_AIN_PCMW_BIT_SIZE

    • 单次写入 pcm 门限 GX_HAL_AIN_PCMW_FIFO_THRESHOLD

    • 一帧单个声道的 pcm 样点数(中断上报 pcm 样点数)

      重要

      注意:一帧的样点数最好是 32 的倍数,非 32 的倍数中断时间间隔会稍微有点误差。buffer 大小必须大于等于两帧。

    • 单个 buffer 的大小

      重要

      注意:单个 buffer 大小必须为 128 的倍数且必须大于等于两帧。

    • 每个 buffer 的起始地址 (物理地址) (该芯片最大可用 pcm buffer 为三个)

      重要

      注意:buffer 的起始地址必须 8 字节对齐,为保证数据完整性,最好 32 字节对齐。

    • PCM 写完成中断回调函数 GX_HAL_AIN_PCMW_CB

    示例代码

        GX_HAL_AIN_PCMW_CFG pcm = {
            .bit_size = GX_HAL_AIN_PCMW_BS_16,  //存储位宽 16bit 存储
            .fifo_threshold = GX_HAL_AIN_PCMW_FT_HALF,  //二分之一门限(FIFO 内部存满 64 字节数据后写入内存)
            .cb_func = ain_func_cb, //中断处理函数,函数指针
            // ... 其余成员使用时按需配置
        };
        gx_hal_ain_pcmw_start(&pcm, 1);
    

示例代码

ADC 输入,数据存储至 PCM(SRAM)

    GX_HAL_AIN_INPUT_ADC adc = {
        .adc_clk_sel = GX_HAL_AIN_ADC_CLK_0,  //adc clk 选择,该芯片只支持 adc_clk_0
    };
    gx_hal_ain_adc_set_input(&adc);

    GX_HAL_AIN_CHANNEL_CFG channel_cfg[3];
    unsigned int channel_num = 3; //实际使用中按需配置,该芯片最大 3

    GX_HAL_AIN_PCMW_CFG pcm = {
        .bit_size = GX_HAL_AIN_PCMW_BS_16,  //存储位宽 16bit 存储
        .fifo_threshold = GX_HAL_AIN_PCMW_FT_HALF,  //二分之一门限(FIFO 内部存满 64 字节数据后写入内存)
        .cb_func = ain_func_cb, //中断处理函数 (函数指针),使用时填入实现的中断回调函数名
        .buffer_size = 1024; //PCM buffer 大小,实际使用按需配置
        .frame_pcm_num = 128; //中断上报 PCM 样点数,实际使用按需配置
    };

    for (int i = 0; i < channel_num; ++i) {
        channel_cfg[i].dcf_enable = 1;
        channel_cfg[i].endian = GX_HAL_AIN_PCM_ENDIAN_LITTLE_16BIT;
        channel_cfg[i].source = GX_HAL_AIN_CHN_SRC_ADC;
        channel_cfg[i].channel = 0;
        channel_cfg[i].enable = 1;
        pcmw_cfg.buffer_saddr[i] = (void *)0x2000000; //举例,实际使用按需配置
    }

    gx_hal_ain_pcmw_set_output(channel_cfg, channel_num);

    gx_hal_ain_pcmw_start(&pcmw_cfg, channel_num);

PDM 输入,数据存储至 PCM(SRAM)

    GX_HAL_AIN_INPUT_PDM pdm = {
        .pdm_clk_mode = GX_HAL_AIN_PDM_CLK_MASTER, //PDM 时钟模式 master 模式
        .pdm_clk_sel = GX_HAL_AIN_PDM_CLK_6144K,  //PDM 时钟 6.144M
    };
    gx_hal_ain_pdm_set_input(&pdm);

    GX_HAL_AIN_CHANNEL_CFG channel_cfg[3];
    unsigned int channel_num = 3; //实际使用中按需配置,该芯片最大 3

    GX_HAL_AIN_PCMW_CFG pcm = {
        .bit_size = GX_HAL_AIN_PCMW_BS_16,  //存储位宽 16bit 存储
        .fifo_threshold = GX_HAL_AIN_PCMW_FT_HALF,  //二分之一门限(FIFO 内部存满 64 字节数据后写入内存)
        .cb_func = ain_func_cb, //中断处理函数 (函数指针),使用时填入实现的中断回调函数名
        .buffer_size = 1024; //PCM buffer 大小,实际使用按需配置
        .frame_pcm_num = 128; //中断上报 PCM 样点数,实际使用按需配置
    };

    for (int i = 0; i < channel_num; ++i) {
        channel_cfg[i].dcf_enable = 1;
        channel_cfg[i].endian = GX_HAL_AIN_PCM_ENDIAN_LITTLE_16BIT;
        channel_cfg[i].source = GX_HAL_AIN_CHN_SRC_ADC;
        channel_cfg[i].channel = 0;
        channel_cfg[i].enable = 1;
        pcmw_cfg.buffer_saddr[i] = (void *)0x2000000; //举例,实际使用按需配置
    }

    gx_hal_ain_pcmw_set_output(channel_cfg, channel_num);

    gx_hal_ain_pcmw_start(&pcmw_cfg, channel_num);