Analog Microphone
本示例实现采集 AMIC (Analog Microphone) 数据,并经 CODEC 编码为 PCM 语音数据。
AMIC 采集模拟语音数据,经 CODEC 编码,送到 I2S 接收 FIFO,利用 DMA 将数据搬运到 UART 。
PC 端通过串口助手接收 UART 传输的数据,使用音频解析软件(如 Audacity)解析数据,并播放录制的语音。
流程如下图所示。

CODEC AMIC 流程
环境需求
该示例支持以下开发套件:
Hardware Platforms |
Board Name |
---|---|
RTL8752H HDK |
RTL8752H EVB |
更多信息请参考 快速入门。
硬件连线
EVB 外接 AMIC 模块,连接 H0 和 1.8V,GND 和 GND,P2_6 和 MIC_P,P2_7 和 MIC_N;
EVB 外接 FT232 模块,连接 P3_2(UART TX)和 FT232 的 RX,P3_3(UART RX)和 FT232 的 TX。
编译和下载
该示例的工程路径如下:
Project file: board\evb\io_sample\CODEC\AMIC\mdk
Project file: board\evb\io_sample\CODEC\AMIC\gcc
请按照以下步骤操作构建并运行该示例:
打开工程文件。
按照 快速入门 中 编译 APP Image 给出的步骤构建目标文件。
编译成功后,在路径
mdk\bin
或gcc\bin
下会生成 app binapp_MP_xxx.bin
文件。按下 reset 按键,开始运行。
测试验证
准备阶段
启动 PuTTY 或 UartAssist 等 PC 终端,连接到使用的 COM 端口,并进行以下 UART 设置:
波特率: 3000000
8 数据位
1 停止位
无校验
无硬件流控
启动音频解析软件。
测试阶段
开始录音到录音完成,采集到的语音数据,Codec 编码为 PCM 数据后通过 UART 发送到 PC 终端。
从 PC 终端复制解码数据到新建 ASCII bin 文档中。
使用音频解析软件查看解码后的语音波形,也可以播放语音。
代码介绍
该章节分为以下几个部分:
源码路径
工程路径:
sdk\board\evb\io_sample\CODEC\AMIC
源码路径:
sdk\src\sample\io_sample\CODEC\AMIC
该工程的工程文件代码结构如下:
└── Project: codec_amic
└── secure_only_app
└── include
├── app_define.h
└── rom_uuid.h
├── cmsis includes CMSIS header files and startup files
├── overlay_mgr.c
├── system_rtl876x.c
└── startup_rtl876x.s
├── lib includes all binary symbol files that user application is built on
├── rtl8752h_sdk.lib
├── gap_utils.lib
├── ROM.lib
└── adc.lib
├── peripheral includes all peripheral drivers and module code used by the application
├── rtl876x_rcc.c
├── rtl876x_pinmux.c
├── rtl876x_nvic.c
├── rtl876x_gdma.c
├── rtl876x_uart.c
├── rtl876x_codec.c
└── rtl876x_i2s.c
├── profile
└── app includes the ble_peripheral user application implementation
└── main.c
初始化
当 EVB 复位启动时,执行 main
函数,执行以下流程:
int main(void)
{
extern uint32_t random_seed_value;
srand(random_seed_value);
__enable_irq();
codec_demo();
while (1)
{
;
}
}
在 codec_demo
中,包含了 PAD/PINMUX 设置,I2S 外设的初始化,UART 外设的初始化,DMA 外设的初始化,CODEC 外设的初始化等流程。
void codec_demo(void)
{
board_codec_init();
board_uart_init();
driver_i2s_init();
driver_uart_init();
driver_gdma_init();
driver_codec_init();
I2S_Cmd(I2S0, I2S_MODE_TX | I2S_MODE_RX, ENABLE);
GDMA_Cmd(GDMA_Channel_AMIC_NUM, ENABLE);
}
board_codec_init
为 AMIC 相关引脚的对 PAD 和 PINMUX 的设置,包含如下流程:
配置 PAD:设置引脚、SW 模式、NOT PowerOn、无内部上拉。其中 H0 引脚输出高,其他引脚输出失能。
void board_codec_init(void) { Pad_Config(H_0, PAD_SW_MODE, PAD_NOT_PWRON, PAD_PULL_NONE, PAD_OUT_ENABLE, PAD_OUT_HIGH); Pad_Config(P2_6, PAD_SW_MODE, PAD_NOT_PWRON, PAD_PULL_NONE, PAD_OUT_DISABLE, PAD_OUT_HIGH); Pad_Config(P2_7, PAD_SW_MODE, PAD_NOT_PWRON, PAD_PULL_NONE, PAD_OUT_DISABLE, PAD_OUT_LOW); }
board_uart_init
为 UART 相关引脚对 PAD 和 PINMUX 的设置,包含如下流程:
配置 PAD:设置引脚、PINMUX 模式、PowerOn、内部上拉。TX 引脚输出高,RX 引脚输出失能。
配置 PINMUX:分配引脚分别为 UART0_TX 和 UART0_RX。
void board_uart_init(void) { Pad_Config(UART_TX_PIN, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_UP, PAD_OUT_ENABLE, PAD_OUT_HIGH); Pad_Config(UART_RX_PIN, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_UP, PAD_OUT_DISABLE, PAD_OUT_LOW); Pinmux_Config(UART_TX_PIN, UART0_TX); Pinmux_Config(UART_RX_PIN, UART0_RX); }
driver_i2s_init
为 I2S 外设的初始化,包含如下流程:
使能 RCC 时钟。
设置 I2S 时钟源为 40MHz,采样率为 16kHz。
设置为主设备模式,单声道输出。
void driver_i2s_init(void) { RCC_PeriphClockCmd(APBPeriph_I2S0, APBPeriph_I2S0_CLOCK, ENABLE); I2S_InitTypeDef I2S_InitStruct; I2S_StructInit(&I2S_InitStruct); I2S_InitStruct.I2S_ClockSource = I2S_CLK_40M; I2S_InitStruct.I2S_DataFormat = I2S_Mode; I2S_InitStruct.I2S_ChannelType = I2S_Channel_Mono; I2S_InitStruct.I2S_DeviceMode = I2S_DeviceMode_Master; I2S_InitStruct.I2S_RxWaterlevel = 0x4; /* BCLK = 40MHz*(I2S_BClockNi/I2S_BClockMi) = Sample Rate * 64BCLK/sample */ I2S_InitStruct.I2S_BClockMi = 0x186A; I2S_InitStruct.I2S_BClockNi = 0xA0; I2S_Init(I2S0, &I2S_InitStruct); }
driver_uart_init
为 UART 外设的初始化,包含如下流程:
使能 RCC 时钟源。
设置 UART 波特率为 3M。
使能 UART TX DMA 功能。
void driver_uart_init(void) { /* Enable clock */ RCC_PeriphClockCmd(APBPeriph_UART0, APBPeriph_UART0_CLOCK, ENABLE); /* UART init */ UART_InitTypeDef UART_InitStruct; UART_StructInit(&UART_InitStruct); /* change to 3M baudrate */ UART_InitStruct.UART_Div = 1; UART_InitStruct.UART_Ovsr = 8; UART_InitStruct.UART_OvsrAdj = 0x492; UART_InitStruct.UART_TxWaterLevel = 12; UART_InitStruct.UART_TxDmaEn = ENABLE; UART_InitStruct.UART_DmaEn = UART_DMA_ENABLE; UART_Init(UART0, &UART_InitStruct); }
driver_gdma_init
为 DMA 外设的初始化,包含如下流程:
使用 DMA 通道 0。
DMA 的传输方向为外设到外设传输。
源端地址为
(&(I2S0->RX_DR))
,目的端地址为(&(UART0->RB_THR))
。设置源端数据宽度为 32 位,目的端数据宽度为 8 位。
设置源端单次 burst 传输数据的个数为 1,目的端单次 burst 传输数据的个数为 4。
使能 DMA 通道 0 总传输完成中断
GDMA_INT_Transfer
。void driver_gdma_init(void) { /* Enable GDMA clock */ RCC_PeriphClockCmd(APBPeriph_GDMA, APBPeriph_GDMA_CLOCK, ENABLE); /* Initialize GDMA peripheral */ GDMA_InitTypeDef GDMA_InitStruct; GDMA_StructInit(&GDMA_InitStruct); GDMA_InitStruct.GDMA_ChannelNum = GDMA_Channel_AMIC_NUM; GDMA_InitStruct.GDMA_DIR = GDMA_DIR_PeripheralToPeripheral; GDMA_InitStruct.GDMA_BufferSize = AUDIO_FRAME_SIZE / 4; GDMA_InitStruct.GDMA_SourceInc = DMA_SourceInc_Fix; GDMA_InitStruct.GDMA_DestinationInc = DMA_DestinationInc_Fix; GDMA_InitStruct.GDMA_SourceDataSize = GDMA_DataSize_Word; GDMA_InitStruct.GDMA_DestinationDataSize = GDMA_DataSize_Byte; GDMA_InitStruct.GDMA_SourceMsize = GDMA_Msize_1; GDMA_InitStruct.GDMA_DestinationMsize = GDMA_Msize_4; GDMA_InitStruct.GDMA_SourceAddr = (uint32_t)(&(I2S0->RX_DR)); GDMA_InitStruct.GDMA_DestinationAddr = (uint32_t)(&(UART0->RB_THR)); GDMA_InitStruct.GDMA_SourceHandshake = GDMA_Handshake_I2S0_RX; GDMA_InitStruct.GDMA_DestHandshake = GDMA_Handshake_UART0_TX; GDMA_Init(GDMA_Channel_AMIC, &GDMA_InitStruct); GDMA_INTConfig(GDMA_Channel_AMIC_NUM, GDMA_INT_Transfer, ENABLE); NVIC_InitTypeDef NVIC_InitStruct; NVIC_InitStruct.NVIC_IRQChannel = GDMA_Channel_AMIC_IRQn; NVIC_InitStruct.NVIC_IRQChannelPriority = 1; NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStruct); }
driver_codec_init
为 CODEC 外设的初始化,包含如下流程:
初始化模拟电路相关配置。
使能 RCC 时钟。
麦克风类型选择 AMIC。
设置 MICBST 模式为差分模式。
设置采样率为 16kHz。
设置数据格式为 I2S 格式。
设置数据宽度为 16 位。
void driver_codec_init(void) { /*switch to pwm mode*/ SystemCall(3, 1); CODEC_AnalogCircuitInit(); RCC_PeriphClockCmd(APBPeriph_CODEC, APBPeriph_CODEC_CLOCK, ENABLE); CODEC_InitTypeDef CODEC_InitStruct; CODEC_StructInit(&CODEC_InitStruct); CODEC_InitStruct.CODEC_Ch0MicType = CODEC_CH0_AMIC; CODEC_InitStruct.CODEC_MicBstMode = MICBST_Mode_Differential; CODEC_InitStruct.CODEC_SampleRate = SAMPLE_RATE_16KHz; CODEC_InitStruct.CODEC_I2SFormat = CODEC_I2S_DataFormat_I2S; CODEC_InitStruct.CODEC_I2SDataWidth = CODEC_I2S_DataWidth_16Bits; CODEC_Init(CODEC, &CODEC_InitStruct); CODEC_Init(CODEC, &CODEC_InitStruct); }
功能实现
初始化完毕后,使能 I2S 发送模式和接收模式;使能 DMA 通道 0 传输。
void codec_demo(void)
{
...
I2S_Cmd(I2S0, I2S_MODE_TX | I2S_MODE_RX, ENABLE);
GDMA_Cmd(GDMA_Channel_AMIC_NUM, ENABLE);
}
AMIC 采集到模拟语音数据,经 CODEC 解码,送到 I2S0 接收 FIFO,利用 DMA 将数据搬运到 UART5;当数据传输完成时,触发
GDMA_INT_Transfer
中断,进入中断处理函数GDMA_Channel_AMIC_Handler
。重新设置源端地址和目的端地址。
重新设置 DMA 传输数据大小。
清除 DMA 通道 0
GDMA_INT_Transfer
中断挂起位,使能 DMA 通道 0。
void GDMA_Channel_AMIC_Handler(void) { GDMA_SetSourceAddress(GDMA_Channel_AMIC, (uint32_t)(&(I2S0->RX_DR))); GDMA_SetDestinationAddress(GDMA_Channel_AMIC, (uint32_t)(&(UART0->RB_THR))); GDMA_SetBufferSize(GDMA_Channel_AMIC, AUDIO_FRAME_SIZE / 4); GDMA_ClearINTPendingBit(GDMA_Channel_AMIC_NUM, GDMA_INT_Transfer); GDMA_Cmd(GDMA_Channel_AMIC_NUM, ENABLE); }