This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

PDM code implementation and testing

static void bsp_event_handler(bsp_event_t event)
{
    ret_code_t err_code;

    switch (event)
    {
        case BSP_EVENT_SLEEP:
            sleep_mode_enter();
            break; // BSP_EVENT_SLEEP

        case BSP_EVENT_DISCONNECT:
            err_code = sd_ble_gap_disconnect(m_conn_handle,
                                             BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
            if (err_code != NRF_ERROR_INVALID_STATE)
            {
                APP_ERROR_CHECK(err_code);
            }
            break; // BSP_EVENT_DISCONNECT

        case BSP_EVENT_WHITELIST_OFF:
            if (m_conn_handle == BLE_CONN_HANDLE_INVALID)
            {
                err_code = ble_advertising_restart_without_whitelist(&m_advertising);
                if (err_code != NRF_ERROR_INVALID_STATE)
                {
                    APP_ERROR_CHECK(err_code);
                }
            }
            break; // BSP_EVENT_KEY_0
          case BSP_EVENT_KEY_1:
            NRF_LOG_INFO("\n Press Button key 1\n");
            NRF_LOG_INFO("\n Erase the flash content !!\n");
//            err_code = pcm_pstorage_eraseall();
//            APP_ERROR_CHECK(err_code);
            break;

         case BSP_EVENT_KEY_2:
            NRF_LOG_INFO("\n Start:PDM --> PCM\n");
            err_code =  nrf_drv_pdm_start(); 
            APP_ERROR_CHECK(err_code);
            break;

         case BSP_EVENT_KEY_3:
            NRF_LOG_INFO("\n Stop:PDM --> PCM\n");
            // stop audio sample
            nrf_drv_pdm_stop();
            break;

        default:
            break;
    }
}









static void drv_audio_pdm_event_handler(uint32_t *p_buffer, uint16_t length)
{
	m_buffer_handler((int16_t *)p_buffer, length);
        int i;
//        for(i=0;i<= length;i++)
//        {
//          NRF_LOG_INFO("%s ",&p_buffer[i]);
//        }
//        NRF_LOG_INFO("\n ");
          NRF_LOG_INFO("pdm event handler \n");

}


uint32_t drv_audio_init(drv_audio_buffer_handler_t buffer_handler)
{
//    nrf_drv_pdm_config_t pdm_cfg = NRF_DRV_PDM_DEFAULT_CONFIG(CONFIG_IO_PDM_CLK,
//                                                              CONFIG_IO_PDM_DATA,
//                                                              m_pdm_buff[0],
//                                                              m_pdm_buff[1],
//                                                              CONFIG_PDM_BUFFER_SIZE_SAMPLES);
    nrf_drv_pdm_config_t pdm_cfg = NRF_DRV_PDM_DEFAULT_CONFIG(CONFIG_IO_PDM_CLK,CONFIG_IO_PDM_DATA);
    
    if (buffer_handler == NULL)
    {
        return NRF_ERROR_INVALID_PARAM;
    }
    
    m_buffer_handler    = buffer_handler;
    pdm_cfg.gain_l      = CONFIG_PDM_GAIN;
    pdm_cfg.gain_r      = CONFIG_PDM_GAIN;
    

    return nrf_drv_pdm_init(&pdm_cfg, drv_audio_pdm_event_handler);
}










int main(void)
{
    bool erase_bonds;

    // Initialize.
    log_init();
    timers_init();
    buttons_leds_init(&erase_bonds);
    power_management_init();
    ble_stack_init();
    gap_params_init();
    gatt_init();
    advertising_init();
    services_init();
    conn_params_init();
    peer_manager_init();

    // Start execution.
    NRF_LOG_INFO("Template example started.");
    application_timers_start();

//    advertising_start(erase_bonds);
    uint32_t err_code;
    err_code = drv_audio_init(drv_audio_pdm_event_handler);
    APP_ERROR_CHECK(err_code);
    
    // Enter main loop.
    for (;;)
    {
        idle_state_handle();
    }
}

I have to connect a MIC  working on PDM to nrf52 DK Board.For that, I have written the above code.  But when I am testing I am not able to get the clock pulses at the defined pin. Also do not know at which Freq it is working?

And when I read the pdm documentation it says I need to change the PSEL.CLK register value? Then how should I do it and with what value? same for PSEL.DIN register. I am confused a lot. Please suggest me the solution to all my doubts.I have checked the clk pin on Oscilloscope, the clock is not being generated.In order to generate clk at pin number 22 of nrf52 DK board should I define pin clk  as #define CONFIG_IO_PDM_CLK 0x22 or 0x16 (hex value of 22 )instead o rtf 0x22?

Parents Reply Children
  • Hello Haakonsh, I got the pdm clock but now how should I print the PDM data on terminal using easyDMA?

  • Once a set of samples are taken they have already been transferred to RAM via EasyDMA. If you want to send this over UART to a terminal you need to start a UARTE transfer where the TX buffer pointer points to the PDM buffer. 

    See UARTE driver API docs:

    nrfx_uarte uarte0 = NRFX_UARTE_INSTANCE(0);
    
    void uarte_handler(nrfx_uarte_evt_type_t evt)
    {
        //Handle uarte events if needed
    }
    
    void uarte_init(void)
    {
        nrfx_err_t err_code = NRFX_SUCCESS;
        nrfx_uarte_config_t uarte_cfg = NRFX_UARTE_DEFAULT_CONFIG; //Set config in sd_config.h
        
        err_code = nrfx_uarte_init(&uarte0, &uarte_cfg, uarte_handler);
        APP_ERROR_CHECK(err_code);
    }
    
    // In PDM handler, call: nrfx_uarte_tx(&uarte0, &YourPDMbuffer, LenghtOfPDMbuffer)



  • Thanks, But when I call uarte_init(); in main the system resets 

  • Is there any other way how can I get the EasyDMA data or PDM data ?

  • For your reference,

    static int16_t                      input_pdm_buff[2][CONFIG_PDM_BUFFER_SIZE_SAMPLES];
    //volatile drv_audio_frame_t       m_audio_frame[CONFIG_AUDIO_FRAME_BUFFERS];
    
    static int32_t                      *output_pdm_buff;
    static drv_audio_buffer_handler_t   m_buffer_handler;
    //uint16_t			m_frame_index = 0;
    //uint16_t                        m_next_frame_index = 0;
    static app_sched_event_handler_t        m_audio_frame_handler = NULL;
    
    
    const uint8_t leds_list[LEDS_NUMBER] = LEDS_LIST;
    
    
    //void UARTE0_UART0_IRQHandler(){
    //
    //    if(NRF_UARTE0->EVENTS_ENDRX){
    //        LEDS_INVERT(1 << leds_list[3]);
    //    }
    //
    //}
    
    
    
    
    /**@brief   Function for handling app_uart events.
     *
     * @details This function will receive a single character from the app_uart module and append it to
     *          a string. The string will be be sent over BLE when the last character received was a
     *          'new line' '\n' (hex 0x0A) or if the string has reached the maximum data length.
     */
    /**@snippet [Handling the data received over UART] */
    void uart_event_handle(app_uart_evt_t * p_event)
    {
        static uint8_t data_array[CONFIG_PDM_BUFFER_SIZE_SAMPLES];
        static uint8_t index = 0;
        uint32_t       err_code;
    
        switch (p_event->evt_type)
        {
            case APP_UART_DATA_READY:
                UNUSED_VARIABLE(app_uart_get(&data_array[index]));
                index++;
    
                if ((data_array[index - 1] == '\n') ||
                    (data_array[index - 1] == '\r') ||
                    (index >= CONFIG_PDM_BUFFER_SIZE_SAMPLES))
                {
                    if (index > 1)
                    {
                        NRF_LOG_DEBUG("Ready to send data over BLE NUS");
                        NRF_LOG_HEXDUMP_DEBUG(data_array, index);
    
    //                    do
    //                    {
    //                        uint16_t length = (uint16_t)index;
    //                        err_code = ble_nus_data_send(&m_nus, data_array, &length, m_conn_handle);
    //                        if ((err_code != NRF_ERROR_INVALID_STATE) &&
    //                            (err_code != NRF_ERROR_RESOURCES) &&
    //                            (err_code != NRF_ERROR_NOT_FOUND))
    //                        {
    //                            APP_ERROR_CHECK(err_code);
    //                        }
    //                    } while (err_code == NRF_ERROR_RESOURCES);
                    }
    
                    index = 0;
                }
                break;
    
            case APP_UART_COMMUNICATION_ERROR:
                APP_ERROR_HANDLER(p_event->data.error_communication);
                break;
    
            case APP_UART_FIFO_ERROR:
                APP_ERROR_HANDLER(p_event->data.error_code);
                break;
    
            default:
                break;
        }
    }
    /**@snippet [Handling the data received over UART] */
    
    
    
    /**@brief  Function for initializing the UART module.
     */
    /**@snippet [UART Initialization] */
    //nrfx_uarte uarte0 = NRFX_UARTE_INSTANCE(0);
    
    nrfx_uarte_t uarte0 = NRFX_UARTE_INSTANCE(0);
    void uarte_handler(nrfx_uarte_evt_type_t evt)
    {
        //Handle uarte events if needed
    }
    
    void uarte_init(void)
    {
        nrfx_err_t err_code = NRFX_SUCCESS;
        nrfx_uarte_config_t uarte_cfg = NRFX_UARTE_DEFAULT_CONFIG; //Set config in sd_config.h
        
    //    err_code = nrfx_uarte_init(&uarte0, &uarte_cfg, uarte_handler);
    //    APP_ERROR_CHECK(err_code);
      
    //    uint8_t txBuffer[20];
    //    uint8_t rxBuffer[20];
    //    
    //    memset(txBuffer,'A',sizeof(txBuffer));
    //
        NRF_UARTE0->BAUDRATE = NRF_UARTE_BAUDRATE_115200;
        NRF_UARTE0->PSEL.TXD = TX_PIN_NUMBER;
        NRF_UARTE0->PSEL.RXD = RX_PIN_NUMBER;
        NRF_UARTE0->CONFIG = NRF_UARTE_HWFC_DISABLED;
        NRF_UARTE0->ENABLE = (UARTE_ENABLE_ENABLE_Enabled << UARTE_ENABLE_ENABLE_Pos);
    
    //    NRF_UARTE0->TXD.PTR = (uint32_t)((uint8_t *) txBuffer);
    //    NRF_UARTE0->TXD.MAXCNT = sizeof(txBuffer);
    //    NRF_UARTE0->TASKS_STARTTX = 0;
    //
    //    NRF_UARTE0->RXD.PTR = (uint32_t)((uint8_t *) rxBuffer);
    //    NRF_UARTE0->RXD.MAXCNT = sizeof(rxBuffer);
    //    NRF_UARTE0->TASKS_STARTRX = 1;
    //    NRF_UARTE0->TASKS_STARTTX = 1;
    
    
        NRF_UARTE0->INTENCLR = 0xFFFFFFFF;
        NRF_UARTE0->INTENSET = NRF_UARTE_INT_ENDRX_MASK;
    
        NVIC_ClearPendingIRQ(UARTE0_UART0_IRQn);
        NVIC_SetPriority(UARTE0_UART0_IRQn, 1);
        NVIC_EnableIRQ(UARTE0_UART0_IRQn);
    //
    //
    //    LEDS_CONFIGURE(LEDS_MASK);
    //    LEDS_OFF(LEDS_MASK);
    //    if(NRF_UARTE0->EVENTS_RXSTARTED){
    //        LEDS_INVERT(1 << leds_list[1]);
    //    }
    
    
    
    }
    
    
    /**@brief Function for initializing the nrf log module.
     */
    static void log_init(void)
    {
        ret_code_t err_code = NRF_LOG_INIT(NULL);
        APP_ERROR_CHECK(err_code);
    
        NRF_LOG_DEFAULT_BACKENDS_INIT();
    }
    
    
    
    
    //static void nrf52_pdm_irq(void)
    //{
    //    // Simply pass on to the driver component handler.
    ////    if (nrf52_pdm_driver)
    ////        nrf52_pdm_driver->irq();
    //      irq();
    //}
    
    /**
     * Constructor for an instance of a PDM input (typically microphone),
     *
     * @param sd The pin the PDM data input is connected to.
     * @param sck The pin the PDM clock is conected to.
     * @param sampleRate the rate at which samples are generated in the output buffer (in Hz)
     * @param id The id to use for the message bus when transmitting events.
     */
    //                
    
    
    #define BUFFER_SIZE  64
    
      typedef struct ArrayList
      {
        uint8_t buffer[BUFFER_SIZE];
      } ArrayList_type;
    
     
    
    
    void startDMA()
    {
    
    //    ArrayList_type ReaderList[63];
    //      uint32_t i;
    ////    PDMREADER.MAXCNT = BUFFER_SIZE;
    ////    READER.PTR = &ReaderList;
    ////    PDM_SAMPLE_PTR_SAMPLEPTR_Pos 
    //    NRF_PDM->SAMPLE.MAXCNT = BUFFER_SIZE;
    //    NRF_PDM->SAMPLE.PTR = &ReaderList;
    //    for(i=0;i<BUFFER_SIZE;i++)
    //   {
    //      NRF_LOG_INFO("ReaderList[%d] = %d ",i,ReaderList->buffer[i]);
    //
    //   }
    
    //    uint32_t err_code;
    //    err_code = drv_audio_init(m_audio_handler);
    //    APP_ERROR_CHECK(err_code);
    
    
    //    output_pdm_buff = &input_pdm_buff[0];
        uint32_t i;
        NRF_LOG_INFO("startDMA   \n");
    //
    //   
       NRF_PDM->SAMPLE.PTR = (uint32_t)&input_pdm_buff[0];
    //   NRF_LOG_INFO("NRF_PDM->SAMPLE.PTR   =  %x ",NRF_PDM->SAMPLE.PTR );
       memcpy(output_pdm_buff, &input_pdm_buff[0],CONFIG_PDM_BUFFER_SIZE_SAMPLES);
       
    //     for(i=0;i<CONFIG_PDM_BUFFER_SIZE_SAMPLES;i++)
    //     {
    //      NRF_LOG_INFO("m_audio_frame->buffer[%d] = %d ",i,output_pdm_buff[i]);
    //
    //
    //     }
    
    
    
    //     drv_audio_frame_t *p_frame;
    //     app_sched_event_put(&p_frame, sizeof(drv_audio_frame_t *), m_audio_frame_handler);
    //    NRF_PDM->SAMPLE.PTR = (uint32_t)&m_audio_frame[0];
    //     memcpy(&(m_audio_frame->buffer), p_frame,CONFIG_AUDIO_FRAME_SIZE_BYTES);
    //     uint32_t i;
    //     for(i=0;i<CONFIG_AUDIO_FRAME_SIZE_BYTES;i++)
    //     {
    //      NRF_LOG_INFO("m_audio_frame->buffer[%d] = %d ",i,m_audio_frame->buffer[i]);
    //
    //
    //     }
    
    
    }
    //
    //
    ///**
    // * Enable this component
    // */
    void pdm_enable()
    {
        if (!enabled)
        {
            enabled = true;
    
            NRF_PDM->ENABLE = 1;
    
    //        pdm_start();
    //        startDMA();
    
            NRF_PDM->TASKS_START = 1;
        }
    }
    
    /**
     * Disable this component
     */
    void pdm_disable()
    {
        // Schedule all DMA transfers to stop after the next DMA transaction completes.
        enabled = false;
        NRF_PDM->ENABLE = 0;
    }
    
    
    void PDM_IRQHandler()
    {
       
        if (NRF_PDM->EVENTS_STARTED) 
        {
            // We've just started receiving data the inputBuffer.
            // So we don't miss any data, line up the next buffer.
            // (unless we've been asked to stop).
    //        m_xfer_done = true;
            nrfx_uarte_tx(&uarte0, &input_pdm_buff, CONFIG_AUDIO_FRAME_SIZE_BYTES);
            
              
            if (enabled)
    
            startDMA();
    
            NRF_PDM->EVENTS_STARTED = 0;
        }
    
        if (NRF_PDM->EVENTS_END)
        {
    //        if (outputBuffer.length() > 0)
    //            output.pullRequest();
    
            NRF_PDM->EVENTS_END = 0;
        }
    
        if (NRF_PDM->EVENTS_STOPPED)
            NRF_PDM->EVENTS_STOPPED = 0;
    
        // Erratum.
        // JF: Not sure what this is working around? Seems harmless, so leaving it in for now...
        (void) NRF_PDM->EVENTS_STOPPED;
    
    
    
    
        
    }
    
    
    
    
    void pdm_init()
    {
       
        // Define our output stream as non-bocking.
    //    output.setBlocking(false);
    
       
        pdm_disable();
      
        nrf_gpio_cfg_output(CONFIG_IO_PDM_CLK);
        nrf_gpio_cfg_input(CONFIG_IO_PDM_DATA,NRF_GPIO_PIN_NOPULL);
    
        // Map the PDM peripheral onto the given pins...
        NRF_PDM->PSEL.CLK = CONFIG_IO_PDM_CLK;
    //    pdm_cfg.edge = NRF_PDM_EDGE_LEFTRISING;
    //   nrf_pdm_mode_set(nrf_pdm_mode_t pdm_mode, nrf_pdm_edge_t pdm_edge)
    
         NRF_PDM->MODE = ((PDM_CONFIG_MODE << PDM_MODE_OPERATION_Pos) & PDM_MODE_OPERATION_Msk)
                        | ((NRF_PDM_EDGE_LEFTRISING << PDM_MODE_EDGE_Pos) & PDM_MODE_EDGE_Msk);
    
    
        NRF_PDM->PSEL.DIN = CONFIG_IO_PDM_DATA;
    
        // Configure for DMA enabled, single channel PDM input.
    //  NVIC_SetVector(PDM_IRQn, (uint32_t )nrf52_pdm_irq);
    
        /* Set up interrupts */
        NRF_PDM->INTENSET = (PDM_INTENSET_STARTED_Enabled << PDM_INTENSET_STARTED_Pos) |
            (PDM_INTENSET_END_Enabled << PDM_INTENSET_END_Pos ) |
            (PDM_INTENSET_STOPPED_Enabled << PDM_INTENSET_STOPPED_Pos);
    
        NVIC_SetPriority( PDM_IRQn, 1);
        NVIC_ClearPendingIRQ( PDM_IRQn );
        NVIC_EnableIRQ( PDM_IRQn );
    
    
        // Configure for a 1.032MHz PDM clock.
        NRF_PDM->PDMCLKCTRL = (PDM_PDMCLKCTRL_FREQ_Default << PDM_PDMCLKCTRL_FREQ_Pos );
    
        // Mono operation.
        NRF_PDM->MODE = ( PDM_MODE_EDGE_LeftRising  << PDM_MODE_EDGE_Pos ) |
            (PDM_MODE_OPERATION_Mono << PDM_MODE_OPERATION_Pos);
    
        // Set default gain of 0dbm.
        NRF_PDM->GAINL = CONFIG_AUDIO_PDM_GAIN;
        NRF_PDM->GAINR = CONFIG_AUDIO_PDM_GAIN;
    
    
        // Configure buffer size.
       
        NRF_PDM->SAMPLE.PTR = &input_pdm_buff[0];
        NRF_PDM->SAMPLE.MAXCNT = CONFIG_PDM_BUFFER_SIZE_SAMPLES;
        pdm_enable();
    
        // Record our sample rate for future computation.
        // This is a constant of the PDM samplerate / 64 (as defined in nrf52 specification, seciton 44).
        // For the configuration above, this translates to approx 16kHz.
    //    this->sampleRate = 1032000 / 64;
    }
    
    
    
       
    
    
    
    
    /**
     * Initiate a DMA transfer into the raw data buffer.
     */
    
    static void idle_state_handle(void)
    {
        if (NRF_LOG_PROCESS() == false)
        {
            nrf_pwr_mgmt_run();
        }
    }
    
    
    /**@brief Function for application main entry.
     */
    int main(void)
    {
       // Start execution.
    
     
        log_init();
    //
    
        uarte_init();
    //      uart_init();
    
        NRF_LOG_INFO("Template example started.");
        pdm_init();
        
    
    for (;;)
        {
            idle_state_handle();
        }
      
    }
    
    
    0456.sdk_config.h I am attaching my code and sdk_config.h file.

Related