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:
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:
Open sample project file.
To build the target, follow the steps listed on the Generating App Image in Quick Start.
After a successful compilation, the app bin
app_MP_xxx.bin
will be generated in the directorymdk\bin
orgcc\bin
.To download app bin into EVB board, follow the steps listed on the MP Tool Download in Quick Start.
Press reset button on EVB board and it will start running.
Experimental Verification
Preparation Phase
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
Start an audio parsing software.
Testing Phase
From the beginning to the end of the recording, the captured audio data is coded and transmitted to the PC terminal via UART.
Copy the decoded data from the PC terminal to a newly created HEX bin file.
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:
Peripheral initialization will be introduced in chapter Initialization.
Functional implementation after initialization will be introduced in chapter Functional Implementation.
Source Code Directory
Project Directory:
sdk\samples\peripheral\codec\amic\proj
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:
Configure PAD:
For AMIC: SW mode, NOT PowerOn, internal Pull-None.
For I2S: PINMUX mode, PowerOn, internal Pull-None.
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:
Configure PAD: Set up pin, PINMUX mode, PowerOn, internal Pull-Up.
Configure PINMUX: Assign pins for UART5_TX, UART5_RX functions.
driver_i2s_init
contains the initialization of I2S peripherals:
Enable PCC clock.
Set the I2S clock source to 40M and the bit clock to 16K.
Set the master device mode, mono output, and data format to I2S mode.
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.
Enable PCC clock.
Set the baud rate to 3M.
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.
Use GDMA channel 0.
The GDMA transfer direction is peripheral to peripheral transfer.
Source address is
(&(I2S0->I2S_RX_FIFO_RD_ADDR))
and destination address is(&(UART5->UART_RBR_THR))
.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:
Initialize the configuration of the CODEC’s analog circuit.
Enable PCC clock.
Select AMIC for the microphone type.
Set the MICBST mode to Differential.
Set the sample rate to 16kHz.
Set the data format to I2S format.
Set the channel width to 32 bits.
Set the RX data width to 16 bits.
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
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);
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 handlerGDMA_Channel_AMIC_Handler
.Reset the source and destination addresses.
Reset the GDMA transfer data size.
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);