cancel
Showing results for 
Search instead for 
Did you mean: 

Issues with PDM mono microphone with I2S

frnt
Senior

Dear all,

I have some trouble setting up the correct acquisition of the MEMS microphone over I2S.

Consider the STM32F401RE Nucleo board connected to the IMP34DT05 PDM microphone with L/R to GND.

Through Mx, the I2S peripheral is configured as follows:

0693W00000GYxgwQAD.pngThen, the DMA is configured as a circular buffer, half-word:

0693W00000GYxe3QAD.pngFinally, I have configured the PDM2PCM library as follows:

0693W00000GYxi9QAD.pngStarting from that configuration I'm having trouble understanding why the PDM2PCM is not working as expected.

Here is the skeleton of the code:

uint16_t pdmRxBuf[128];
uint16_t MidBuffer[16];
uint16_t pcm_data[4096];
uint8_t txstate = 0;
uint8_t rxstate = 0;
 
int main(void)
{
  /* USER CODE BEGIN 1 */
 
  /* USER CODE END 1 */
  
 
  /* MCU Configuration--------------------------------------------------------*/
 
  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();
 
  /* USER CODE BEGIN Init */
 
  /* USER CODE END Init */
 
  /* Configure the system clock */
  SystemClock_Config();
 
  /* USER CODE BEGIN SysInit */
 
  /* USER CODE END SysInit */
 
  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_I2S2_Init();
  MX_I2S3_Init();
  MX_CRC_Init();
  MX_PDM2PCM_Init();
  /* USER CODE BEGIN 2 */
 
 pcm_index = 0;
  /* USER CODE END 2 */
  
  HAL_I2S_Receive_DMA(&hi2s2, &pdmRxBuf[0],128);
 
  /* Infinite loop */
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    if (rxstate==1) {
    	PDM_Filter(&pdmRxBuf[0],&MidBuffer[0], &PDM1_filter_handler);
    	for(uint8_t i = 0; i < 16 ; i++){
		pcm_data[pcm_index] = mid_buffer[i];
		pcm_index++;
	}
    	rxstate=0;
 
    }
 
    if (rxstate==2) {
    	PDM_Filter(&pdmRxBuf[64],&MidBuffer[0], &PDM1_filter_handler);
    	for(uint8_t i = 0; i < 16 ; i++){
	   pcm_data[pcm_index] = mid_buffer[i];
           pcm_index++;
        }
        rxstate=0;
    }
 
   if(pcm_index==4096){
	//Stop the DMA
	HAL_I2S_DMAPause(&hi2s2);
        
       // Send to UART or Store Data 
       pcm_index = 0;
       
       
 
    }
  /* USER CODE END 3 */
}
 
void HAL_I2S_RxHalfCpltCallback(I2S_HandleTypeDef *hi2s){
	rx_state = 1;
}
 
void HAL_I2S_RxCpltCallback(I2S_HandleTypeDef *hi2s){
	rx_state = 2;
}

The program is very stupid, tries to get 4096 samples into the pcm_data to be saved or sent through the UART.

Having configured the DMA as a circular buffer, I would expect that at every interrupt Half of the buffer is filled with new data, while the other half is used to run the PDM_Filter function and complete the PCM conversion and copy the data out to the pcm_data.

However, before starting the execution I emit from the PC a sine wave at a specific frequency that should be recorded by the 4096 samples acquired by the microphone.

Unfortunately, when I reproduce the 4096 samples, there is only noise.

Did I misunderstand some configurations?

Thanks for your help

8 REPLIES 8
frnt
Senior

Update!

I forgot to mention that, at the beginning of the acquisition after the PDM_Filter function call, the mid_buffer contains values very close to 32767. After few calls, the number starts to varying but the audio reproduced with audacity is somehow shifted in frequency.

What could be the problem?

Eleon BORLINI
ST Employee

Eleon BORLINI

Hi @frnt (Community Member)​ ,

Unfortunately I'm not an expert of the interface of audio sensors with microcontrollers, sorry.

I might suggest you to have a look to existing examples, instead of trying to configure the peripherals for the acquisition from scratch.

For example, you can have a look to the Microphones_Streaming example with the STM32F401RE-Nucleo that you can find in the X-CUBE-MEMSMIC1 function pack, folder: \Projects\STM32F401RE-Nucleo\Demonstration\CCA02M2\Microphones_Streaming.

If it is not suitable for you, try to post this question (a new one) in the STM32 group, topic STM32F401RE Nucleo, so that experts can easily reach you.

-Eleon

frnt

Dear @Eleon BORLINI​ ,

thanks for your reply. I have partially solved the issue.

Now I have 16kHz selected audio frequency, 16-bit data on 16 data frame, 64 decimation. Therefore the I2S clock should be 1.024MHz.

I record the audio of a pure tone (e.g. 500Hz) and then I convert it to a 16bit, 16kHz .wav file. The problem is that the recorded audio, played has double the frequency of the pure tone (1000Hz in this case). How could it be possible?

Changing the data and dataframe format to 24-bit in 32 data frame solves this issue.

But I don't undestand why!

Why with 16-bit data the pure tone appears with a double frequency?

Do you have any suggestions?

Eleon BORLINI
ST Employee

Hi @frnt (Community Member)​ ,

the I2S clock usually takes into account double of the frequency because it could deal with a stereo configuration.

In this configuration the two (Left and Right) mics share the same clock and data line, so that the clock samples the data on the rising edge of the digital pattern for the Right mic and on the falling edge for the Left mic.

Not sure however why you solved the issue by changing the data and dataframe format to 24-bit in 32 data frame.

Can you apply this configuration for your application?

-Eleon

** Note: I've reported here the conversation from this other thread, that we'll be closed **

frnt
Senior

Dear @Eleon BORLINI​,

The IS2 is configured for a mono microphone (L/R connected to ground).

I'm using the internal HSI (16MHz) to derive the clock (M=10), the PLLI2S is configured with N=192, R = 5 that resulting in 61.44MHz as I2S clock. This is fine with the documentation (Tab.10 AN5027) for mono configuration.

Changing the data size: 24bits on 32bit frame requires that the pdm_buffer[128], but the call to:

HAL_I2S_Receive_DMA(&hi2s2, &pdm_buffer[0], 128/2);

Requires that only half of the size is passed to the DMA because internally one left shift is done for data with 24 and 32bits.

This configuration perfectly works.

However, simply changing the data size: 16bits on 16bit (or 16bits on 32 bits) frame requires to call:

HAL_I2S_Receive_DMA(&hi2s2, &pdm_buffer[0], 128);

Passing the full size of the buffer.

However, this solution results in a distorted audio signal.

Looking with the debugger, the I2SDIV and ODD are the following:

  • 16bit data on 16bit frame (I2SDIV = 0x3c and ODD = 0x00) -> Fs = 16kHz
  • 24bit data on 32bit frame (I2SDIV = 0x1e and ODD = 0x00) -> Fs = 16kHz

0693W00000GZOb0QAH.pngThe resulting Fs for both configuration are correct.

Could you help me understand? Have the pdm_buffer the wrong size?

Thanks!

frnt
Senior

Dear @Eleon BORLINI​ ,

I have provided all the configurations for I2S. Do you have any idea why if I use 16bit data on 16bit frame the .wav should be saved setting 8kHz as sampling frequency (the ear the correct sound) instead of 16kHz?

With 24bit da on 32bit frame, I simply get all the data and on the .wav setting 16kHz as sampling frequency and can ear the correct sound.

Any idea?

Thanks.

Eleon BORLINI
ST Employee

Hi @frnt​ ,

I got this feedback from our experts: they are referring to the X-CUBE-MEMSMIC1 library, and they are asking you whether you are using this function pack.

If so, the I2S peripheral configuration in the MEMSMIC1 with the PDMFilter function works (only) if it is set in that way (i.e. 24 bit on 32).

This because, during the data conversion, registers of specific 24-bits peripherals are used, together with local variable at 32 bits.

For this reason, if you change just a configuration parameter in the I2S configuration, then the procedure works no more.

See for example this presentation --> STM32H7-Peripheral-Digital Filter for SD Modulators interface (DFSDM)0693W00000Ho4JeQAJ.pngIn any case, during the conversion the "useful" data have an extension of 24 or 32 bits, never at 16 bits.

-Eleon

frnt
Senior

Dear @Eleon BORLINI​ ,

thanks for your reply. I’m not using the X-CUBE-MEMSMIC1 library, but simply the I2S pheriferal (configured with cube mx as written above) and the PDM2PCM library.

I was very precise in describing my configuration to help as much as possibile understanding why I’m getting this behavior.

I report from above (Fs=16kHz, recorded signal 500Hz:(

Changing the data size: 24bits on 32bit frame requires that the pdm_buffer[128], but the call to:

HAL_I2S_Receive_DMA(&hi2s2, &pdm_buffer[0], 128/2);

Requires that only half of the size is passed to the DMA because internally one left shift is done for data with 24 and 32bits.

I convert PCM to .wav setting Fs to 16kHz and It perfectly works. The audio is correct, checked with FFT.

However, simply changing the data size: 16bits on 16bit (or 16bits on 32 bits) frame requires to call:

HAL_I2S_Receive_DMA(&hi2s2, &pdm_buffer[0], 128);

Passing the full size of the buffer.

I convert PCM to .wav setting Fs to 16kHz, but this time it results in a distorted audio signal. Looking at the FFT the peak is a 1000Hz instead of 500Hz.

Is there an explanation for this? Why 16bit on 16bit frame is not working?

I really want to understand the reason.

Thanks

Hi @frnt​ ,

If you don't want to use the X-CUBE-MEMSMIC1 library, maybe it's better to ask for help to STM32 experts.

Hi @Imen DAHMEN​, @Amel NASRI​ ,

could you suggest an expert for this topic (I2S peripheral configuration details)?

Thank you,

-Eleon