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 ?
2025-10-24 9:17 AM
Hi,
I made fast Python script for that:
Noise floor: -51.33 dB
Noise level: -25.31 dBFS
I'm surprised by this noise because in the BSP example for this devboard there is an example with recording and playing sound and the sound is very clear.
2025-10-24 10:08 AM
Hi,
> I made fast Python script for that:
cool.
Did you check the signals on mic : clk , D ? frequency ?
2025-10-24 11:08 AM
That background white noise is quite common with the STM32H747-DISCO’s onboard PDM mic — it’s not necessarily your code, but rather the PDM clocking and analog front-end noise.
Here are a few things worth trying:
Use lower PDM clock — try ~1.5–2 MHz instead of 3 MHz. The onboard mic often gets noisy above 2 MHz.
Enable high-pass filter in the PDM lib (set high_pass_tap to a smaller value like 0x05A0E000) — it can reduce DC/low-frequency hiss.
Add averaging or window smoothing on PCM samples before saving (simple FIR or moving average works well).
Shorter wiring + proper grounding if you’re testing on breadboard or using jumpers — noise pickup is huge on fast digital lines.
Try decimation factor 64 — at 24 kHz sample rate, this sometimes gives cleaner results than 128 (less aliasing).
If the white noise remains constant even in silence, it’s hardware-level — that built-in mic just has a high noise floor. For production-quality audio, consider an external PDM or analog mic via I²S/SAI.
Hope this helps you get a cleaner signal!
2025-10-24 3:42 PM
I checked the clock and it is getting the right frequency
2025-10-24 4:02 PM
What is the main clock source? I see, that CubeMX starting project with HSI.
From my experience, HSI should not be in use if analog signal processing required, no with adc or dac.
Seems there are 20 MHz crystal, try to reconfigure your clock tree
2025-10-25 4:38 AM
Good point! I'll check it out