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
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.
Revision 11:b2f7f79026e4, committed 2017-04-28
- Comitter:
- davide.aliprandi@st.com
- Date:
- Fri Apr 28 17:22:13 2017 +0200
- Parent:
- 9:4c3d94b67a6b
- Child:
- 12:193d495b4688
- Commit message:
- OpenPDM2PCM library improved.
Changed in this revision
--- a/BSP/PDM2PCMAudio.cpp Thu Apr 27 17:05:38 2017 +0200
+++ b/BSP/PDM2PCMAudio.cpp Fri Apr 28 17:22:13 2017 +0200
@@ -89,7 +89,6 @@
#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]);
- index++;
#else
PDM_Filter_64_LSB(&((uint8_t *) input_buffer)[index], (uint16_t *) &(output_buffer[index]), volume, (PDMFilter_InitStruct *) &_PDM2PCM_filter[index]);
#endif
@@ -106,7 +105,6 @@
#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]);
- index++;
#else
PDM_Filter_128_LSB(&((uint8_t *) input_buffer)[index], (uint16_t *) &(output_buffer[index]), volume, (PDMFilter_InitStruct *) &_PDM2PCM_filter[index]);
#endif
--- a/BSP/XNucleoCCA02M1.cpp Thu Apr 27 17:05:38 2017 +0200
+++ b/BSP/XNucleoCCA02M1.cpp Fri Apr 28 17:22:13 2017 +0200
@@ -80,8 +80,10 @@
#ifdef USE_OPEN_PDM2PCM_LIBRARY
/* Checking input parameters. */
- if (!((_frequency == 16000) && (_channels == 2)))
- error("\r\nConfiguration error: Currently only two channels at 16KHz are supported.\n\r");
+ if (!(((_frequency == 16000) && (_channels == 1)) ||
+ ((_frequency == 16000) && (_channels == 2)) ||
+ ((_frequency == 32000) && (_channels == 1))))
+ error("\r\nConfiguration error: Currently only mono@16KHz, stero@16KHz or mono@32KHz are supported.\n\r");
#endif
/* Setting configuration. */
@@ -111,11 +113,9 @@
/* Allocating support buffers. */
_PDM_buffer_one_ms = (uint16_t *) calloc(_PDM_samples_one_ms, sizeof(uint16_t));
- /* Starting the I2S frequency divider, if needed. */
- if (_channels == 2) {
- FrequencyDivider *divider = new FrequencyDivider();
- divider->start();
- }
+ /* Starting the I2S frequency divider. */
+ FrequencyDivider *divider = new FrequencyDivider();
+ divider->start();
/* Initializing the PDM to PCM conversion library. */
if ((_pdm2pcm = new PDM2PCMAudio(_frequency, _channels)) == NULL)
--- a/BSP/XNucleoCCA02M1_config.h Thu Apr 27 17:05:38 2017 +0200 +++ b/BSP/XNucleoCCA02M1_config.h Fri Apr 28 17:22:13 2017 +0200 @@ -73,6 +73,6 @@ * Enable to signal the duration of the PDM2PCM library utilization, which can * be seen through an oscilloscope. */ -//#define PDM2PCM_AUDIO_DEBUG +#define PDM2PCM_AUDIO_DEBUG #endif /* __X_NUCLEO_CCA02M1_CONFIG_H */
--- a/Middlewares/OpenPDM2PCM/OpenPDMFilter.c Thu Apr 27 17:05:38 2017 +0200
+++ b/Middlewares/OpenPDM2PCM/OpenPDMFilter.c Fri Apr 28 17:22:13 2017 +0200
@@ -58,37 +58,32 @@
/* Functions -----------------------------------------------------------------*/
-int64_t filterTable(uint8_t *data, uint8_t table, TPDMFilter_InitStruct *Param);
+int64_t filterTable(uint8_t *data, uint8_t table, uint8_t decimation, 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 */]);
-inline int64_t filterTable(uint8_t *data, uint8_t table, TPDMFilter_InitStruct *Param)
+inline int64_t filterTable(uint8_t *data, uint8_t table, uint8_t decimation, uint8_t channels)
{
- uint16_t counter = 0;
+ uint8_t c, i, j;
+ uint16_t data_index = 0;
+ uint32_t *coef_p = &coef[table][0];
int64_t F = 0;
- uint8_t c;
- uint8_t i;
- uint16_t internal_bit = Param->bit[table];
- uint16_t In_Mic = Param->In_MicChannels;
- c = data[0];
- for (i=0; i<Param->Decimation; i++)
+ for (i = 0; i < decimation; i += 8)
{
- if (c & (1<<((7-internal_bit))))
- F += coef[table][i];
- internal_bit++;
- if (internal_bit==8)
- {
- counter += In_Mic;
- internal_bit = 0;
- c = data[counter];
- }
+ c = data[data_index];
+ F += ((c >> 7) ) * coef_p[i ] +
+ ((c >> 6) & 0x01) * coef_p[i + 1] +
+ ((c >> 5) & 0x01) * coef_p[i + 2] +
+ ((c >> 4) & 0x01) * coef_p[i + 3] +
+ ((c >> 3) & 0x01) * coef_p[i + 4] +
+ ((c >> 2) & 0x01) * coef_p[i + 5] +
+ ((c >> 1) & 0x01) * coef_p[i + 6] +
+ ((c ) & 0x01) * coef_p[i + 7];
+ data_index += channels;
}
- Param->bit[table] = internal_bit;
- Param->byte = counter;
-
return F;
}
@@ -245,42 +240,42 @@
switch(Param->SincN)
{
case 1:
- Z = filterTable(data,0, Param);
+ Z = filterTable(data, 0, Param->Decimation, Param->In_MicChannels);
break;
case 2:
- Z = Param->Coef[0] + filterTable(data,1, Param);
- Param->Coef[0] = filterTable(data,0, Param);
+ Z = Param->Coef[0] + filterTable(data, 1, Param->Decimation, Param->In_MicChannels);
+ Param->Coef[0] = filterTable(data, 0, Param->Decimation, Param->In_MicChannels);
break;
case 3:
- Z = Param->Coef[1] + filterTable(data,2, Param);
- Param->Coef[1] = Param->Coef[0] + filterTable(data,1, Param);
- Param->Coef[0] = filterTable(data,0, Param);
+ Z = Param->Coef[1] + filterTable(data, 2, Param->Decimation, Param->In_MicChannels);
+ Param->Coef[1] = Param->Coef[0] + filterTable(data, 1, Param->Decimation, Param->In_MicChannels);
+ Param->Coef[0] = filterTable(data, 0, Param->Decimation, Param->In_MicChannels);
break;
case 4:
- Z = Param->Coef[2] + filterTable(data,3, Param);
- Param->Coef[2] = Param->Coef[1] + filterTable(data,2, Param);
- Param->Coef[1] = Param->Coef[0] + filterTable(data,1, Param);
- Param->Coef[0] = filterTable(data,0, Param);
+ Z = Param->Coef[2] + filterTable(data, 3, Param->Decimation, Param->In_MicChannels);
+ Param->Coef[2] = Param->Coef[1] + filterTable(data, 2, Param->Decimation, Param->In_MicChannels);
+ Param->Coef[1] = Param->Coef[0] + filterTable(data, 1, Param->Decimation, Param->In_MicChannels);
+ Param->Coef[0] = filterTable(data, 0, Param->Decimation, Param->In_MicChannels);
break;
case 5:
- Z = Param->Coef[3] + filterTable(data,4, Param);
- Param->Coef[3] = Param->Coef[2] + filterTable(data,3, Param);
- Param->Coef[2] = Param->Coef[1] + filterTable(data,2, Param);
- Param->Coef[1] = Param->Coef[0] + filterTable(data,1, Param);
- Param->Coef[0] = filterTable(data,0, Param);
+ Z = Param->Coef[3] + filterTable(data, 4, Param->Decimation, Param->In_MicChannels);
+ Param->Coef[3] = Param->Coef[2] + filterTable(data, 3, Param->Decimation, Param->In_MicChannels);
+ Param->Coef[2] = Param->Coef[1] + filterTable(data, 2, Param->Decimation, Param->In_MicChannels);
+ Param->Coef[1] = Param->Coef[0] + filterTable(data, 1, Param->Decimation, Param->In_MicChannels);
+ Param->Coef[0] = filterTable(data, 0, Param->Decimation, Param->In_MicChannels);
break;
}
- Z-=SubConst;
+ Z -= SubConst;
- if(Param->HP_ALFA!= 0)
+ if (Param->HP_ALFA!= 0)
{
OldOut = (Param->HP_ALFA * (OldOut + Z - OldIn))/256;
- OldIn=Z;
- Z=OldOut;
+ OldIn = Z;
+ Z = OldOut;
}
- if(Param->LP_ALFA != 0)
+ if (Param->LP_ALFA != 0)
{
OldZ = ((256-Param->LP_ALFA)*OldZ+Param->LP_ALFA*Z)/256;
Z = OldZ;
@@ -295,9 +290,7 @@
// }
Z = SaturaLH(Z, -32700, 32700); // saturation
dataOut[i*Param->Out_MicChannels] = Z ;
- // data+=(Param->Decimation-app)/8 * Param->In_MicChannels;
- data+=Param->byte;
- // data+=Param->Decimation/8*Param->In_MicChannels;
+ data += ((Param->Decimation / 8) * Param->In_MicChannels);
}
Param->OldOut=OldOut;
Param->OldIn=OldIn;

X-NUCLEO-CCA02M1 Digital MEMS Microphones Expansion Board.