Skip to content

概念先知道

  • AUADC / AUDAC:音频 ADC(采集麦克风)与音频 DAC(驱动喇叭)的简称,本页让它们“回环”——采到什么就放什么。
  • 采样率:每秒采集多少个声音样本,例程 32kHz;采样率越高音质越好、数据量越大。
  • PDM vs ADC 麦克风:PDM 麦克风输出数字脉冲流(需开 Kconfig 开关),普通模拟麦克风走 ADC 差分通道。

例程功能简介

本页对应博流官方 SDK 的 auadc_audac_loopback 例程(examples/peripherals/audio/auadc_audac_loopback),演示音频采集(AUADC)+ 播放(AUDAC)回环

  • AUADC 以 32KHz、16bit 采集麦克风(DMA 搬运),AUDAC 通过 DMA 把同一份数据播放到喇叭;
  • 采集与播放各用一条 DMA 通道与 LLI 链表,形成“录-放”回环;
  • 每个 DMA 周期触发回调打印 scyle_n:N,用于观察数据流是否持续。
  • 同族例程examples/peripherals/audio/):auadc_record_to_mem(录音到内存)、audac_play_from_mem(从内存播放)、audio_dac_adc(DAC+ADC)、audio_dac_i2s_rec(DAC 播放 + I2S 录音)。

操作步骤

1
硬件准备

把麦克风接到 board_auadc_gpio_init() 对应的 AUADC 采集引脚(例程默认 ADC 差分通道 CH4/CH7),喇叭/耳机接到 AUDAC 输出引脚(board_audac_gpio_init())。

2
进入例程目录

在终端进入 SDK 的音频例程目录(前提:已按快速开始(Linux)Windows搭建好环境):

cd examples/peripherals/audio/auadc_audac_loopback
3
编译工程

执行编译命令。Ai-M62(BL616)与 Ai-M61(BL618)同属一个系列,统一填写引脚最少的 bl616 即可:

make CHIP=bl616 BOARD=bl616dk
4
烧录固件

用 USB 线连接开发板,按住 BOOT 键(Ai-M61-32S-Kit 为 IO2)不放、短按 EN/RST 进入下载模式,然后执行烧录(把串口号换成实际值):

make flash CHIP=bl616 COMX=/dev/ttyUSB0
5
运行验证

打开串口助手(波特率 2000000)。例程打印 audac case start 后启动采集与播放,向麦克风说话应能从喇叭听到回放(回环);DMA 每个周期打印 scyle_n:N,最后打印 audac case end

代码执行流程

例程从启动到运行的完整流程如下(图中的循环箭头表示反复执行):

例程调用的 API 介绍

bflb_auadc_init(auadc, config)

初始化音频 ADC。struct bflb_auadc_init_config_s 中:sampling_rate = AUADC_SAMPLING_RATE_32Kinput_mode(ADC/PDM)、data_format = 16BITfifo_threshold

参数

  • auadc:AUADC 设备句柄(bflb_device_get_by_name("auadc")
  • config:配置结构体指针

返回值:成功返回 0;失败返回负值错误码

把 AUADC 接收方向链接到 DMA,自动搬运采样数据。

参数

  • auadc:AUADC 设备句柄
  • enabletrue 链接 / false 断开

返回值:成功返回 0;失败返回负值错误码

bflb_auadc_feature_control(auadc, AUADC_CMD_RECORD_START, 0)

启动/停止录音采集。

参数

  • auadc:AUADC 设备句柄
  • cmdAUADC_CMD_RECORD_START 等命令

返回值:成功返回 0;失败返回负值错误码

bflb_audac_init / bflb_audac_feature_control(AUDAC_CMD_PLAY_START)(...)

初始化音频 DAC 并启动播放(DMA 输出)。

参数:同 AUADC 用法

返回值:成功返回 0;失败返回负值错误码

完整代码

以下为 auadc_audac_loopback/main.c 完整源码,与官方示例(examples/peripherals/audio/auadc_audac_loopback)一致;点灯引脚已适配 Ai-M61/62-32S-Kit 板载 RGB 灯,默认折叠,点击展开:

📜 点击展开 auadc_audac_loopback/main.c 完整代码
c
#include "bflb_auadc.h"
#include "bflb_audac.h"
#include "bflb_gpio.h"
#include "bflb_dma.h"
#include "board.h"

struct bflb_device_s *auadc_dma_hd;
struct bflb_device_s *audac_dma_hd;

struct bflb_device_s *auadc_hd;
struct bflb_device_s *audac_hd;

struct bflb_dma_channel_lli_pool_s auadc_dma_lli_pool[10];
struct bflb_dma_channel_lli_pool_s audac_dma_lli_pool[10];
uint16_t audio_loopback_buff[8 * 1000];

void auadc_dma_callback(void *arg)
{
    static uint16_t num = 0;
    num++;
    printf("scyle_n:%d\r\n", num);
}

/* audio adc init */
static void auadc_init(void)
{
    /* audio adc config */
    struct bflb_auadc_init_config_s auadc_init_cfg = {
        .sampling_rate = AUADC_SAMPLING_RATE_32K,
#ifdef CONFIG_AUDIO_MIC_PDM_MODE
        .input_mode = AUADC_INPUT_MODE_PDM_L,
#else
        .input_mode = AUADC_INPUT_MODE_ADC,
#endif
        .data_format = AUADC_DATA_FORMAT_16BIT,
        .fifo_threshold = 3,
    };

    /* auadc init */
    auadc_hd = bflb_device_get_by_name("auadc");
    bflb_auadc_init(auadc_hd, &auadc_init_cfg);
#ifndef CONFIG_AUDIO_MIC_PDM_MODE
    /* audio adc analog config */
    struct bflb_auadc_adc_init_config_s auadc_analog_init_cfg = {
        .auadc_analog_en = true,
        .adc_mode = AUADC_ADC_MODE_AUDIO,
        .adc_pga_mode = AUADC_ADC_PGA_MODE_AC_DIFFER,
        .adc_pga_posi_ch = AUADC_ADC_ANALOG_CH_4,
        .adc_pga_nega_ch = AUADC_ADC_ANALOG_CH_7,
        .adc_pga_gain = 21,
    };
    bflb_auadc_adc_init(auadc_hd, &auadc_analog_init_cfg);
#endif
    /* auadc enable dma */
    bflb_auadc_link_rxdma(auadc_hd, true);
}

/* audio adc dma init */
void auadc_dma_init(void)
{
    uint32_t dma_lli_cnt;
    struct bflb_dma_channel_lli_transfer_s transfers[1];
    struct bflb_dma_channel_config_s auadc_dma_cfg;

    auadc_dma_cfg.direction = DMA_PERIPH_TO_MEMORY;
    auadc_dma_cfg.src_req = DMA_REQUEST_AUADC_RX;
    auadc_dma_cfg.dst_req = DMA_REQUEST_NONE;
    auadc_dma_cfg.src_addr_inc = DMA_ADDR_INCREMENT_DISABLE;
    auadc_dma_cfg.dst_addr_inc = DMA_ADDR_INCREMENT_ENABLE;
    auadc_dma_cfg.src_burst_count = DMA_BURST_INCR4;
    auadc_dma_cfg.dst_burst_count = DMA_BURST_INCR4;
    auadc_dma_cfg.src_width = DMA_DATA_WIDTH_16BIT;
    auadc_dma_cfg.dst_width = DMA_DATA_WIDTH_16BIT;

    auadc_dma_hd = bflb_device_get_by_name("dma0_ch0");
    bflb_dma_channel_init(auadc_dma_hd, &auadc_dma_cfg);
    bflb_dma_channel_irq_attach(auadc_dma_hd, auadc_dma_callback, NULL);

    transfers[0].src_addr = (uint32_t)DMA_ADDR_AUADC_RDR;
    transfers[0].dst_addr = (uint32_t)audio_loopback_buff;
    transfers[0].nbytes = sizeof(audio_loopback_buff);

    dma_lli_cnt = bflb_dma_channel_lli_reload(auadc_dma_hd, auadc_dma_lli_pool, 10, transfers, 1);
    bflb_dma_channel_lli_link_head(auadc_dma_hd, auadc_dma_lli_pool, dma_lli_cnt);
}

/* audio dac init */
static void audac_init(void)
{
    /* audio dac config */
    struct bflb_audac_init_config_s audac_init_cfg = {
        .sampling_rate = AUDAC_SAMPLING_RATE_32K,
        .output_mode = AUDAC_OUTPUT_MODE_PWM,
        .source_channels_num = AUDAC_SOURCE_CHANNEL_SINGLE,
        .mixer_mode = AUDAC_MIXER_MODE_ONLY_L,
        .data_format = AUDAC_DATA_FORMAT_16BIT,
        .fifo_threshold = 3,
    };

    /* audio dac volume config */
    struct bflb_audac_volume_config_s audac_volume_cfg = {
        .mute_ramp_en = true,
        .mute_up_ramp_rate = AUDAC_RAMP_RATE_FS_32,
        .mute_down_ramp_rate = AUDAC_RAMP_RATE_FS_8,
        .volume_update_mode = AUDAC_VOLUME_UPDATE_MODE_RAMP,
        .volume_ramp_rate = AUDAC_RAMP_RATE_FS_128,
        .volume_zero_cross_timeout = AUDAC_RAMP_RATE_FS_128,
    };

    /* audac init */
    audac_hd = bflb_device_get_by_name("audac");
    bflb_audac_init(audac_hd, &audac_init_cfg);
    bflb_audac_feature_control(audac_hd, AUDAC_CMD_SET_VOLUME_VAL, (size_t)(-5 * 2));
    bflb_audac_volume_init(audac_hd, &audac_volume_cfg);
    /* audac enable dma */
    bflb_audac_link_rxdma(audac_hd, true);
}

/* audio dac dma init */
void audac_dma_init(void)
{
    uint32_t dma_lli_cnt;
    struct bflb_dma_channel_lli_transfer_s transfers[1];
    struct bflb_dma_channel_config_s audac_dma_cfg;

    audac_dma_cfg.direction = DMA_MEMORY_TO_PERIPH;
    audac_dma_cfg.src_req = DMA_REQUEST_NONE;
    audac_dma_cfg.dst_req = DMA_REQUEST_AUDAC_TX;
    audac_dma_cfg.src_addr_inc = DMA_ADDR_INCREMENT_ENABLE;
    audac_dma_cfg.dst_addr_inc = DMA_ADDR_INCREMENT_DISABLE;
    audac_dma_cfg.src_burst_count = DMA_BURST_INCR4;
    audac_dma_cfg.dst_burst_count = DMA_BURST_INCR4;
    audac_dma_cfg.src_width = DMA_DATA_WIDTH_16BIT;
    audac_dma_cfg.dst_width = DMA_DATA_WIDTH_16BIT;

    audac_dma_hd = bflb_device_get_by_name("dma0_ch1");
    bflb_dma_channel_init(audac_dma_hd, &audac_dma_cfg);

    transfers[0].src_addr = (uint32_t)audio_loopback_buff;
    transfers[0].dst_addr = (uint32_t)DMA_ADDR_AUDAC_TDR;
    transfers[0].nbytes = sizeof(audio_loopback_buff);

    dma_lli_cnt = bflb_dma_channel_lli_reload(audac_dma_hd, audac_dma_lli_pool, 10, transfers, 1);
    bflb_dma_channel_lli_link_head(audac_dma_hd, audac_dma_lli_pool, dma_lli_cnt);
}

int main(void)
{
    /* board init */
    board_init();

    printf("audac case start \r\n");

    /* gpio init */
    board_auadc_gpio_init();
    board_audac_gpio_init();

    /* auadc init */
    auadc_init();
    auadc_dma_init();
    bflb_dma_channel_start(auadc_dma_hd);
    bflb_auadc_feature_control(auadc_hd, AUADC_CMD_RECORD_START, 0);

    /* delay 10ms */
    bflb_mtimer_delay_ms(10);

    /* audac init */
    audac_init();
    audac_dma_init();
    bflb_dma_channel_start(audac_dma_hd);
    bflb_audac_feature_control(audac_hd, AUDAC_CMD_PLAY_START, 0);

    printf("audac case end \r\n");

    while (1) {
        bflb_mtimer_delay_ms(1);
    }
}

FAQ

喇叭没有声音

确认麦克风与喇叭接线(采集 CH4/CH7、AUDAC 输出引脚),确认 bflb_dma_channel_start 已调用且 DMA 中断正常;PDM 麦克风需在 Kconfig 开启 CONFIG_AUDIO_MIC_PDM_MODE 并接 PDM 引脚。

scyle_n 不增长

DMA 回调没触发:检查 DMA 通道是否被占用、LLI 链表是否够长(auadc_dma_lli_pool[10])、采集 FIFO 阈值与 DMA 配置是否匹配。

有回音/声音小

回环例程不做降噪与增益处理属正常;可调整 bflb_auadc_adc_init 中的 adc_pga_gain 麦克风增益。

遇到问题?

如有其他问题,请到统一的提问与讨论区:Ai-Thinker Discussions

Released under the MIT License. Build Time 2026-09-11 14:52:23