Using PDM microphone on nrf5340

I am developing a board with the nrf5340, and using a PDM microphone for audio input.

I have used the same microphone on the nrf52832 with the nrf PDM driver with success.

However, on the nrf5340 under Zephyr, I get the following error as soon as I start the PDM recording:

[00:00:33.402,099] <inf> base: pdmmgr : rec start turning power on
[00:00:33.409,240] <inf> base: pdmmgr : rec start configuring pinctrl
[00:00:33.416,137] <inf> base: pdmmgr : rec start enabling irq
[00:00:33.422,424] <inf> base: pdmmgr : rec start nrfx_pdm_init()
[00:00:33.428,985] <inf> base: pdmmgr : rec start nrfx_pdm_start()
[00:00:33.481,323] <err> os: >>> ZEPHYR FATAL ERROR 1: Unhandled interrupt on CPU 0
[00:00:33.489,624] <err> os: Current thread: 0x200052c8 (main)
[00:00:33.496,124] <err> os: Halting system


This occurs when I call nrfx_pdm_start()...

My code:

    log_info("pdmmgr : rec start turning power on");
    // turn on the mic power
    gpiomgr_write(ctx->pin_pdm_en, 1);
    ctx->rec_cb = cb_fn;

    // microphone config : only 1 hw configured as L, so mono left channel (clock on rising edge)
    nrfx_pdm_config_t config1 = {
        .mode               = NRF_PDM_MODE_MONO,
        .edge               = NRF_PDM_EDGE_LEFTRISING,
        .clock_freq         = NRF_PDM_FREQ_1032K,
        .gain_l             = NRF_PDM_GAIN_MAXIMUM,
        .gain_r             = NRF_PDM_GAIN_MAXIMUM,
        .interrupt_priority = NRFX_PDM_DEFAULT_CONFIG_IRQ_PRIORITY,
        .skip_gpio_cfg      = true,            /* use DTS via pinctrl_apply_state() */
        .skip_psel_cfg      = true
    };
//    config1.clk_pin = gpiomgr_get_pin(ctx->pin_sck);
//    config1.din_pin = gpiomgr_get_pin(ctx->pin_sdio);
    log_info("pdmmgr : rec start configuring pinctrl");
    uint32_t errcode = pinctrl_apply_state(PINCTRL_DT_DEV_CONFIG_GET(PDM_NL), PINCTRL_STATE_DEFAULT);
    if (errcode!=0) {
        log_warn("pdmmgr : PDM pin setup from DTS fails, errcode %d",errcode);
        return false;
    }

    log_info("pdmmgr : rec start enabling irq");
    irq_enable(DT_IRQN(PDM_NL));

    log_info("pdmmgr : rec start nrfx_pdm_init()");
    errcode = nrfx_pdm_init(&config1, _drv_pdm_handler);
    if (errcode!=NRFX_SUCCESS) {
        log_warn("pdmmgr: error %d trying to init pdm record",errcode);
        gpiomgr_write(ctx->pin_pdm_en, 0);
        return false;
    }
    ctx->audio_rec_buf = data;
    ctx->audio_rec_buf_sz = dlen;
    ctx->voice_detected = false;   // no voice detected
    ctx->rec_active_buffer = 0;       // no active buffer yet (unlike play, driver will immediately call the handler cb to get 1st buffer)
    ctx->rec_data_nsamples = 0;     // no data yet
    log_info("pdmmgr : rec start nrfx_pdm_start()");
    errcode = nrfx_pdm_start();
    if (errcode!=NRFX_SUCCESS) {
        log_warn("pdmmgr: error %d trying to start pdm record",errcode);
        nrfx_pdm_uninit();
        gpiomgr_write(ctx->pin_pdm_en, 0);
        return false;
    }

What am I not initialising correctly?

Parents
  • Hello,

    I am sorry for the late reply!

    It looks like you are not forwarding the interrupt to your driver. 

    Please open VS Code in your NCS directory, and search for "IRQ_CONNECT(NRFX_IRQ_NUMBER_GET(", and you will see a lot of examples that are doing this. Unfortunately, not for the PDM, but a lot of other peripherals, such as UART:

    #if defined(__ZEPHYR__)
        IRQ_CONNECT(NRFX_IRQ_NUMBER_GET(NRF_UARTE_INST_GET(UARTE_INST_IDX)), IRQ_PRIO_LOWEST,
                    NRFX_UARTE_INST_HANDLER_GET(UARTE_INST_IDX), 0, 0);
    #endif

    The error that you are seeing is that you are setting up your PDM, and enabling interrupts, and then an interrupt occurs, but the application doesn't know where to send it. 

    I am not really sure whether the PDM has these macros t point to it's base, but if you are building for the nRF5340, the NRF_PDM0_S_BASE is found in nrf5340_application.h file, and is either 0x50026000, or 0x40026000 if you are building for nrf5340dk_nrf5340_cpuapp_ns.

    Then make it point to your _drv_pdm_handler().

    Best regards,

    Edvin

Reply
  • Hello,

    I am sorry for the late reply!

    It looks like you are not forwarding the interrupt to your driver. 

    Please open VS Code in your NCS directory, and search for "IRQ_CONNECT(NRFX_IRQ_NUMBER_GET(", and you will see a lot of examples that are doing this. Unfortunately, not for the PDM, but a lot of other peripherals, such as UART:

    #if defined(__ZEPHYR__)
        IRQ_CONNECT(NRFX_IRQ_NUMBER_GET(NRF_UARTE_INST_GET(UARTE_INST_IDX)), IRQ_PRIO_LOWEST,
                    NRFX_UARTE_INST_HANDLER_GET(UARTE_INST_IDX), 0, 0);
    #endif

    The error that you are seeing is that you are setting up your PDM, and enabling interrupts, and then an interrupt occurs, but the application doesn't know where to send it. 

    I am not really sure whether the PDM has these macros t point to it's base, but if you are building for the nRF5340, the NRF_PDM0_S_BASE is found in nrf5340_application.h file, and is either 0x50026000, or 0x40026000 if you are building for nrf5340dk_nrf5340_cpuapp_ns.

    Then make it point to your _drv_pdm_handler().

    Best regards,

    Edvin

Children
No Data
Related