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

 

1 REPLY 1
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".