AnsweredAssumed Answered

How does PDM2PCM library works?

Question asked by Riccardo Laiolo on Feb 4, 2018

Hi STCommunity, I'm using a Nucleo F446RE and I have to convert a PDM bitstream from a pair of mems microphones (CCA02M1 eval board) into PCM. Does anyone know how the latest PDM2PCM library (rev. 3.0.0) works? The application note is updated to the rev. 1.0.0 (2011) and the latest revision is not backward compatible.

 

This is my filter setup code

hfilter.bit_order=PDM_FILTER_BIT_ORDER_MSB;                    // Source PDM stream format     (?)
hfilter.endianness=PDM_FILTER_ENDIANNESS_LE;               // F4 endianness (?)
hfilter.high_pass_tap=;                                             // I have no clue how to set this
hfilter.in_ptr_channels=2;
hfilter.out_ptr_channels=2;
PDM_Filter_Init(&hfilter);

filtconf.decimation_factor=PDM_FILTER_DEC_FACTOR_128;     // Target sample rate is 16kHz, PDM sample rate is 16k*128=2.048MHz
filtconf.mic_gain=0;
filtconf.output_samples_number=PCMbufflen/2;               
PDM_Filter_setConfig(&hfilter, &filtconf);

I have some concerns about ... well, about everything.

 

I'm not sure about the endianness and the bit order parameters. I suppose they should be correct, but meh... 

I have no clue at all how to set the high_pass_tap parameter.

 

Here is the main code. Data acquisition from I2S is in DMA circular mode on a buffer 2*I2Sbufflen long (the half transfer function is identical)

void HAL_I2S_RxCpltCallback(I2S_HandleTypeDef *hi2s)
{

     uint32_t index = 0;

     volatile uint16_t * DataTempI2S = &(I2S_InternalBuffer[I2Sbufflen]);
     
     /* From bit interleaved buffer (DataTempI2S) to byte interleaved buffer (PDMbuff) */
     /* (Copied from a working example) */
     uint8_t a,b=0;
     for(index=0; index<I2Sbufflen; index++)
     {
          a = ((uint8_t *)(DataTempI2S))[(index*2)];
          b = ((uint8_t *)(DataTempI2S))[(index*2)+1];
          ((uint8_t *)(PDMbuff))[(index*2)] = Channel_Demux[a & CHANNEL_DEMUX_MASK] | Channel_Demux[b & CHANNEL_DEMUX_MASK] << 4;;
          ((uint8_t *)(PDMbuff))[(index*2)+1] = Channel_Demux[(a>>1) & CHANNEL_DEMUX_MASK] |Channel_Demux[(b>>1) & CHANNEL_DEMUX_MASK] << 4;
     }
     /* -------------- */
     
     
     
     uint8_t retval;
     if ((retval = AudioProcess((uint16_t *)PDMbuff, (uint16_t *)PCMbuff))!=0)
     {
          HAL_UART_Transmit(&huart2,&A,1,1000);

     }
     else
     {
          /* uart bitrate = 921600bps, more than enough to stream the 16kHz PCM */          
          
          //HAL_UART_Transmit(&huart2,(uint8_t *)PCMbuff,sizeof(uint16_t)*32,1000);
          HAL_UART_Transmit_DMA(&huart2,(uint8_t *)PCMbuff,PCMbufflen);
     }
}


uint8_t AudioProcess(uint16_t *PDMBuf, uint16_t *PCMBuf)
{
     PDM_Filter(PDMBuf,PCMBuf,&hfiltro);                 // PDM_Filter on even and odd bytes to convert both channels
     return(PDM_Filter(PDMBuf+1,PCMBuf+1,&hfiltro));     // return PDM_Filter exit status

}

 

Recap, the main issues are:

- I can't figure what "high_pass_tap" parameter does;

- Importing the serial dump file into audacity there is nothing that resemble the actual sound activity (me blowing into the microphones) and resetting the MCU the behaviour changes! Sometimes in the waveform there are the "blobs" that could be me blowing but it's heavily distorted.

Outcomes