cancel
Showing results for 
Search instead for 
Did you mean: 

Data corruption with PDM Microphone

kcire L.
Associate III

Hello,

I am using a MEMS PDM microphone and reading it in using I2S. The following parameters are set in my I2S and PDM configurations.

hi2s3.Instance = SPI3;
  hi2s3.Init.Mode = I2S_MODE_MASTER_RX;
  hi2s3.Init.Standard = I2S_STANDARD_MSB;
  hi2s3.Init.DataFormat = I2S_DATAFORMAT_24B;
  hi2s3.Init.MCLKOutput = I2S_MCLKOUTPUT_DISABLE;
  hi2s3.Init.AudioFreq = I2S_AUDIOFREQ_48K;
  hi2s3.Init.CPOL = I2S_CPOL_LOW;
  hi2s3.Init.ClockSource = I2S_CLOCK_PLL;
  hi2s3.Init.FullDuplexMode = I2S_FULLDUPLEXMODE_ENABLE;

The PDM2PCM decimation factor is 64. I am sending the data out of the uart at 2Mbaud, but am getting gaps of corrupt values in my data. Is this because I am not sending it fast enough? If so, how could I buffer this better in order to fix this issue?

Thanks for any help, my code is here as well and an image of my plotted audio.

 HAL_I2S_Receive_DMA(&hi2s3, &pdmRxBuf[0],64);
   HAL_UART_Transmit_DMA(&huart2, (uint8_t *)txBuf, 256);
  /* USER CODE END 2 */
 
 
 
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
 
	  if (rxstate==1) {
	     	PDM_Filter(&pdmRxBuf[0],&MidBuffer[0], &PDM1_filter_handler);
	     	for (int i=0; i<16;i++)
	     	{
	     		//MidBuffer[i] = j++;
	     		FifoWrite(MidBuffer[i]);
	     		//j %= 65535;
	     	}
	     	if (fifo_w_ptr-fifo_r_ptr > 128) fifo_read_enabled=1;
	     	rxstate=0;
 
	     }
 
	     if (rxstate==2) {
	     	PDM_Filter(&pdmRxBuf[64],&MidBuffer[0], &PDM1_filter_handler);
	     	for (int i=0; i<16;i++)
	     	{
	     		//MidBuffer[i] = j++;
	     		FifoWrite(MidBuffer[i]);
	     		//j %= 65535;
	     	}
	     	rxstate=0;
 
	     }
 
	     if (txstate==1) {
	     	if (fifo_read_enabled==1) {
	 			for (int i=0; i<64;i=i+1) {
	 				uint16_t data = FifoRead();
	 				txBuf[i] = data;
	 				//txBuf[i+2] = data;
	 			}
	     	}
	     	txstate=0;
	     }
 
	     if (txstate==2) {
	     	if (fifo_read_enabled==1) {
	 			for (int i=64; i<128;i=i+1) {
	 				uint16_t data = FifoRead();
	 				txBuf[i] = data;
	 			//	txBuf[i+2] = data;
	 			}
 
	 		}
	     	txstate=0;
	     }
void HAL_UART_TxHalfCpltCallback(UART_HandleTypeDef *huart)
{
	 txstate = 1;
}
 
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
	 txstate = 2;
}
 
void HAL_I2S_RxHalfCpltCallback (I2S_HandleTypeDef *hi2s) {
	rxstate = 1;
}
 
void HAL_I2S_RxCpltCallback (I2S_HandleTypeDef *hi2s) {
	rxstate = 2;
}

1 ACCEPTED SOLUTION

Accepted Solutions

Hi @kcire L.​ .

There is a parameter in the library called "nSamples" that defines how many samples (in 16-bit format) every call to the conversion function produces in output.

So, on the basis of nSamples parameter and on the decimation factor you have to feed the input with the correct dimensions.

Regarding your example:

nSamples = 16

decimation = 64

--> input must be 16*64 (bits) = 64 halfwords of 16 bits

Hope this will clarify a bit more your issue.

If so, please select this answer as "best".

-Eleon

View solution in original post

11 REPLIES 11
Eleon BORLINI
ST Employee

Hi @kcire L.​ ,

>> The PDM2PCM decimation factor is 64. I am sending the data out of the uart at 2Mbaud, but am getting gaps of corrupt values in my data. Is this because I am not sending it fast enough? If so, how could I buffer this better in order to fix this issue?

If the word rate is 48kHz and the bit depth is 24 bits, you should be able to send a 1.152.000 serial data on a 2MBaud rate.

However, since the audio stream can be a little tricky, to be sure this is not the issue you could check if with a lower word rate or a lower you still get wrong data.

Btw, which is the PDM clock frequency you are feeding the mic? 64x48kHz = 3.072MHz, right?

And can you check the membrane of the MEMS microphone inside the acoustic inlet with a microscope, to be sure it is not damaged?

-Eleon

kcire L.
Associate III

I tried it with 16Khz with 64 decimation factor which would be 1.024Mhz clock and I was still getting this error. Is there a bug in my code? I tried two MEMS microphones and had the same result....

Thanks for the responses

kcire L.
Associate III

I did try this with hard coded data of a ramp from 0 to 65535 and this is the result I get... same issue so I don't think it's the microphone... my code must have an error but I can't figure out what it is.

kcire L.
Associate III

Can the USB UART link on the STM32NUCLEO-F401RE support data rates at 2MBaud?

Eleon BORLINI
ST Employee

Hi @kcire L.​ ,

the STM32F401xE microcontroller supports the USB 2.0 full-speed for the interface and up to 3 USARTs (2 x 10.5 Mbit/s, 1 x 5.25 Mbit/s) for the VCOM, so I believe it can.

But let me better check internally with our experts...

-Eleon

Eleon BORLINI
ST Employee

Hi @kcire L.​ ,

after internal check with our experts, even if there limit of the ST-LINK baud rate could be higher, it's nor recommended to use it to send all the data through this interface, since this peripheral is designed only for temporary debug tests.

Probably it would be better to switch to the USB interface, which is the "correct" one. This is probably much more complicated, but in the X-CUBE-MEMSMIC1 you have the out-of-the-box example.

-Eleon

Thanks for the information.

I got my code working, but I am still not understanding some things with the PDM 2 PCM conversion.

uint16_t txBuf[128];	
uint16_t pdmRxBuf[128];
uint16_t MidBuffer[16];
 
 HAL_I2S_Receive_DMA(&hi2s3, &pdmRxBuf[0],64);		
// decimation factor = 64 ...... number of output samples = 16?
 
HAL_UART_Transmit_DMA(&huart1, (uint8_t*)txBuf, 256);
 
while(1)
{
PDM_Filter(&pdmRxBuf[0],&MidBuffer[0], &PDM1_filter_handler);
for (int i=0; i<16;i++)
			{
				FifoWrite(MidBuffer[i]);
			}
if (fifo_w_ptr-fifo_r_ptr > 128) fifo_read_enabled=1;
}
 
 

how does a pdmRxBuf of 64 (uint16_t values) read from the I2S receiver result in 16 (uint16_t values) of PCM data which are stored into the MidBuffer?

I want to increase those buffer sizes but I don't know how they correspond to each other. Can I double the pdmRxBuf to 128 and then assume this will convert to 32 (uint16_t values) of PCM data?

Again, thanks for all of the help

Hi @kcire L.​ .

There is a parameter in the library called "nSamples" that defines how many samples (in 16-bit format) every call to the conversion function produces in output.

So, on the basis of nSamples parameter and on the decimation factor you have to feed the input with the correct dimensions.

Regarding your example:

nSamples = 16

decimation = 64

--> input must be 16*64 (bits) = 64 halfwords of 16 bits

Hope this will clarify a bit more your issue.

If so, please select this answer as "best".

-Eleon

kcire L.
Associate III

So lets say I want to change the number of output nSamples to 32 for each time the function is called.

The decimation factor stays the same at 64.

what does my pdmRxBuf stize have to be?