Analog Microphone

本示例实现采集 AMIC 数据,并经 CODEC 编码为 PCM 语音数据。

AMIC 采集模拟语音数据,经 CODEC 编码,送到 I2S 接收 FIFO,利用 GDMA 将数据搬运到 UART

PC 端通过串口助手接收 UART 传输的数据,使用音频解析软件解析数据,并播放录制的语音,本示例中用到的音频解析软件是 Audacity。

环境需求

该示例的环境需求,可参考 环境需求

此外,需要在 PC 终端安装 PuTTY 或 UartAssist 等串口助手工具以及 Audacity 等音频解析工具。

硬件连线

EVB 外接 AMIC 模块,连接 MICBIAS 和 1.8V, GND 和 GND, MIC_P 和 P2_6, MIC_N 和 P2_7;

EVB 外接 FT232 模块接收 UART 数据,连接 P3_2 和 RXD, P3_3 和 TXD 。

编译和下载

该示例的编译和下载流程,可参考 编译和下载

测试验证

准备阶段

  1. 启动 PuTTY 或 UartAssist 等 PC 终端, 用 ASCII 接收数据, 打开 UART COM 端口, 并进行以下 UART 设置:

  • 波特率: 3000000

  • 8 数据位

  • 1 停止位

  • 无校验

  • 无硬件流控

  • 可以设置将输出数据字节转向文件。

  1. 启动音频解析软件, 根据 CODEC 中的设定选择解析格式, 本示例中可以参考如下 Audacity 设定。

  • 编码: 16-bit PCM

  • 字节序:小尾端

  • 声道:1 声道

  • 采样率:1600 Hz

测试阶段

  1. 开始录音到录音完成, 采集到的语音数据, Codec 编码为 PCM 数据后通过 UART 发送到 PC 终端。

  2. 使用音频解析软件查看解码后的语音波形,也可以播放语音。

代码介绍

该章节主要介绍示例中的初始化和相应功能实现的代码和流程说明。

源码路径

工程文件和源码路径如下:

  • 工程路径: sdk\samples\peripheral\codec\amic\proj

  • 源码路径: sdk\samples\peripheral\codec\amic\src

初始化

外设的初始化流程可参考 General Introduction 中的 初始化流程 部分。

初始化流程包括了 CODEC / UART / I2S / GDMA 模块的初始化, 具体流程如下。

  1. 调用 Pad_Config()Pinmux_Config(),配置 CODEC 模块对应引脚的 PAD 和 PINMUX。I2S 引脚复用分别为 BCLK_SPORT0、LRC_RX_SPORT0、SDI_CODEC_SLAVE、SDO_CODEC_SLAVE 功能。

    void board_codec_init(void)
    {
       Pad_Config(AMIC_MSBC_CLK_PIN, PAD_SW_MODE, PAD_NOT_PWRON, PAD_PULL_NONE, PAD_OUT_DISABLE,PAD_OUT_HIGH);
       Pad_Config(AMIC_MSBC_DAT_PIN, PAD_SW_MODE, PAD_NOT_PWRON, PAD_PULL_NONE, PAD_OUT_DISABLE,PAD_OUT_LOW);
    
       Pad_Config(CODEC_BCLK_PIN, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_NONE, PAD_OUT_ENABLE,PAD_OUT_LOW);
       Pad_Config(CODEC_LRCLK_PIN, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_NONE, PAD_OUT_ENABLE,PAD_OUT_LOW);
       Pad_Config(CODEC_TX_PIN, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_NONE, PAD_OUT_ENABLE, PAD_OUT_LOW);
       Pad_Config(CODEC_RX_PIN, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_NONE, PAD_OUT_ENABLE, PAD_OUT_LOW);
    
       Pinmux_Config(CODEC_BCLK_PIN, BCLK_SPORT0);
       Pinmux_Config(CODEC_LRCLK_PIN, LRC_RX_SPORT0);
       Pinmux_Config(CODEC_TX_PIN,    SDI_CODEC_SLAVE);
       Pinmux_Config(CODEC_RX_PIN,    SDO_CODEC_SLAVE);
    }
    
  2. 调用 Pad_Config()Pinmux_Config(),配置 UART 模块对应引脚的 PAD 和 PINMUX。

    void board_uart_init (void)
    {
      Pad_Config(UART_TX_PIN, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_UP, PAD_OUT_DISABLE, PAD_OUT_HIGH);
      Pad_Config(UART_RX_PIN, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_UP, PAD_OUT_DISABLE, PAD_OUT_HIGH);
    
      Pinmux_Config(UART_TX_PIN, UART5_TX);
      Pinmux_Config(UART_RX_PIN, UART5_RX);
    }
    
  3. 执行 I2S_StructInit()I2S_Init(), 初始化 I2S 外设。I2S0 的初始化参数配置如下:

I2S 初始化参数

I2S Hardware Parameters

Setting in the I2S_InitStruct

I2S master RX

Sample Rate (Mi)

I2S_InitTypeDef::I2S_RxBClockMi

0x271

Sample Rate (Ni)

I2S_InitTypeDef::I2S_RxBClockNi

0x10

Device Mode

I2S_InitTypeDef::I2S_DeviceMode

I2S_DeviceMode_Master

Channel Type

I2S_InitTypeDef::I2S_RxChannelType

I2S_Channel_Mono

Data Format

I2S_InitTypeDef::I2S_RxDataFormat

I2S_Mode

Data Width

I2S_InitTypeDef::I2S_RxDataWidth

I2S_Width_16Bits

  1. 执行 UART_StructInit()UART_Init(), 初始化 UART 外设。UART 的初始化参数配置如下:

UART 初始化参数

UART Hardware Parameters

Setting in the UART_InitStruct

UART

UART Div

UART_InitTypeDef::UART_Div

1

UART Ovsr

UART_InitTypeDef::UART_Ovsr

8

UART OvsrAdj

UART_InitTypeDef::UART_OvsrAdj

0x492

UART Tx Dma En

UART_InitTypeDef::UART_TxDmaEn

ENABLE

UART Dma En

UART_InitTypeDef::UART_DmaEn

UART_DMA_ENABLE

  1. 执行 GDMA_StructInit()GDMA_Init(),初始化 GDMA 外设。GDMA 的初始化参数配置如下:

GDMA 初始化参数

GDMA Hardware Parameters

Setting in the GDMA_InitStruct

GDMA Channel

Channel Num

GDMA_InitTypeDef::GDMA_ChannelNum

0

Transfer Direction

GDMA_InitTypeDef::GDMA_DIR

GDMA_DIR_PeripheralToPeripheral

Buffer Size

GDMA_InitTypeDef::GDMA_BufferSize

1000

Source Address Increment or Decrement

GDMA_InitTypeDef::GDMA_SourceInc

DMA_SourceInc_Fix

Destination Address Increment or Decrement

GDMA_InitTypeDef::GDMA_DestinationInc

DMA_DestinationInc_Fix

Source Data Size

GDMA_InitTypeDef::GDMA_SourceDataSize

GDMA_DataSize_Word

Destination Data Size

GDMA_InitTypeDef::GDMA_DestinationDataSize

GDMA_DataSize_Byte

Source Burst Transaction Length

GDMA_InitTypeDef::GDMA_SourceMsize

GDMA_Msize_4

Destination Burst Transaction Length

GDMA_InitTypeDef::GDMA_DestinationMsize

GDMA_Msize_16

Source Address

GDMA_InitTypeDef::GDMA_SourceAddr

&(I2S1->I2S_RX_FIFO_RD_ADDR)

Destination Address

GDMA_InitTypeDef::GDMA_DestinationAddr

&(UART5->UART_RBR_THR)

Source Handshake

GDMA_InitTypeDef::GDMA_SourceHandshake

GDMA_Handshake_I2S1_TDM0_RX

Destination Handshake

GDMA_InitTypeDef::GDMA_DestHandshake

GDMA_Handshake_UART5_TX

  1. 配置 GDMA 总传输完成中断 GDMA_INT_Transfer 和 NVIC,NVIC 相关配置可参考 中断配置

  2. 对 CODEC 外设的初始化。

    1. 调用 CODEC_AnalogCircuitInit() 初始化模拟电路。

    2. 调用 RCC_PeriphClockCmd() ,开启 CODEC 时钟。

    3. 执行 CODEC_StructInit()CODEC_Init(), 初始化 CODEC 外设。CODEC 的初始化参数配置如下:

CODEC 初始化参数

CODEC Hardware Parameters

Setting in the CODEC_InitStruct

CODEC

Mic Type

CODEC_InitTypeDef::CODEC_Ch0MicType

CODEC_CH_AMIC

MICBST Mode

CODEC_InitTypeDef::CODEC_MicBstMode

MICBST_Mode_Differential

SampleRate

CODEC_InitTypeDef::CODEC_SampleRate0

SAMPLE_RATE_16KHz

I2S Data Format

CODEC_InitTypeDef::CODEC_I2SFormat

CODEC_I2S_DataFormat_I2S

I2S Channel Len

CODEC_InitTypeDef::CODEC_I2SChannelLen

I2S_CHANNELLEN_32

I2S Data Width

CODEC_InitTypeDef::CODEC_I2SRxDataWidth

CODEC_I2S_Rx_DataWidth_16Bits

I2S Channel Sequence

CODEC_InitTypeDef::CODEC_I2SChSequence

CODEC_I2S_CH_L_R

  1. 调用 I2S_Cmd(), 使能 I2S 接收模式。调用 GDMA_Cmd(), 使能 GDMA 传输。

功能实现

AMIC 收集到语音数据后,经过 CODEC 模块的 AD 转换,将语音数据放入 I2S RX FIFO 中。I2S RX FIFO 内的数据再通过 GDMA 传输到 UART TX FIFO 中,在串口助手内,将 UART 发送的数据保存到文件内,通过音频解析软件解析文件数据。 数据在各个模块的传输顺序如下图所示。

这里应该是 AMIC 波形图片

数据传输模块(AMIC)

  1. 当 GDMA 传输数据量达到设定的 BlockSize 时,会触发 GDMA_INT_Transfer 中断。由于音频数据在通过 CODEC 进行 AD 转换后,其数据量较大,单次 GDMA 传输无法满足需求。在中断处理函数内重新设置源端地址、目的端地址和 BlockSize,并重新使能 GDMA 传输,以确保能够连续传输大量数据。

    GDMA_SetSourceAddress(GDMA_Channel_AMIC, (uint32_t)(&(I2S0->I2S_RX_FIFO_RD_ADDR)));
    GDMA_SetDestinationAddress(GDMA_Channel_AMIC, (uint32_t)(&(UART5->UART_RBR_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);