Quentin Roche / X_NUCLEO_CCA02M1

Dependencies:   ST_FREQUENCY_DIVIDER ST_I2S USBDEVICE

Fork of X_NUCLEO_CCA02M1 by ST

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
 }