Library to handle the X-NUCLEO-CCA02M1 MEMS Microphones Expansion Board.

Dependencies:   ST_I2S ST_FREQUENCY_DIVIDER USBDEVICE

Dependents:   HelloWorld_CCA02M1 HelloWorld_CCA02M1_mbedOS HelloWorld_CCA02M1 Karaoke_CCA01M1_CCA02M1_mbedOS

Fork of X_NUCLEO_CCA02M1 by ST Expansion SW Team

MEMS Microphones Library

Library to handle the X-NUCLEO-CCA02M1 MEMS Microphones Expansion Board. A single board allows to record a standard 2-channel stereo signal as an array of PCM samples (16 bit/sample); in principle, it could make use of six additional MEMS microphones to realize a 8-channel audio system.


Microphones configuration

Currently the configurations supported are the following:

  • Stereo@48KHz
  • Stereo@44.1KHz (CD audio quality)
  • Stereo@32KHz
  • Stereo@16KHz
  • Stereo@8KHz
  • Mono@48KHz
  • Mono@44.1KHz
  • Mono@32KHz
  • Mono@16KHz
  • Mono@8KHz

Mono configurations need a Jumper connecting PB_5 and PB_13 on the Morpho connector to properly work.


Platform compatibility

  • This board can be currently used with the Nucleo F4 Family only, please see the ST_I2S library compatibility for further information.
  • The library is compatible both with mbed OS 5.x and mbed classic 2.x (to work with mbed classic, the main application has to import the "events" library, which is not included into the "mbed" library).


I2S Peripheral Usage

By default this board makes use of the I2S peripheral available on Nucleo boards.


Acquiring through the USB

In order to acquire the recorded PCM audio channel with an audio SW on a PC, please connect the expansion board to a USB port of the PC, and the Nucleo board to a USB power supply.

Files at this revision

API Documentation at this revision

Comitter:
Davidroid
Date:
Fri May 05 11:34:10 2017 +0000
Parent:
19:1a061e306cc9
Child:
21:9d301ba97e69
Commit message:
Simplifying code.

Changed in this revision

BSP/PDM2PCMAudio.cpp Show annotated file Show diff for this revision Revisions of this file
BSP/PDM2PCMAudio.h Show annotated file Show diff for this revision Revisions of this file
BSP/XNucleoCCA02M1.cpp Show annotated file Show diff for this revision Revisions of this file
BSP/XNucleoCCA02M1.h Show annotated file Show diff for this revision Revisions of this file
Middlewares/OpenPDM2PCM/OpenPDMFilter.c Show annotated file Show diff for this revision Revisions of this file
Middlewares/OpenPDM2PCM/OpenPDMFilter.h Show annotated file Show diff for this revision Revisions of this file
--- a/BSP/PDM2PCMAudio.cpp	Thu May 04 10:39:39 2017 +0000
+++ b/BSP/PDM2PCMAudio.cpp	Fri May 05 11:34:10 2017 +0000
@@ -68,55 +68,58 @@
 /* Methods -------------------------------------------------------------------*/
 
 /**
-* @brief  Converting audio data from PDM to PCM.
-* @param  output_buffer     Pointer to output PCM buffer data.
-* @param  input_buffer      Pointer to input PDM buffer data.
-* @param  volume            Volume level (it must be in the range [0..64]).
-* @param  decimation_factor Decimation factor (it must be either 64 or 128).
-* @retval COMPONENT_OK in case of success, COMPONENT_ERROR otherwise.
-*/
-status_t PDM2PCMAudio::convert(int16_t *output_buffer, uint16_t *input_buffer, uint32_t volume, uint32_t decimation_factor)
+ * @brief  Getting number of PCM samples from nummber of PDM samples.
+ * @param  PCM_samples Number of PCM samples.
+ * @retval Number of equivalent PDM samples.
+ */
+uint32_t PDM2PCMAudio::pcm2pdm_samples(uint32_t PCM_samples)
+{
+    return PCM_samples * (_decimation_factor >> 4);
+}
+
+/**
+ * @brief  Converting audio data from PDM to PCM.
+ * @param  output_buffer     Pointer to output PCM buffer data.
+ * @param  input_buffer      Pointer to input PDM buffer data.
+ * @param  volume            Volume level (it must be in the range [0..PDM2PCM_MAX_VOLUME]).
+ * @retval COMPONENT_OK in case of success, COMPONENT_ERROR otherwise.
+ */
+status_t PDM2PCMAudio::convert(int16_t *output_buffer, uint16_t *input_buffer, uint32_t volume)
 {
     if (!(volume <= PDM2PCM_MAX_VOLUME))
-        error("Volume level not supported: it must be in the range [0..64].\r\n");
+        error("Volume level not supported: it must be in the range [0..%d].\r\n", PDM2PCM_MAX_VOLUME);
 
-    switch (decimation_factor)
+#ifdef PDM2PCM_AUDIO_DEBUG
+                _pdm2pcm_audio_signal = 1;
+#endif
+    switch (_decimation_factor)
     {
         case 64:
             for (uint32_t index = 0; index < _channels; index++) {
-#ifdef PDM2PCM_AUDIO_DEBUG
-                _pdm2pcm_audio_signal = 1;
-#endif
 #ifdef USE_OPEN_PDM2PCM_LIBRARY
-                Open_PDM_Filter(&((uint8_t *) input_buffer)[index], (uint16_t *) &(output_buffer[index]), volume, (TPDMFilter_InitStruct *) &_PDM2PCM_filter[index]);
+                Open_PDM_Filter_64(&((uint8_t *) input_buffer)[index], (uint16_t *) &(output_buffer[index]), volume, (TPDMFilter_InitStruct *) &_PDM2PCM_filter[index]);
 #else                
                 PDM_Filter_64_LSB(&((uint8_t *) input_buffer)[index], (uint16_t *) &(output_buffer[index]), volume, (PDMFilter_InitStruct *) &_PDM2PCM_filter[index]);
 #endif
-#ifdef PDM2PCM_AUDIO_DEBUG
-                _pdm2pcm_audio_signal = 0;
-#endif
             }
             break;
 
         case 128:
             for (uint32_t index = 0; index < _channels; index++) {
-#ifdef PDM2PCM_AUDIO_DEBUG
-                _pdm2pcm_audio_signal = 1;
-#endif
 #ifdef USE_OPEN_PDM2PCM_LIBRARY
-                Open_PDM_Filter(&((uint8_t *) input_buffer)[index], (uint16_t *) &(output_buffer[index]), volume, (TPDMFilter_InitStruct *) &_PDM2PCM_filter[index]);
+                Open_PDM_Filter_128(&((uint8_t *) input_buffer)[index], (uint16_t *) &(output_buffer[index]), volume, (TPDMFilter_InitStruct *) &_PDM2PCM_filter[index]);
 #else                
                 PDM_Filter_128_LSB(&((uint8_t *) input_buffer)[index], (uint16_t *) &(output_buffer[index]), volume, (PDMFilter_InitStruct *) &_PDM2PCM_filter[index]);
 #endif
-#ifdef PDM2PCM_AUDIO_DEBUG
-                _pdm2pcm_audio_signal = 0;
-#endif
             }
             break;
 
         default:
             error("Decimation factor not supported: it must be either 64 or 128.\r\n");
     }
+#ifdef PDM2PCM_AUDIO_DEBUG
+                _pdm2pcm_audio_signal = 0;
+#endif
 
     return COMPONENT_OK;
 }
--- a/BSP/PDM2PCMAudio.h	Thu May 04 10:39:39 2017 +0000
+++ b/BSP/PDM2PCMAudio.h	Fri May 05 11:34:10 2017 +0000
@@ -69,12 +69,11 @@
 
 /* Definitions ---------------------------------------------------------------*/
 
-#define DEMUX_FILTER_SIZE         128
-#define DEMUX_FILTER_MASK         0x55
-#define PDM2PCM_FILTER_SIZE       4
-#define PDM2PCM_NOGAIN_VOLUME     4
-#define PDM2PCM_MAX_VOLUME        64
-#define PDM2PCM_DECIMATION_FACTOR 64
+#define DEMUX_FILTER_SIZE      128
+#define DEMUX_FILTER_MASK     0x55
+#define PDM2PCM_FILTER_SIZE      4
+#define PDM2PCM_NOGAIN_VOLUME    4
+#define PDM2PCM_MAX_VOLUME      64
 
 
 /* Classes -------------------------------------------------------------------*/
@@ -100,6 +99,22 @@
 	    /* Enable CRC peripheral to unlock the PDM2PCMAudio library. */
 	    __CRC_CLK_ENABLE();
 
+	 	/* Setting configuration. */
+	    switch (_frequency)
+	    {
+	        case I2S_AUDIOFREQ_8K:
+	            _decimation_factor = 128;
+	            break;
+	
+	        case I2S_AUDIOFREQ_16K:
+	        case I2S_AUDIOFREQ_32K:
+	        case I2S_AUDIOFREQ_44K:
+	        case I2S_AUDIOFREQ_48K:
+	        default:
+	            _decimation_factor = 64;
+	            break;
+	    }
+
 	    /* Initializing PDM2PCMAudio Filter. */
 	    for (uint32_t i = 0; i < _channels; i++)
 	    {
@@ -109,6 +124,8 @@
 	        _PDM2PCM_filter[i].Fs = _frequency;
 	        _PDM2PCM_filter[i].Out_MicChannels = _channels;
 	        _PDM2PCM_filter[i].In_MicChannels = _channels;
+	        _PDM2PCM_filter[i].Decimation = _decimation_factor;
+	        _PDM2PCM_filter[i].MaxVolume = PDM2PCM_MAX_VOLUME;
 #ifdef USE_OPEN_PDM2PCM_LIBRARY
 	        Open_PDM_Filter_Init((TPDMFilter_InitStruct *) &_PDM2PCM_filter[i]);
 #else
@@ -118,14 +135,20 @@
     };
 
 	/**
-	* @brief  Converting audio data from PDM to PCM.
-	* @param  output_buffer     Pointer to output PCM buffer data.
-	* @param  input_buffer      Pointer to input PDM buffer data.
-	* @param  volume            Volume level (it must be in the range [0..64]).
-	* @param  decimation_factor Decimation factor (it must be either 64 or 128).
-	* @retval COMPONENT_OK in case of success, COMPONENT_ERROR otherwise.
-	*/
-	status_t convert(int16_t *output_buffer, uint16_t *input_buffer, uint32_t volume, uint32_t decimation_factor);
+	 * @brief  Getting number of PCM samples from nummber of PDM samples.
+     * @param  PCM_samples Number of PCM samples.
+	 * @retval Number of equivalent PDM samples.
+	 */
+	uint32_t pcm2pdm_samples(uint32_t PCM_samples);
+
+	/**
+	 * @brief  Converting audio data from PDM to PCM.
+	 * @param  output_buffer     Pointer to output PCM buffer data.
+	 * @param  input_buffer      Pointer to input PDM buffer data.
+	 * @param  volume            Volume level (it must be in the range [0..PDM2PCM_MAX_VOLUME]).
+	 * @retval COMPONENT_OK in case of success, COMPONENT_ERROR otherwise.
+	 */
+	status_t convert(int16_t *output_buffer, uint16_t *input_buffer, uint32_t volume);
 
 	/**
 	 * @brief  Scrambling audio data.
@@ -150,6 +173,7 @@
 
 	uint32_t _frequency;
 	uint32_t _channels;
+	uint32_t _decimation_factor;
 #ifdef USE_OPEN_PDM2PCM_LIBRARY
 	TPDMFilter_InitStruct _PDM2PCM_filter[PDM2PCM_FILTER_SIZE];
 #else
--- a/BSP/XNucleoCCA02M1.cpp	Thu May 04 10:39:39 2017 +0000
+++ b/BSP/XNucleoCCA02M1.cpp	Fri May 05 11:34:10 2017 +0000
@@ -67,7 +67,6 @@
 * @brief  Initializing the X_NUCLEO_CCA02M1 board.
 * @param  init Pointer to device specific initalization structure.
 * @retval "0" in case of success, an error code otherwise.
-* @note   Currently only two channels at 16KHz are supported.
 */
 status_t XNucleoCCA02M1::init(void *init)
 {
@@ -80,7 +79,9 @@
 
 #ifdef USE_OPEN_PDM2PCM_LIBRARY
     /* Checking input parameters. */
-    if (!(((_frequency == 16000) && (_channels == 1)) ||
+    if (!(((_frequency ==  8000) && (_channels == 1)) ||
+          ((_frequency ==  8000) && (_channels == 2)) ||
+          ((_frequency == 16000) && (_channels == 1)) ||
           ((_frequency == 16000) && (_channels == 2)) ||
           ((_frequency == 32000) && (_channels == 1)) ||
           ((_frequency == 32000) && (_channels == 2)) ||
@@ -88,36 +89,9 @@
           ((_frequency == 44100) && (_channels == 2)) ||
           ((_frequency == 48000) && (_channels == 1)) ||
           ((_frequency == 48000) && (_channels == 2))))
-        error("\r\nError: please set one of the following configurations: mono/stereo 16/32/44.1/48 KHz.\n\r");
+        error("\r\nError: please set one of the following configurations: mono/stereo @ 8/16/32/44.1/48 KHz.\r\n");
 #endif
 
-	/* Setting configuration. */
-    switch (_frequency)
-    {
-        case I2S_AUDIOFREQ_8K:
-            _decimation_factor = 128;
-            break;
-
-        case I2S_AUDIOFREQ_16K:
-        case I2S_AUDIOFREQ_32K:
-        case I2S_AUDIOFREQ_48K:
-        default:
-            _decimation_factor = 64;
-            break;
-    }
-
-    /* Buffer sizes in 16-bits samples. */
-    _PCM_samples_one_ms = ((_frequency * _channels) / 1000);
-    _PDM_samples_one_ms = ((_PCM_samples_one_ms * _decimation_factor) / 16);
-    _PDM_samples_two_ms = (_PDM_samples_one_ms << 1);
-
-    /* Allocating input and output buffers. */
-    _PDM_buffer_two_ms = (uint16_t *) calloc(_PDM_samples_two_ms, sizeof(uint16_t));
-    _PCM_buffer_n_ms = (int16_t *) calloc(_PCM_samples_one_ms * PCM_BUFFER_SIZE_ms, sizeof(uint16_t));
-
-    /* Allocating support buffers. */
-    _PDM_buffer_one_ms = (uint16_t *) calloc(_PDM_samples_one_ms, sizeof(uint16_t));
-
     /*
      * Starting the I2S frequency divider.
      * Note: put a jumper to connect PB_5 and PB_13 on the MORPHO connector when
@@ -139,6 +113,18 @@
     dev_i2s.protocol(MSB);
     dev_i2s.format(_channels == 1 ? 16 : 32, _channels == 1 ? 16 : 32, 1);
 
+    /* Buffer sizes in 16-bits samples. */
+    _PCM_samples_one_ms = ((_frequency * _channels) / 1000);
+    _PDM_samples_one_ms = _pdm2pcm->pcm2pdm_samples(_PCM_samples_one_ms);
+    _PDM_samples_two_ms = (_PDM_samples_one_ms << 1);
+
+    /* Allocating input and output buffers. */
+    _PDM_buffer_two_ms = (uint16_t *) calloc(_PDM_samples_two_ms, sizeof(uint16_t));
+    _PCM_buffer_n_ms = (int16_t *) calloc(_PCM_samples_one_ms * PCM_BUFFER_SIZE_ms, sizeof(uint16_t));
+
+    /* Allocating support buffers. */
+    _PDM_buffer_one_ms = (uint16_t *) calloc(_PDM_samples_one_ms, sizeof(uint16_t));
+
     return COMPONENT_OK;
 }
 
@@ -277,7 +263,7 @@
 		_mutex->lock();
 
 		/* Converting PDM to PCM audio data. */
-	    _pdm2pcm->convert(&_PCM_buffer_n_ms[_PCM_buffer_write_index], _PDM_buffer_one_ms, _volume, _decimation_factor);
+	    _pdm2pcm->convert(&_PCM_buffer_n_ms[_PCM_buffer_write_index], _PDM_buffer_one_ms, _volume);
 
         /* Copying PCM data to the user buffer. */
         if (_callback_attached)
--- a/BSP/XNucleoCCA02M1.h	Thu May 04 10:39:39 2017 +0000
+++ b/BSP/XNucleoCCA02M1.h	Fri May 05 11:34:10 2017 +0000
@@ -128,7 +128,6 @@
         dev_i2s(dpin, clk, wsel, fdpin, mck),
         _usb_enabled(false),
         _volume(PDM2PCM_NOGAIN_VOLUME),
-        _decimation_factor(PDM2PCM_DECIMATION_FACTOR),
         _frequency(DEFAULT_FREQUENCY),
         _channels(DEFAULT_CHANNELS),
         _callback_attached(false)
@@ -272,7 +271,6 @@
 
     /* PDM to PCM conversion parameters. */
     uint32_t _volume;
-    uint32_t _decimation_factor;
 
     /* Microphone parameters. */
     uint32_t _frequency;
--- a/Middlewares/OpenPDM2PCM/OpenPDMFilter.c	Thu May 04 10:39:39 2017 +0000
+++ b/Middlewares/OpenPDM2PCM/OpenPDMFilter.c	Fri May 05 11:34:10 2017 +0000
@@ -1,6 +1,6 @@
 /**
 ******************************************************************************
-* @file    OpenPDMFilter.h
+* @file    OpenPDMFilter.c
 * @author  CL
 * @version V1.0.0
 * @date    9-September-2015
@@ -33,41 +33,23 @@
 #include "OpenPDMFilter.h"
 
 
-/* Definitions ---------------------------------------------------------------*/
-
-#define RoundDiv(a, b)    (((a)>0)?(((a)+(b)/2)/(b)):(((a)-(b)/2)/(b)))
-#define SaturaLH(N, L, H) (((N)<(L))?(L):(((N)>(H))?(H):(N)))
-
-#define VOLUME_MAX     64
-#define FILTER_GAIN    16
-
-#define SINCN_MAX       3
-#define DECIMATION_MAX 64
-
-
 /* Variables -----------------------------------------------------------------*/
 
 uint32_t div_const = 0;
 int64_t sub_const = 0;
-uint32_t sinc[DECIMATION_MAX * SINCN_MAX];
+uint32_t sinc[DECIMATION_MAX * SINCN];
 uint32_t sinc1[DECIMATION_MAX];
 uint32_t sinc2[DECIMATION_MAX * 2];
-uint32_t coef[SINCN_MAX][DECIMATION_MAX];
+uint32_t coef[SINCN][DECIMATION_MAX];
 #ifdef USE_LUT
-int32_t lut[256][DECIMATION_MAX / 8][SINCN_MAX];
+int32_t lut[256][DECIMATION_MAX / 8][SINCN];
 #endif
 
 
 /* Functions -----------------------------------------------------------------*/
 
-int32_t filter_table(uint8_t *data, uint8_t sincn, uint8_t channels);
-
-void convolve(uint32_t Signal[/* SignalLen */], unsigned short SignalLen,
-              uint32_t Kernel[/* KernelLen */], unsigned short KernelLen,
-              uint32_t Result[/* SignalLen + KernelLen - 1 */]);
-
 #ifdef USE_LUT
-int32_t filter_table_mono(uint8_t *data, uint8_t sincn)
+int32_t filter_table_mono_64(uint8_t *data, uint8_t sincn)
 {
   return (int32_t)
     lut[data[0]][0][sincn] +
@@ -79,7 +61,7 @@
     lut[data[6]][6][sincn] +
     lut[data[7]][7][sincn];
 }
-int32_t filter_table_stereo(uint8_t *data, uint8_t sincn)
+int32_t filter_table_stereo_64(uint8_t *data, uint8_t sincn)
 {
   return (int32_t)
     lut[data[0]][0][sincn] +
@@ -91,17 +73,59 @@
     lut[data[12]][6][sincn] +
     lut[data[14]][7][sincn];
 }
-int32_t (* filter_tables[2]) (uint8_t *data, uint8_t sincn) = {filter_table_mono, filter_table_stereo};
+int32_t filter_table_mono_128(uint8_t *data, uint8_t sincn)
+{
+  return (int32_t)
+    lut[data[0]][0][sincn] +
+    lut[data[1]][1][sincn] +
+    lut[data[2]][2][sincn] +
+    lut[data[3]][3][sincn] +
+    lut[data[4]][4][sincn] +
+    lut[data[5]][5][sincn] +
+    lut[data[6]][6][sincn] +
+    lut[data[7]][7][sincn] +
+    lut[data[8]][8][sincn] +
+    lut[data[9]][9][sincn] +
+    lut[data[10]][10][sincn] +
+    lut[data[11]][11][sincn] +
+    lut[data[12]][12][sincn] +
+    lut[data[13]][13][sincn] +
+    lut[data[14]][14][sincn] +
+    lut[data[15]][15][sincn];
+}
+int32_t filter_table_stereo_128(uint8_t *data, uint8_t sincn)
+{
+  return (int32_t)
+    lut[data[0]][0][sincn] +
+    lut[data[2]][1][sincn] +
+    lut[data[4]][2][sincn] +
+    lut[data[6]][3][sincn] +
+    lut[data[8]][4][sincn] +
+    lut[data[10]][5][sincn] +
+    lut[data[12]][6][sincn] +
+    lut[data[14]][7][sincn] +
+    lut[data[16]][8][sincn] +
+    lut[data[18]][9][sincn] +
+    lut[data[20]][10][sincn] +
+    lut[data[22]][11][sincn] +
+    lut[data[24]][12][sincn] +
+    lut[data[26]][13][sincn] +
+    lut[data[28]][14][sincn] +
+    lut[data[30]][15][sincn];
+}
+int32_t (* filter_tables_64[2]) (uint8_t *data, uint8_t sincn) = {filter_table_mono_64, filter_table_stereo_64};
+int32_t (* filter_tables_128[2]) (uint8_t *data, uint8_t sincn) = {filter_table_mono_128, filter_table_stereo_128};
 #else
-int64_t filter_table(uint8_t *data, uint8_t sincn, uint8_t channels)
+int32_t filter_table(uint8_t *data, uint8_t sincn, TPDMFilter_InitStruct *param)
 {
   uint8_t c, i;
   uint16_t data_index = 0;
-  uint32_t *coef_p = &coef[table][0];
-  int64_t F = 0;
+  uint32_t *coef_p = &coef[sincn][0];
+  int32_t F = 0;
+  uint8_t decimation = param->Decimation;
+  uint8_t channels = param->In_MicChannels;
 
-  for (i = 0; i < DECIMATION_MAX; i += 8)
-  {
+  for (i = 0; i < decimation; i += 8) {
     c = data[data_index];
     F += ((c >> 7)       ) * coef_p[i    ] +
          ((c >> 6) & 0x01) * coef_p[i + 1] +
@@ -117,50 +141,70 @@
 }
 #endif
 
+void convolve(uint32_t Signal[/* SignalLen */], unsigned short SignalLen,
+              uint32_t Kernel[/* KernelLen */], unsigned short KernelLen,
+              uint32_t Result[/* SignalLen + KernelLen - 1 */])
+{
+  uint16_t n;
+
+  for (n = 0; n < SignalLen + KernelLen - 1; n++)
+  {
+    unsigned short kmin, kmax, k;
+    
+    Result[n] = 0;
+    
+    kmin = (n >= KernelLen - 1) ? n - (KernelLen - 1) : 0;
+    kmax = (n < SignalLen - 1) ? n : SignalLen - 1;
+    
+    for (k = kmin; k <= kmax; k++) {
+      Result[n] += Signal[k] * Kernel[n - k];
+    }
+  }
+}
+
 void Open_PDM_Filter_Init(TPDMFilter_InitStruct *Param)
 {
   uint16_t i, j;
   int64_t sum = 0;
-  for (i = 0; i < SINCN_MAX; i++)
-  {
+
+  uint8_t decimation = Param->Decimation;
+
+  for (i = 0; i < SINCN; i++) {
     Param->Coef[i] = 0;
     Param->bit[i] = 0;
   }
-  for (i = 0; i < DECIMATION_MAX; i++)
-  {
+  for (i = 0; i < decimation; i++) {
     sinc1[i] = 1;
   }
 
   Param->OldOut = Param->OldIn = Param->OldZ = 0;
-  Param->LP_ALFA = (Param->LP_HZ != 0 ? (uint16_t) (Param->LP_HZ * 256 / (Param->LP_HZ + Param->Fs / (2 * 3.14))) : 0);
-  Param->HP_ALFA = (Param->HP_HZ != 0 ? (uint16_t) (Param->Fs * 256 / (2 * 3.14 * Param->HP_HZ + Param->Fs)) : 0);
+  Param->LP_ALFA = (Param->LP_HZ != 0 ? (uint16_t) (Param->LP_HZ * 256 / (Param->LP_HZ + Param->Fs / (2 * 3.14159))) : 0);
+  Param->HP_ALFA = (Param->HP_HZ != 0 ? (uint16_t) (Param->Fs * 256 / (2 * 3.14159 * Param->HP_HZ + Param->Fs)) : 0);
 
-  Param->FilterLen = DECIMATION_MAX * 3;       
+  Param->FilterLen = decimation * SINCN;       
   sinc[0] = 0;
-  sinc[DECIMATION_MAX * 3 - 1] = 0;      
-  convolve(sinc1, DECIMATION_MAX, sinc1, DECIMATION_MAX, sinc2);
-  convolve(sinc2, DECIMATION_MAX * 2 - 1, sinc1, DECIMATION_MAX, &sinc[1]);     
-  for(j = 0; j < 3; j++)
-  {
-    for (i = 0; i < DECIMATION_MAX ;i++)
-    {
-      coef[j][i] = sinc[j * DECIMATION_MAX + i];
-      sum += sinc[j * DECIMATION_MAX + i];
+  sinc[decimation * SINCN - 1] = 0;      
+  convolve(sinc1, decimation, sinc1, decimation, sinc2);
+  convolve(sinc2, decimation * 2 - 1, sinc1, decimation, &sinc[1]);     
+  for(j = 0; j < SINCN; j++) {
+    for (i = 0; i < decimation; i++) {
+      coef[j][i] = sinc[j * decimation + i];
+      sum += sinc[j * decimation + i];
     }
   }
 
   sub_const = sum >> 1;
-  div_const = sub_const * VOLUME_MAX / 32768 / FILTER_GAIN;
+  div_const = sub_const * Param->MaxVolume / 32768 / FILTER_GAIN;
   div_const = (div_const == 0 ? 1 : div_const);
 
 #ifdef USE_LUT
   /* Look-Up Table. */
   uint16_t c, d, s;
-  for (s = 0; s < SINCN_MAX; s++)
+  for (s = 0; s < SINCN; s++)
   {
     uint32_t *coef_p = &coef[s][0];
     for (c = 0; c < 256; c++)
-      for (d = 0; d < DECIMATION_MAX / 8; d++)
+      for (d = 0; d < decimation / 8; d++)
         lut[c][d][s] = ((c >> 7)       ) * coef_p[d * 8    ] +
                        ((c >> 6) & 0x01) * coef_p[d * 8 + 1] +
                        ((c >> 5) & 0x01) * coef_p[d * 8 + 2] +
@@ -173,50 +217,31 @@
 #endif
 }
 
-void convolve(uint32_t Signal[/* SignalLen */], unsigned short SignalLen,
-              uint32_t Kernel[/* KernelLen */], unsigned short KernelLen,
-              uint32_t Result[/* SignalLen + KernelLen - 1 */])
-{
-  uint16_t n;
-  for (n = 0; n < SignalLen + KernelLen - 1; n++)
-  {
-    unsigned short kmin, kmax, k;
-    
-    Result[n] = 0;
-    
-    kmin = (n >= KernelLen - 1) ? n - (KernelLen - 1) : 0;
-    kmax = (n < SignalLen - 1) ? n : SignalLen - 1;
-    
-    for (k = kmin; k <= kmax; k++)
-    {
-      Result[n] += Signal[k] * Kernel[n - k];
-    }
-  }
-}
-
-void Open_PDM_Filter(uint8_t* data, uint16_t* dataOut, uint16_t volume, TPDMFilter_InitStruct *Param)
+void Open_PDM_Filter_64(uint8_t* data, uint16_t* dataOut, uint16_t volume, TPDMFilter_InitStruct *Param)
 {
   uint8_t i, data_out_index;
-  uint8_t decimation = DECIMATION_MAX;
   uint8_t channels = Param->In_MicChannels;
-  uint8_t data_inc = ((decimation >> 3) * channels);
+  uint8_t data_inc = ((DECIMATION_MAX >> 4) * channels);
   int64_t Z, Z0, Z1, Z2;
-  int64_t OldOut, OldIn, OldZ;       
+  int64_t OldOut, OldIn, OldZ;
 
   OldOut = Param->OldOut;
   OldIn = Param->OldIn;
   OldZ = Param->OldZ;
 
-  for (i = 0, data_out_index = 0; i < Param->Fs / 1000; i++, data_out_index += channels) 
-  {
+#ifdef USE_LUT
+  uint8_t j = channels - 1;
+#endif
+
+  for (i = 0, data_out_index = 0; i < Param->Fs / 1000; i++, data_out_index += channels) {
 #ifdef USE_LUT
-    Z0 = filter_tables[channels - 1](data, 0);
-    Z1 = filter_tables[channels - 1](data, 1);
-    Z2 = filter_tables[channels - 1](data, 2);
+    Z0 = filter_tables_64[j](data, 0);
+    Z1 = filter_tables_64[j](data, 1);
+    Z2 = filter_tables_64[j](data, 2);
 #else
-    Z0 = filter_table(data, 0, channels);
-    Z1 = filter_table(data, 1, channels);
-    Z2 = filter_table(data, 2, channels);
+    Z0 = filter_table(data, 0, Param);
+    Z1 = filter_table(data, 1, Param);
+    Z2 = filter_table(data, 2, Param);
 #endif
 
     Z = Param->Coef[1] + Z2 - sub_const;
@@ -225,11 +250,9 @@
 
     OldOut = (Param->HP_ALFA * (OldOut + Z - OldIn)) >> 8;
     OldIn = Z;
-    Z = OldOut;
-    OldZ = ((256 - Param->LP_ALFA) * OldZ + Param->LP_ALFA * Z) >> 8;
-    Z = OldZ;
+    OldZ = ((256 - Param->LP_ALFA) * OldZ + Param->LP_ALFA * OldOut) >> 8;
 
-    Z *= volume;
+    Z = OldZ * volume;
     Z = RoundDiv(Z, div_const);
     Z = SaturaLH(Z, -32700, 32700);
 
@@ -241,3 +264,51 @@
   Param->OldIn = OldIn;
   Param->OldZ = OldZ;
 }
+
+void Open_PDM_Filter_128(uint8_t* data, uint16_t* dataOut, uint16_t volume, TPDMFilter_InitStruct *Param)
+{
+  uint8_t i, data_out_index;
+  uint8_t channels = Param->In_MicChannels;
+  uint8_t data_inc = ((DECIMATION_MAX >> 3) * channels);
+  int64_t Z, Z0, Z1, Z2;
+  int64_t OldOut, OldIn, OldZ;
+
+  OldOut = Param->OldOut;
+  OldIn = Param->OldIn;
+  OldZ = Param->OldZ;
+
+#ifdef USE_LUT
+  uint8_t j = channels - 1;
+#endif
+
+  for (i = 0, data_out_index = 0; i < Param->Fs / 1000; i++, data_out_index += channels) {
+#ifdef USE_LUT
+    Z0 = filter_tables_128[j](data, 0);
+    Z1 = filter_tables_128[j](data, 1);
+    Z2 = filter_tables_128[j](data, 2);
+#else
+    Z0 = filter_table(data, 0, Param);
+    Z1 = filter_table(data, 1, Param);
+    Z2 = filter_table(data, 2, Param);
+#endif
+
+    Z = Param->Coef[1] + Z2 - sub_const;
+    Param->Coef[1] = Param->Coef[0] + Z1;
+    Param->Coef[0] = Z0;
+
+    OldOut = (Param->HP_ALFA * (OldOut + Z - OldIn)) >> 8;
+    OldIn = Z;
+    OldZ = ((256 - Param->LP_ALFA) * OldZ + Param->LP_ALFA * OldOut) >> 8;
+
+    Z = OldZ * volume;
+    Z = RoundDiv(Z, div_const);
+    Z = SaturaLH(Z, -32700, 32700);
+
+    dataOut[data_out_index] = Z;
+    data += data_inc;
+  }
+
+  Param->OldOut = OldOut;
+  Param->OldIn = OldIn;
+  Param->OldZ = OldZ;
+}
--- a/Middlewares/OpenPDM2PCM/OpenPDMFilter.h	Thu May 04 10:39:39 2017 +0000
+++ b/Middlewares/OpenPDM2PCM/OpenPDMFilter.h	Fri May 05 11:34:10 2017 +0000
@@ -44,28 +44,36 @@
 
 /* Definitions ---------------------------------------------------------------*/
 
-#define HTONS(A) ((((uint16_t)(A) & 0xff00) >> 8) | \
-                 (((uint16_t)(A) & 0x00ff) << 8))
-
-
 /*
  * Enable to use a Look-Up Table to improve performances while using more FLASH
  * and RAM memory.
+ * Note: Without Look-Up Table up to stereo@16KHz configuration is supported.
  */
 #define USE_LUT
 
+#define SINCN            3
+#define DECIMATION_MAX 128
+#define FILTER_GAIN     16
+
+#define HTONS(A) ((((uint16_t)(A) & 0xff00) >> 8) | \
+                 (((uint16_t)(A) & 0x00ff) << 8))
+#define RoundDiv(a, b)    (((a)>0)?(((a)+(b)/2)/(b)):(((a)-(b)/2)/(b)))
+#define SaturaLH(N, L, H) (((N)<(L))?(L):(((N)>(H))?(H):(N)))
+
 
 /* Types ---------------------------------------------------------------------*/
 
 typedef struct {
   /* Public */
-  uint16_t Fs;
   float LP_HZ;
   float HP_HZ;
-  uint16_t In_MicChannels;
-  uint16_t Out_MicChannels;
+  uint16_t Fs;
+  uint8_t In_MicChannels;
+  uint8_t Out_MicChannels;
+  uint8_t Decimation;
+  uint8_t MaxVolume;
   /* Private */
-  uint32_t Coef[5];
+  uint32_t Coef[SINCN];
   uint16_t FilterLen;
   int64_t OldOut, OldIn, OldZ;
   uint16_t LP_ALFA;
@@ -78,7 +86,8 @@
 /* Exported functions ------------------------------------------------------- */
 
 void Open_PDM_Filter_Init(TPDMFilter_InitStruct *init_struct);
-void Open_PDM_Filter(uint8_t* data, uint16_t* data_out, uint16_t mic_gain, TPDMFilter_InitStruct *init_struct);
+void Open_PDM_Filter_64(uint8_t* data, uint16_t* data_out, uint16_t mic_gain, TPDMFilter_InitStruct *init_struct);
+void Open_PDM_Filter_128(uint8_t* data, uint16_t* data_out, uint16_t mic_gain, TPDMFilter_InitStruct *init_struct);
 
 #ifdef __cplusplus
 }