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

nRF52840 SAADC Continuous sampling not started with TASK_START

When using the local timer of the SAADC it should be started with TASK_START according to https://infocenter.nordicsemi.com/topic/ps_nrf52840/saadc.html?cp=4_0_0_5_22_4#concept_continuous.

"The internal timer and the continuous sampling are started by triggering the START task and stopped using the STOP task."

However this doesn't work. TASK_SAMPLE is also required.

void SAADC_IRQHandler(void)
{
    if (nrf_saadc_event_check(NRF_SAADC_EVENT_END)) {
        nrf_saadc_event_clear(NRF_SAADC_EVENT_END);
        __LOG(LOG_SRC_APP, LOG_LEVEL_DBG1, "NRF_SAADC_EVENT_END\n");

    }

    if (nrf_saadc_event_check(NRF_SAADC_EVENT_STARTED)) {
        nrf_saadc_event_clear(NRF_SAADC_EVENT_STARTED);
        __LOG(LOG_SRC_APP, LOG_LEVEL_DBG1, "NRF_SAADC_EVENT_STARTED\n");
    }
}

void current_sensor_init(void) {
    nrf_saadc_resolution_set(NRF_SAADC_RESOLUTION_14BIT);
    nrf_saadc_oversample_set(NRF_SAADC_OVERSAMPLE_16X);
    nrf_saadc_continuous_mode_enable(16 * 16 * (2 + 3));

    nrf_saadc_int_disable(NRF_SAADC_INT_ALL);
    nrf_saadc_int_enable(NRF_SAADC_INT_END);
    nrf_saadc_int_enable(NRF_SAADC_INT_STARTED);
    nrf_saadc_event_clear(NRF_SAADC_EVENT_END);
    nrf_saadc_event_clear(NRF_SAADC_EVENT_STARTED);

    NRFX_IRQ_PRIORITY_SET(SAADC_IRQn, NRFX_SAADC_CONFIG_IRQ_PRIORITY);
    NRFX_IRQ_ENABLE(SAADC_IRQn);

    nrf_saadc_enable();

    nrf_saadc_channel_config_t config = {
            .resistor_p = NRF_SAADC_RESISTOR_DISABLED,
            .resistor_n = NRF_SAADC_RESISTOR_DISABLED,
            .gain       = NRF_SAADC_GAIN1_5,
            .reference  = NRF_SAADC_REFERENCE_INTERNAL,
            .acq_time   = NRF_SAADC_ACQTIME_3US,
            .mode       = NRF_SAADC_MODE_DIFFERENTIAL,
            .burst      = NRF_SAADC_BURST_ENABLED,
            .pin_p      = NRF_SAADC_INPUT_AIN3,
            .pin_n      = NRF_SAADC_INPUT_AIN4,
    };
    nrf_saadc_channel_init(0, &config);
    nrf_saadc_buffer_init(s_buf, 250);

    nrf_saadc_task_trigger(NRF_SAADC_TASK_START);
    //nrf_saadc_task_trigger(NRF_SAADC_TASK_SAMPLE);
}

In the above only NRF_SAADC_EVENT_STARTED is shown in the log.

If TASK_SAMPLE is triggered the NRF_SAADC_EVENT_END is also emitted to the log.

    nrf_ppi_channel_t ppi_saadc_end;

    APP_ERROR_CHECK(nrfx_ppi_channel_alloc(&ppi_saadc_end));
    APP_ERROR_CHECK(nrfx_ppi_channel_assign(
            ppi_saadc_end, nrf_saadc_event_address_get(NRF_SAADC_EVENT_END),
            nrf_saadc_task_address_get(NRF_SAADC_TASK_START)));
    nrf_ppi_channel_enable(ppi_saadc_end);

Connecting EVENT_END to TASK_START using PPI seem to be enough to keep the local timer running. But if TASK_CALIBRATEOFFSET is triggered after EVENT_END instead of TASK_START, TASK_SAMPLE is required to get the local timer to start sampling again.

I can't find anything related to this in the PS nor the Errata.

This was tested on the nRF52840-DK with an AAC0 variant. The same behavior was also seen on a nRF52833 AAA0 variant.

Thanks.

Parents
  • Hi Karl,

    Have you had a chance to look at the interrupt findings in the last post?

    Thanks.

  • Hello again,

    I am terribly sorry for the delay in answers for this ticket!
    I have been out of office for some time now, and I returned just this week.
    Somehow this ticket fell between the cracks.

    I will go through your previous comment and attached code tomorrow and I'll get back to you with an update by the end of day.

    I again apologize for the delay in answers to you here, thank you for your extreme patience!

    Best regards,
    Karl

  • Hello again,

    I've replicated the behavior you described with the main file you provided, and I do see what you mean by the behavior exhibited by the example not matching with what you would expect based on the documentation.

    I have asked to have a meeting with one of the SAADC developers to discuss and gain a better understanding of this, and what exactly is going on here. I will update you as soon as I have talked to him.

    Best regards,
    Karl

  • Hello again, JonasJ,

    Thanks again for the patience.

    I have now looked more closely at the project code that you supplied, and it seems to me that the SAADC is sampling perpetually (since the TASKS_STOP is never triggered), and the IRQ will therefore be called after each sample perpetually, which causes the CPU to spent most of its time in the IRQ handler, either doing simulated work or the artificial 20 ms delay.

    In essence; In the case that the 20 ms delay is present this means that the PC will never get to return to the main context, because the 20 ms delay is executed at every sampling, in perpetuity.
    In the case that the 20 ms delay is removed, and RESULTDONE + DONE events are enabled, the many interruptions of simulated 1 µs work in the IRQ incurred over 250 ms causes a significant(visible) delay on the toggling of the LEDs in the main context (because the CPU spends much of its time executing the IRQ delays, compared to the main context delay).

    I guess the main confusion around the behavior here was that the SAADC will keep sampling perpetually, since it is never explicitly stopped. I concur that this should be explicitly stated in the documentation.

    Please do not hesitate to let me know if any part of my explanation is unclear, or if you should have any follow-up questions to this! :) 

    Best regards,
    Karl

  • Thanks Karl,

    Your explanation make sense. It should perhaps be noted that TASK_CALIBRATEOFFSET also cause the internal timer to stop.

Reply Children
  • JonasJ said:
    Your explanation make sense.

    Great, I am happy to hear that!

    I must again apologize for the huge delay in answers to this case from April until now, I have no idea how it slipped off the radar.
    If this should ever happen again here on DevZone, please do not hesitate to prompt us for an update. 

    JonasJ said:
    It should perhaps be noted that TASK_CALIBRATEOFFSET also cause the internal timer to stop.

    Yes, I will note that the entire continuous mode section of the documentation should be reviewed. It seems to be quite light at the moment.
    Thank you for bringing this to our attention! :)

    Please do not hesitate to open another ticket if you should encounter any issues or questions in the future!

    Best regards,
    Karl

Related