PDM captured data from mic is distorted

Hello, we are capturing sound with a PDM mic, and sending it to a codec through I2S. We have tested the I2S with software generated pure tones, and it is working properly. When we send the mic sound to the coded it is distorted so we think the problem is related to the microphone missconfiguration.

There are two interrupts, one for I2S, another for the PDM. We are using nordic drivers for both. The PDM buffer is copied in a "for loop"  into the I2S when both interrup handlers mark the buffer release event.

The microphone is configured for data capture on clk rise, mono. Desired sampling is 16KHz.

Thanks in advance for reviewing the code.

#include "pdm-microphone.h"
#include "I2S_port.h"  
#include <nrfx_pdm.h>
#include <nrfx.h>
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(PDMport);

//Definir el tipo del array igual que word_size
int16_t pdm_data_frame[NUM_SAMPLES];
int16_t pdm_data_frame2[NUM_SAMPLES];
int16_t *pdm_active_buffer = pdm_data_frame;
int16_t *pdm_previous_buffer = pdm_data_frame2;

bool pdm_ready_flag = false;

//uint16_t pdm_buffer_size = PDM_N_WORDS;
uint16_t pdm_buffer_size = NUM_SAMPLES;

ISR_DIRECT_DECLARE(pdm_isr_handler)
{
    nrfx_pdm_irq_handler();
    ISR_DIRECT_PM(); // PM done after servicing interrupt for best latency
             
    return 1;
}

static void pdm_data_handler(nrfx_pdm_evt_t const * p_evt)
{
        nrfx_err_t err = 0;
        LOG_INF("PDM data Handler");  

        if(true == p_evt->buffer_requested){
            err = nrfx_pdm_buffer_set(pdm_active_buffer, pdm_buffer_size);
            if(err != NRFX_SUCCESS)
            {
                printk("PDM buffer init error: %d\n", err);
            }
        }

        if(p_evt->buffer_released != 0){

            // Swap active and next buffer
            uint32_t *pdm_tmp = pdm_active_buffer;
            pdm_active_buffer = pdm_previous_buffer;
            pdm_previous_buffer = pdm_tmp;

            pdm_ready_flag = true;
            LOG_INF("PDM buffer released, dataflag =TRUE");

        }
}

void init_microphone ()
{
    nrfx_pdm_config_t config_pdm = NRFX_PDM_DEFAULT_CONFIG(PDM_CLK_PIN, PDM_DIN_PIN);

    //***Run from 32MHz
    //config_pdm.clock_freq = NRF_PDM_FREQ_1280K;
    //config_pdm.ratio = NRF_PDM_RATIO_80X;
   
    //***Run from ACLK, PDM_CLK =1.024MHz (fsample= PDM_CLK/Ratio = 16KHz)
    //***PDM_CLK= fsource / [(4096**1048576)/(PDMCLKCTRL_regval)];, fsample= PDM_CLK / ratio.
    config_pdm.clock_freq = 0x15555555;
    config_pdm.mclksrc = NRF_PDM_MCLKSRC_ACLK;

    //Select-->GND , MIC captura dato en flanco de subida.
    config_pdm.edge = NRF_PDM_EDGE_LEFTRISING;

    IRQ_DIRECT_CONNECT (PDM0_IRQn, 0, pdm_isr_handler, 0);

    nrfx_err_t err = nrfx_pdm_init(&config_pdm, pdm_data_handler);
    if(err != NRFX_SUCCESS){
        printk("PDM init error: %d\n", err);
    }

    err = nrfx_pdm_start();

    if (err == NRFX_SUCCESS)
    {
        printk("Pdm start was successfull\n");
    }
    else {
        printk("Pdm start was NOT successfull\n");
    }

}

this is the main code:

int main(void)
{

    nrfx_err_t err_code;
    err_code = get_sound_init();
    //***Configura I2C
    init_i2c_device();
    //***Configura microphono PDM
    init_microphone();

        while (true) {

            if (I2S_ready_flag)
             {
                if (pdm_ready_flag)
                {
                convert_PDM_buffer_to_I2S_output();
                // Reset the data_ready_flag
                data_ready_flag = false;
                pdm_ready_flag = false;
                }
            }

        k_msleep(10);

        }

return 0;
}
Parents
  • Hi 

    In case the code shared by Ajaysinh doesn't fix the issue, could you provide a bit more details on the sound distortion? 

    Are you getting repeated clicks, or is the distortion more random in nature? 

    What is the size of NUM_SAMPLES in your test? 

    Best regards
    Torbjørn

  • Hi, I updated the pdm_event_handler and pdm_init as in the code provided, but same result.

    NUM_SAMPLES=1024

    I see you declare pdm_buffer1 and pdm_buffer2 as unsigned int, are pcm samples saved as unsigned?

  • Hi Ovrebekk, I attach a few seconds of the output sound; I would say it might be related to the decimation filter, but of course we are testing tomorrow the ring buffer as you suggest. Please let me know your opinion, regards.

  • Hi Rafael

    Thanks for sharing the sound. The distortion is quite interesting, none of the clicks and pops you often get if there are buffering issues. 

    Still, possibly you can hear some kind of frequent, rapid interference happening, which could imply some kind of issue when the buffer swap happens (with a buffer size of 1024 you should get 16 buffer swaps every second). 

    What happens if you increase NUM_SAMPLES by a significant amount, try 8192 for instance. Does it affect the distortion? 

    Best regards
    Torbjørn

  • Hi Torbjorn,

    I found the problem and partially fixed it with the buffer ring; As the frequencies of I2S and PDM are slightly different, the interrupts secuence was not constant, so some times the PDM_handler swapped the buffers for a second time before the I2S_data_flag_ready was true.

    Now with the buffer ring, sound is clear till it overflows, because at some point there will be more data from the PDM than the I2S requested.

    I am using both Nordic drivers (I2S,PDM), both have same IRQ priority=7, and both run from ACLK.

    Which is the best approach to solve this?, If the numbers on the register "CONFIG.MCKFREQ" and "PDMCLKCTRL" are multiple, should we reach a perfect sampling synchronization?

    thanks in advance.

  • Hi Rafael

    Using a ring buffer is a good idea, then you should be able to handle the data handover in a more reliable manner. 

    If the I2S and PDM run from the same clock source and use the same audio settings they should run at the same speed. Can you let me know what kind of sample rate, bitrate and channel configuration you are trying to use? 

    Best regards
    Torbjørn

  • Hi Torbjorn,

    recalculated the values of PDMCLKCTRL, and CONFIG.MCKFREQ and finally is working fine, thanks very much for your support.

    regards.

Reply Children
Related