Analog Microphone

This sample implements the acquisition of AMIC (Analog Microphone) data and encodes it into PCM voice data by CODEC.

AMIC collects analog voice data, encodes it by CODEC, sends it to I2S receiving FIFO, and uses DMA to carry the data to UART.

The PC receives the data transferred from the UART through the serial assistant, parses the data using audio parsing software, and plays the recorded voice.

Requirements

The sample supports the following development kits:

Development Kits

Hardware Platforms

Board Name

RTL87x2G HDK

RTL87x2G EVB

For more requirements, please refer to Quick Start.

Wiring

EVB external AMIC module, connect MICBIAS and 1.8V, GND and GND, P2_6 and MIC_P, P2_7 and MIC_N; EVB external FT232 module, connect P3_2 and RX, P3_3 and TX.

Building and Downloading

This sample can be found in the SDK folder:

Project file: samples\peripheral\codec\amic\proj\rtl87x2g\mdk

Project file: samples\peripheral\codec\amic\proj\rtl87x2g\gcc

To build and run the sample, follow the steps listed below:

  1. Open sample project file.

  2. To build the target, follow the steps listed on the Generating App Image in Quick Start.

  3. After a successful compilation, the app bin app_MP_xxx.bin will be generated in the directory mdk\bin or gcc\bin.

  4. To download app bin into EVB board, follow the steps listed on the MP Tool Download in Quick Start.

  5. Press reset button on EVB board and it will start running.

Experimental Verification

Preparation Phase

  1. Start a PC terminal like PuTTY or UartAssist and connect to the used COM port with the following UART settings:

  • Baud rate: 3000000

  • 8 data bits

  • 1 stop bit

  • No parity

  • No hardware flow control

  1. Start an audio parsing software.

Testing Phase

  1. From the beginning to the end of the recording, the captured audio data is coded and transmitted to the PC terminal via UART.

  2. Copy the decoded data from the PC terminal to a newly created HEX bin file.

  3. Use audio parsing software to view the waveform of the decoded voice, or play the voice.

Code Overview

This chapter will be introduced according to the following several parts:

  1. Source Code Directory.

  2. Peripheral initialization will be introduced in chapter Initialization.

  3. Functional implementation after initialization will be introduced in chapter Functional Implementation.

Source Code Directory

  1. Project Directory: sdk\samples\peripheral\codec\amic\proj

  2. Source Code Directory: sdk\samples\peripheral\codec\amic\src

Source files are currently categorized into several groups as below.

└── Project: amic
    └── secure_only_app
        └── Device                   includes startup code
            ├── startup_rtl.c
            └── system_rtl.c
        ├── CMSIS                    includes CMSIS header files
        ├── CMSE Library             Non-secure callable lib
        ├── Lib                      includes all binary symbol files that user application is built on
            └── rtl87x2g_io.lib
        ├── Peripheral               includes all peripheral drivers and module code used by the application
            ├── rtl_rcc.c
            ├── rtl_pinmux.c
            ├── rtl_uart.c
            ├── rtl_gdma.c
            ├── rtl_nvic.c
            ├── rtl_codec.c
            └── rtl_i2s.c
        └── APP                      includes the ble_peripheral user application implementation
            ├── main_ns.c
            └── io_codec.c

Initialization

The initialization flow includes the initialization of the CODEC, UART, I2S, and DMA modules as follows.


board_codec_init contains the PAD and PINMUX settings for I2S and AMIC:

  1. Configure PAD:

    1. For AMIC: SW mode, NOT PowerOn, internal Pull-None.

    2. For I2S: PINMUX mode, PowerOn, internal Pull-None.

  2. Configure PINMUX: Multiplex the pin to BCLK_SPORT0, LRC_RX_SPORT0, SDI_CODEC_SLAVE and SDO_CODEC_SLAVE functions.

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);

board_uart_init contains the PAD and PINMUX settings for UART:

  1. Configure PAD: Set up pin, PINMUX mode, PowerOn, internal Pull-Up.

  2. Configure PINMUX: Assign pins for UART5_TX, UART5_RX functions.


driver_i2s_init contains the initialization of I2S peripherals:

  1. Enable PCC clock.

  2. Set the I2S clock source to 40M and the bit clock to 16K.

  3. Set the master device mode, mono output, and data format to I2S mode.

  4. Set the data width and channel width.

RCC_PeriphClockCmd(APBPeriph_I2S0, APBPeriph_I2S0_CLOCK, ENABLE);

I2S_InitStruct.I2S_ClockSource        = I2S_CLK_40M;
I2S_InitStruct.I2S_RxBClockMi         = 0x271;/* <!BCLK = 16K */
I2S_InitStruct.I2S_RxBClockNi         = 0x10;
I2S_InitStruct.I2S_DeviceMode         = I2S_DeviceMode_Master;
I2S_InitStruct.I2S_RxChannelType      = I2S_Channel_Mono;
I2S_InitStruct.I2S_RxDataFormat       = I2S_Mode;
I2S_InitStruct.I2S_RxChannelWidth     = I2S_Width_32Bits;
I2S_InitStruct.I2S_RxDataWidth        = I2S_Width_16Bits;

driver_uart_init contains the initialization of UART peripherals.

  1. Enable PCC clock.

  2. Set the baud rate to 3M.

  3. Enable the UART TX DMA function.

RCC_PeriphClockCmd(APBPeriph_UART5, APBPeriph_UART5_CLOCK, ENABLE);

UART_InitStruct.UART_Div             = 1;
UART_InitStruct.UART_Ovsr            = 8;
UART_InitStruct.UART_OvsrAdj         = 0x492;

UART_InitStruct.UART_TxDmaEn         = ENABLE;
UART_InitStruct.UART_DmaEn           = UART_DMA_ENABLE;

driver_gdma_init contains the initialization of GDMA peripherals.

  1. Use GDMA channel 0.

  2. The GDMA transfer direction is peripheral to peripheral transfer.

  3. Source address is (&(I2S0->I2S_RX_FIFO_RD_ADDR)) and destination address is (&(UART5->UART_RBR_THR)) .

  4. Enable GDMA channel 0 total transfer completion interrupt GDMA_INT_Transfer.

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_SourceAddr          = (uint32_t)(&(I2S0->I2S_RX_FIFO_RD_ADDR));
GDMA_InitStruct.GDMA_DestinationAddr     = (uint32_t)(&(UART5->UART_RBR_THR));
GDMA_InitStruct.GDMA_SourceHandshake     = GDMA_Handshake_I2S0_TDM0_RX;
GDMA_InitStruct.GDMA_DestHandshake       = GDMA_Handshake_UART5_TX;
GDMA_InitStruct.GDMA_ChannelPriority = 2;

GDMA_Init(GDMA_Channel_AMIC, &GDMA_InitStruct);
GDMA_INTConfig(GDMA_Channel_AMIC_NUM, GDMA_INT_Transfer, ENABLE);

driver_codec_init contains the initialization of CODEC peripherals:

  1. Initialize the configuration of the CODEC’s analog circuit.

  2. Enable PCC clock.

  3. Select AMIC for the microphone type.

  4. Set the MICBST mode to Differential.

  5. Set the sample rate to 16kHz.

  6. Set the data format to I2S format.

  7. Set the channel width to 32 bits.

  8. Set the RX data width to 16 bits.

  9. Set the I2S channel order to left and right.

CODEC_AnalogCircuitInit();
RCC_PeriphClockCmd(APBPeriph_CODEC, APBPeriph_CODEC_CLOCK, ENABLE);
...
CODEC_InitStruct.CODEC_Ch0MicType       = CODEC_CH_AMIC;
CODEC_InitStruct.CODEC_MicBstMode       = MICBST_Mode_Differential;
CODEC_InitStruct.CODEC_SampleRate0      = SAMPLE_RATE_16KHz;
CODEC_InitStruct.CODEC_I2SFormat        = CODEC_I2S_DataFormat_I2S;
CODEC_InitStruct.CODEC_I2SChannelLen    = I2S_CHANNELLEN_32;
CODEC_InitStruct.CODEC_I2SRxDataWidth     = CODEC_I2S_Rx_DataWidth_16Bits;
CODEC_InitStruct.CODEC_I2SChSequence    = CODEC_I2S_CH_L_R;

Functional Implementation

  1. Enable I2S transmit mode and receive mode; enable GDMA channel 0.

I2S_Cmd(I2S0, I2S_MODE_TX | I2S_MODE_RX, ENABLE);
GDMA_Cmd(GDMA_Channel_AMIC_NUM, ENABLE);
  1. AMIC collects analog voice data, decodes it by CODEC, sends it to I2S0 receiving FIFO, and carries the data to UART5 by using GDMA; when the data transmission is completed, it triggers the GDMA_INT_Transfer interrupt, and enters the interrupt handler GDMA_Channel_AMIC_Handler.

    1. Reset the source and destination addresses.

    2. Reset the GDMA transfer data size.

    3. Clear the GDMA channel 0 GDMA_INT_Transfer interrupt pending bit and enable GDMA channel 0.

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);