NRF54L15 ADC sampling gets stuck inside adc_read

Hi Dev,

Development platform: NRF54L15 + NCS 3.2.3

We are facing an issue with ADC sampling. The code occasionally gets stuck/hangs inside the adc_read function. This issue does not occur every time — it happens sporadically after long-term operation or under certain unknown conditions.

I have already narrowed down the issue and confirmed that the hang occurs inside adc_read.

Here is the code snippet:

c
int adc_single_channel_poll(uint8_t chan)
{
    if (chan >= ADC_CH_COUNT) return -EINVAL;

    int16_t             local_sample = 0;
    struct adc_sequence seq          = {
                 .channels    = BIT(channel_cfgs[chan].channel_id),
                 .buffer      = &local_sample,
                 .buffer_size = sizeof(local_sample),
                 .resolution  = 12,
    };

    int err = adc_read(adc_dev, &seq);

    if (likely(err == 0))
    {
        adc_raw[chan] = (local_sample < 0) ? 0 : local_sample;
    }

    return err;
}

The execution gets stuck at adc_read() and never returns.

Could you please help clarify:

  1. Is this a driver-layer bug in the ADC driver provided with NCS 3.2.3?

  2. Or could it be a hardware issue with the NRF54L15 device itself?

  3. Are there any known issues or errata related to ADC on NRF54L15 that could cause occasional hangs in adc_read?

Any suggestions on how to further debug or work around this issue would be greatly appreciated.

Thanks,
Chen

Parents
  • Hi there,

    I also have this issue in one of our companies projects (nRF54L15, NCS 3.2.1) - I suspected everything else and even some errors because I was making adc-measurements from different threads, but when I removed the last call to adc_read it finally worked.

    It happens during an active cycle in my firmware where I measure in an interval of 1ms for about 400ms (so 400 measurements).

    Here is the channel configuration:

    &adc {
    	status = "okay";
    	#address-cells = <1>;
    	#size-cells = <0>;
        zephyr,pm-device-runtime-auto;
    
    	// supply voltage
    	channel@0 {
    		reg = <0>;
    		zephyr,gain = "ADC_GAIN_2_5";
    		zephyr,reference = "ADC_REF_INTERNAL";
    		zephyr,acquisition-time = <ADC_ACQ_TIME(ADC_ACQ_TIME_MICROSECONDS, 40)>;
    		zephyr,input-positive = <NRF_SAADC_AIN7>;
            zephyr,resolution = <12>;
        };
    
        // motor current
        channel@1 {
    		reg = <1>;
    		zephyr,gain = "ADC_GAIN_1";
    		zephyr,reference = "ADC_REF_INTERNAL";
    		zephyr,acquisition-time = <ADC_ACQ_TIME(ADC_ACQ_TIME_MICROSECONDS, 5)>;
    		zephyr,input-positive = <NRF_SAADC_AIN5>;
            zephyr,resolution = <12>;
        };
    
    };
    

    Now I have a workaround applied, which changes the mentioned ADC_CONTEXT_WAIT_FOR_COMPLETION_TIMEOUT to K_MSEC(10) through a definition in CMakeLists.txt of my project. Then I am handling the timeout by recovering with the following function:

    static void adc_recover(void)
    {
        LOG_WRN("SAADC hung — recovering");
    
        /* Abort + disable IRQ: prevents a late SAADC ISR from giving ctx->sync. */
        nrfx_saadc_uninit();
    
        /* Small delay to let any in-flight peripheral activity settle. */
        k_busy_wait(500);
    
        /* Re-init nrfx driver (restores m_cb state to IDLE, re-enables IRQ). */
        int err = nrfx_saadc_init(0);
        if (err != 0) {
            LOG_ERR("nrfx_saadc_init failed: %d", err);
            return;
        }
    
        /* Re-configure channels so the Zephyr driver sets up nrfx simple mode
         * and restores the channel bitmask. */
        for (size_t i = 0; i < CHANNEL_COUNT; i++) {
            err = adc_channel_setup_dt(&m_adc_channels[i]);
            if (err < 0) {
                LOG_ERR("adc_channel_setup_dt[%zu] failed: %d", i, err);
            }
        }
    }

    So at least now I can continue, but it leaves a bad feeling for now. Is this an issue, where either the measurement is not correctly started or is it an issue with the interrupt not firing?

Reply
  • Hi there,

    I also have this issue in one of our companies projects (nRF54L15, NCS 3.2.1) - I suspected everything else and even some errors because I was making adc-measurements from different threads, but when I removed the last call to adc_read it finally worked.

    It happens during an active cycle in my firmware where I measure in an interval of 1ms for about 400ms (so 400 measurements).

    Here is the channel configuration:

    &adc {
    	status = "okay";
    	#address-cells = <1>;
    	#size-cells = <0>;
        zephyr,pm-device-runtime-auto;
    
    	// supply voltage
    	channel@0 {
    		reg = <0>;
    		zephyr,gain = "ADC_GAIN_2_5";
    		zephyr,reference = "ADC_REF_INTERNAL";
    		zephyr,acquisition-time = <ADC_ACQ_TIME(ADC_ACQ_TIME_MICROSECONDS, 40)>;
    		zephyr,input-positive = <NRF_SAADC_AIN7>;
            zephyr,resolution = <12>;
        };
    
        // motor current
        channel@1 {
    		reg = <1>;
    		zephyr,gain = "ADC_GAIN_1";
    		zephyr,reference = "ADC_REF_INTERNAL";
    		zephyr,acquisition-time = <ADC_ACQ_TIME(ADC_ACQ_TIME_MICROSECONDS, 5)>;
    		zephyr,input-positive = <NRF_SAADC_AIN5>;
            zephyr,resolution = <12>;
        };
    
    };
    

    Now I have a workaround applied, which changes the mentioned ADC_CONTEXT_WAIT_FOR_COMPLETION_TIMEOUT to K_MSEC(10) through a definition in CMakeLists.txt of my project. Then I am handling the timeout by recovering with the following function:

    static void adc_recover(void)
    {
        LOG_WRN("SAADC hung — recovering");
    
        /* Abort + disable IRQ: prevents a late SAADC ISR from giving ctx->sync. */
        nrfx_saadc_uninit();
    
        /* Small delay to let any in-flight peripheral activity settle. */
        k_busy_wait(500);
    
        /* Re-init nrfx driver (restores m_cb state to IDLE, re-enables IRQ). */
        int err = nrfx_saadc_init(0);
        if (err != 0) {
            LOG_ERR("nrfx_saadc_init failed: %d", err);
            return;
        }
    
        /* Re-configure channels so the Zephyr driver sets up nrfx simple mode
         * and restores the channel bitmask. */
        for (size_t i = 0; i < CHANNEL_COUNT; i++) {
            err = adc_channel_setup_dt(&m_adc_channels[i]);
            if (err < 0) {
                LOG_ERR("adc_channel_setup_dt[%zu] failed: %d", i, err);
            }
        }
    }

    So at least now I can continue, but it leaves a bad feeling for now. Is this an issue, where either the measurement is not correctly started or is it an issue with the interrupt not firing?

Children
No Data
Related