2025-10-23 9:46 AM
Hi everyone,
I’m working on an audio recording project using the STM32H747-DISCO board with its built-in PDM microphone. The recording works — I can clearly hear my voice — but there’s a constant background white noise in the recording. I’m trying to figure out what’s causing it and how to reduce or eliminate it.
I’m using STM32CubeMX + HAL, with a standard SAI + PDM2PCM configuration. The WAV file is saved to an SD card using FATFS.
Here are some key details:
I’m not using any prefix or divider for the sampling rate — I simply feed the microphone with a 3 MHz clock via SAI4A with "User Set Master Clock Devider Value".
I’ve achieved the most satisfying results so far with these settings:
SAMPLE_RATE 24000U
PDM_DECIMATION 128U
PCM_SAMPLES 1024
see my config below:
#define BUTTON_DEBOUNCE_MS 200U
static uint32_t last_button_tick = 0;
#define SAMPLE_RATE 24000U
#define BITS_PER_SAMPLE 16U
#define NUM_CHANNELS 1U
#define PDM_DECIMATION 128U
#define PCM_SAMPLES 1024
#define PDM_HALFWORDS_PER_BLOCK ((PCM_SAMPLES * PDM_DECIMATION) / 16U) // = 64 halfwords
#define PDM_BUF_SIZE (PDM_HALFWORDS_PER_BLOCK * 2U)
#define PCM_BUF_SIZE (PCM_SAMPLES * 2U)
SAI4A configuration :
hsai_BlockA4.Instance = SAI4_Block_A;
hsai_BlockA4.Init.Protocol = SAI_FREE_PROTOCOL;
hsai_BlockA4.Init.AudioMode = SAI_MODEMASTER_RX;
hsai_BlockA4.Init.DataSize = SAI_DATASIZE_16;
hsai_BlockA4.Init.FirstBit = SAI_FIRSTBIT_LSB;
hsai_BlockA4.Init.ClockStrobing = SAI_CLOCKSTROBING_FALLINGEDGE;
hsai_BlockA4.Init.Synchro = SAI_ASYNCHRONOUS;
hsai_BlockA4.Init.OutputDrive = SAI_OUTPUTDRIVE_DISABLE;
hsai_BlockA4.Init.NoDivider = SAI_MASTERDIVIDER_DISABLE;
hsai_BlockA4.Init.MckOverSampling = SAI_MCK_OVERSAMPLING_DISABLE;
hsai_BlockA4.Init.FIFOThreshold = SAI_FIFOTHRESHOLD_1QF;
hsai_BlockA4.Init.AudioFrequency = SAI_AUDIO_FREQUENCY_MCKDIV;
hsai_BlockA4.Init.Mckdiv = 1;
hsai_BlockA4.Init.MonoStereoMode = SAI_MONOMODE;
hsai_BlockA4.Init.CompandingMode = SAI_NOCOMPANDING;
hsai_BlockA4.Init.PdmInit.Activation = ENABLE;
hsai_BlockA4.Init.PdmInit.MicPairsNbr = 1;
hsai_BlockA4.Init.PdmInit.ClockEnable = SAI_PDM_CLOCK1_ENABLE;
hsai_BlockA4.FrameInit.FrameLength = 16;
hsai_BlockA4.FrameInit.ActiveFrameLength = 1;
hsai_BlockA4.FrameInit.FSDefinition = SAI_FS_STARTFRAME;
hsai_BlockA4.FrameInit.FSPolarity = SAI_FS_ACTIVE_HIGH;
hsai_BlockA4.FrameInit.FSOffset = SAI_FS_FIRSTBIT;
hsai_BlockA4.SlotInit.FirstBitOffset = 0;
hsai_BlockA4.SlotInit.SlotSize = SAI_SLOTSIZE_DATASIZE;
hsai_BlockA4.SlotInit.SlotNumber = 1;
hsai_BlockA4.SlotInit.SlotActive = 0x00000001;
PDM configuration:
PDM1_filter_handler.bit_order = PDM_FILTER_BIT_ORDER_MSB;
PDM1_filter_handler.endianness = PDM_FILTER_ENDIANNESS_BE;
PDM1_filter_handler.high_pass_tap = 2104533974;
PDM1_filter_handler.in_ptr_channels = 1;
PDM1_filter_handler.out_ptr_channels = 1;
PDM_Filter_Init(&PDM1_filter_handler);
PDM1_filter_config.decimation_factor = PDM_FILTER_DEC_FACTOR_128 ;
PDM1_filter_config.output_samples_number = 1024;
PDM1_filter_config.mic_gain = 0;
PDM_Filter_setConfig(&PDM1_filter_handler, &PDM1_filter_config);
conversion functions:
static void flush_sd_buffer(void)
{
if (sd_buf_ptr == 0) return;
UINT bw = 0;
FRESULT res = f_write(&SDFile, (uint8_t*)SD_WriteBuffer, sd_buf_ptr, &bw);
if (res != FR_OK || bw != sd_buf_ptr) {
/* obsłuż błąd zapisu - tu prosty debug print*/
printf("SD write error or short write (res=%d bw=%u expected=%u)\n", (int)res, (unsigned)bw, (unsigned)sd_buf_ptr);
}
printf("SD flush: wrote %u bytes\n", (unsigned)bw);
total_data_bytes += bw;
sd_buf_ptr = 0;
}
void write_pcm_samples_to_sd(int16_t *pcm_data, UINT samples)
{
UINT bytes = samples * sizeof(int16_t); // 16 samples * 2 bytes = 32 bytes
printf("write_pcm_samples_to_sd: samples=%u, bytes=%u, sd_buf_ptr=%u\n",
samples, bytes, sd_buf_ptr);
UINT offset = 0;
while (offset < bytes) {
UINT space = sizeof(SD_WriteBuffer) - sd_buf_ptr;
UINT to_copy = (bytes - offset) < space ? (bytes - offset) : space;
memcpy(&SD_WriteBuffer[sd_buf_ptr], (uint8_t*)&pcm_data[offset / 2], to_copy);
sd_buf_ptr += to_copy;
offset += to_copy;
if (sd_buf_ptr >= sizeof(SD_WriteBuffer)) {
flush_sd_buffer();
}
}
printf("write_pcm_samples_to_sd: copied %lu bytes (%.1f ms of audio)\r\n",
(uint32_t)(PCM_SAMPLES * sizeof(int16_t)),
(1000.0f * PCM_SAMPLES / 8000.0f));
}
void Audio_Process(void)
{
if (!recording_active) return;
if (pdm_half_ready)
{
pdm_half_ready = 0;
printf("[PDM HALF] Start processing...\r\n");
printf(" PDM buffer size: %lu bytes\r\n", (uint32_t)sizeof(PDM_Buffer));
printf(" PCM buffer size: %lu bytes\r\n", (uint32_t)sizeof(PCM_Buffer));
printf(" PCM samples per block: %lu\r\n", (uint32_t)PCM_SAMPLES);
/* Konwersja pierwszej połowy bufora PDM -> PCM */
PDM_Filter((void*)&PDM_Buffer[0],
(void*)&PCM_Buffer[0],
&PDM1_filter_handler);
printf(" -> PDM_Filter done, writing %lu samples (%lu bytes)\r\n",
(uint32_t)PCM_SAMPLES,
(uint32_t)(PCM_SAMPLES * sizeof(int16_t)));
write_pcm_samples_to_sd(&PCM_Buffer[0], PCM_SAMPLES);
}
if (pdm_full_ready)
{
pdm_full_ready = 0;
printf("[PDM FULL] Start processing...\r\n");
printf(" PDM buffer size: %lu bytes\r\n", (uint32_t)sizeof(PDM_Buffer));
printf(" PCM buffer size: %lu bytes\r\n", (uint32_t)sizeof(PCM_Buffer));
printf(" PCM samples per block: %lu\r\n", (uint32_t)PCM_SAMPLES);
/* Konwersja drugiej połowy bufora PDM -> PCM */
PDM_Filter((void*)&PDM_Buffer[PDM_BUF_SIZE / 2],
(void*)&PCM_Buffer[PCM_BUF_SIZE / 2],
&PDM1_filter_handler);
printf(" -> PDM_Filter done, writing %lu samples (%lu bytes)\r\n",
(uint32_t)PCM_SAMPLES,
(uint32_t)(PCM_SAMPLES * sizeof(int16_t)));
write_pcm_samples_to_sd(&PCM_Buffer[PCM_BUF_SIZE / 2], PCM_SAMPLES);
}
}
2025-10-23 12:58 PM
Hi,
> but there’s a constant background white noise
How much noise ? (try some audio program, FFT, to get a number of - xx dB noise level)
Because every mic will have background noise, so the question is: much more than it should have,
or -depending on your settings for Fs and decimation- about the expected noise ?