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
  • check this code ! 

    #include <stdint.h>
    #include "nrfx_pdm.h"
    
    #define PDM_BUFFER_SIZE 256
    
    
    static int16_t pdm_buffer[PDM_BUFFER_SIZE];
    
    uint16_t *p_buffer;
    uint16_t pdm_buffer1[PDM_BUFFER_SIZE];
    uint16_t pdm_buffer2[PDM_BUFFER_SIZE];
    uint8_t data_ready_flag;
    
    ISR_DIRECT_DECLARE(pdm_isr_handler)
    {
        nrfx_pdm_irq_handler();
        ISR_DIRECT_PM(); /* PM done after servicing interrupt for best latency
                  */
        //printk("pdm_isr_handler\n");
    
        return 1; /* We should check if scheduling decision should be made */
    }
    
    
    void pdm_event_handler(nrfx_pdm_evt_t const *p_evt) {
      
            
            nrfx_err_t err = 0;
    
            if(true == p_evt->buffer_requested){
                if(buffer_no)   err = nrfx_pdm_buffer_set(pdm_buffer2, PDM_BUFFER_SIZE);
                else            err = nrfx_pdm_buffer_set(pdm_buffer1, PDM_BUFFER_SIZE);
    
                buffer_no = !buffer_no;
                
                if(err != NRFX_SUCCESS)
                {
                    printk("PDM buffer init error: %d\n", err);
                }
                else
                {
                    //LOG_DBG("PDM buffer init OK\n");
                }
            }
            if(p_evt->buffer_released != 0){
                printk("buffer_released: %p\n", p_evt->buffer_released);
                p_buffer = p_evt->buffer_released;
                data_ready_flag = true;
    
            }
        }
    
    void i2s_data_handler(nrfx_i2s_buffers_t const *p_released, uint32_t status) {
        if (status & NRFX_I2S_STATUS_NEXT_BUFFERS_NEEDED) {
    
    		printk("i2s_handeller CB ! \n");
    
    		
            // Handle I2S errors or other status conditions
            return;
        }
    }
    
    
    int pdm_init(){
    
    	 nrfx_pdm_config_t pdm_cfg = NRFX_PDM_DEFAULT_CONFIG(25,26);
    
    	 IRQ_DIRECT_CONNECT(PDM0_IRQn, 0, pdm_isr_handler, 0);
    
         
        nrfx_err_t err = nrfx_pdm_init(&pdm_cfg, pdm_event_handler);
        if(err != NRFX_SUCCESS){
            printk("PDM init error: %d\n", err);
        }
        else{
            printk("PDM init OK\n");
        }
    }
    
    
    void check_data(void)
    {
        /* print PCM stream */
        while(!data_ready_flag){
            k_sleep(K_MSEC(1));
        }
    
        data_ready_flag = false;
    
        for(int i = 0; i < PDM_BUFFER_SIZE; i++) {
                printk("%x ", p_buffer[i]);
    
            }
            printk("\n");
    
       // printk("PINRT DATA\n");
    }
    
    nrfx_i2s_buffers_t i2s_buffers;
    
    int main(void) {
    
    	// Initialize PDM
    	pdm_init();
    
    	
    	// Start PDM and I2S
    	 nrfx_err_t err = nrfx_pdm_start();
    	 if(err != NRFX_SUCCESS){
    	 printk("PDM start error: %d\n", err);
    	 }
         else{
    	 	printk("PDM start OK\n");
    	 }
    
    		while (1) {
    			// Your application logic here
    			check_data();
    			k_msleep(2);
    		}
    }

Reply
  • check this code ! 

    #include <stdint.h>
    #include "nrfx_pdm.h"
    
    #define PDM_BUFFER_SIZE 256
    
    
    static int16_t pdm_buffer[PDM_BUFFER_SIZE];
    
    uint16_t *p_buffer;
    uint16_t pdm_buffer1[PDM_BUFFER_SIZE];
    uint16_t pdm_buffer2[PDM_BUFFER_SIZE];
    uint8_t data_ready_flag;
    
    ISR_DIRECT_DECLARE(pdm_isr_handler)
    {
        nrfx_pdm_irq_handler();
        ISR_DIRECT_PM(); /* PM done after servicing interrupt for best latency
                  */
        //printk("pdm_isr_handler\n");
    
        return 1; /* We should check if scheduling decision should be made */
    }
    
    
    void pdm_event_handler(nrfx_pdm_evt_t const *p_evt) {
      
            
            nrfx_err_t err = 0;
    
            if(true == p_evt->buffer_requested){
                if(buffer_no)   err = nrfx_pdm_buffer_set(pdm_buffer2, PDM_BUFFER_SIZE);
                else            err = nrfx_pdm_buffer_set(pdm_buffer1, PDM_BUFFER_SIZE);
    
                buffer_no = !buffer_no;
                
                if(err != NRFX_SUCCESS)
                {
                    printk("PDM buffer init error: %d\n", err);
                }
                else
                {
                    //LOG_DBG("PDM buffer init OK\n");
                }
            }
            if(p_evt->buffer_released != 0){
                printk("buffer_released: %p\n", p_evt->buffer_released);
                p_buffer = p_evt->buffer_released;
                data_ready_flag = true;
    
            }
        }
    
    void i2s_data_handler(nrfx_i2s_buffers_t const *p_released, uint32_t status) {
        if (status & NRFX_I2S_STATUS_NEXT_BUFFERS_NEEDED) {
    
    		printk("i2s_handeller CB ! \n");
    
    		
            // Handle I2S errors or other status conditions
            return;
        }
    }
    
    
    int pdm_init(){
    
    	 nrfx_pdm_config_t pdm_cfg = NRFX_PDM_DEFAULT_CONFIG(25,26);
    
    	 IRQ_DIRECT_CONNECT(PDM0_IRQn, 0, pdm_isr_handler, 0);
    
         
        nrfx_err_t err = nrfx_pdm_init(&pdm_cfg, pdm_event_handler);
        if(err != NRFX_SUCCESS){
            printk("PDM init error: %d\n", err);
        }
        else{
            printk("PDM init OK\n");
        }
    }
    
    
    void check_data(void)
    {
        /* print PCM stream */
        while(!data_ready_flag){
            k_sleep(K_MSEC(1));
        }
    
        data_ready_flag = false;
    
        for(int i = 0; i < PDM_BUFFER_SIZE; i++) {
                printk("%x ", p_buffer[i]);
    
            }
            printk("\n");
    
       // printk("PINRT DATA\n");
    }
    
    nrfx_i2s_buffers_t i2s_buffers;
    
    int main(void) {
    
    	// Initialize PDM
    	pdm_init();
    
    	
    	// Start PDM and I2S
    	 nrfx_err_t err = nrfx_pdm_start();
    	 if(err != NRFX_SUCCESS){
    	 printk("PDM start error: %d\n", err);
    	 }
         else{
    	 	printk("PDM start OK\n");
    	 }
    
    		while (1) {
    			// Your application logic here
    			check_data();
    			k_msleep(2);
    		}
    }

Children
No Data
Related