cancel
Showing results for 
Search instead for 
Did you mean: 

SDMMC & SAI configuration on PDM microphone - how to deal with background noise? STM32H747-DISCO

Patryk_Kucia
Associate III

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:

Patryk_Kucia_0-1761237458136.png

#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);
    }
}

 

7 REPLIES 7
AScha.3
Super User

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 ?

 

If you feel a post has answered your question, please click "Accept as Solution".

Hi,

I made fast Python script for that:

Noise floor: -51.33 dB
Noise level: -25.31 dBFS

Patryk_Kucia_0-1761322609283.png

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.

 

 

 

Hi,

I made fast Python script for that:

cool.

 

Did you check the signals on mic : clk , D ? frequency ?

If you feel a post has answered your question, please click "Accept as Solution".
jameswilliam
Associate II

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:

  1. Use lower PDM clock — try ~1.5–2 MHz instead of 3 MHz. The onboard mic often gets noisy above 2 MHz.

  2. 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.

  3. Add averaging or window smoothing on PCM samples before saving (simple FIR or moving average works well).

  4. Shorter wiring + proper grounding if you’re testing on breadboard or using jumpers — noise pickup is huge on fast digital lines.

  5. 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!

I checked the clock and it is getting the right frequency

MasterT
Lead

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

Good point! I'll check it out