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

  • Has this or have you found a fix for this issue? I'm also experiencing the same problems, of doing an ADC read seems to hang. This is randomly, as I do an ADC read every 4 seconds. 

    I've left my device running over night, and the same thing has happened.

    I'm using SDK 3.1.1, with the nRF5340

  • Thanks @hmolesworth for the detailed analysis on SAADC transfer details. The difference you pointed out — nRF54L15 using byte count while nRF52840 uses 16‑bit word count — is indeed an important hardware change worth noting.

    However, the issue I'm facing is that adc_read() occasionally hangs completely and never returns, rather than a data length misconfiguration causing corrupted samples. I've already checked buffer size and alignment, but the problem still occurs randomly.

    Also thanks @jerome.sc for the feedback. Seeing that you're experiencing the same hang on nRF5340 with SDK 3.1.1 makes me more inclined to think this might not be nRF54L15‑specific, but rather a potential issue in the Zephyr ADC driver or the SAADC hardware state machine locking up under certain conditions.

    As of now, I still haven't found the root cause and am waiting for further response from Nordic official support. My current temporary workaround is to monitor the ADC hang and trigger a watchdog software reset.

    If you have any further debugging progress (e.g., checking register states to identify where it gets stuck), please do share.

  • @ I've switched from Zephyr API ADC to the nrfx drivers. It's hard to say if this has fixed anything, but I've ran my device for 3 hours without it crashing.

    I haven't done low level debugging, but if it does crash again, then I will have to.

    Unlike you, if the ADC hangs I can't do a software reset, as this will defeat the purpose of my application.

    Hopefully the Nordic team returns with a solution.

    If you do find a fix, please post it on here, as I'm often checking for updates on this thread.

  • 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?

  • Sorry for late reply


    For the hang, what we know for sure is only that the ADC completion is never delivered, so adc_read() waits forever. There are three possible reasons that i can think of and the SAADC registers at the moment it hangs will tell us which:

    1. conversion never completed (EVENTS_END = 0), or
    2. it completed but was not serviced (EVENTS_END = 1).
    3. the interrupt was serviced and the event cleared, but a race in how the driver handles the event/state flags dropped the completion.

    Can you please capture EVENTS_END, EVENTS_STARTED, STATUS, INTENSET and RESULT.AMOUNT at the point it hangs? That will confirm which case it is.

    As a workaround, your approach is correct: set a finite ADC_CONTEXT_WAIT_FOR_COMPLETION_TIMEOUT so adc_read() returns an error instead of hanging, and reinit the peripheral on that path (the driver does not clean it up on timeout).

    Once we know what happened here, we can try to see if this is a driver issue or something else.

Related