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 ,

    I see now that this is missing from both the API reference for the nrf_saadc_continuous_mode_enable function documentation, and the SAADC peripheral continuous mode documentation.
    I have made an internal ticket to our technical writers to have this reviewed. Thank you for bringing this up!

    Thanks for confirming this. I haven't checked but I guess the same issue applies to all nRF52 devices PS.

    Are you saying that you need to keep calling TASK_START after every EVENT_END? That does not sound right to me.

    Yes. Otherwise I only get one EVENT_END. Is it so that the internal timer keep emitting TASK_SAMPLE and they are ignored until a TASK_START is triggered again?

    Are you getting the EVENT_STOPPED following a EVENT_END?

    No.

    If you here mean to say that you are working with an Engineering Version A variant of the nRF52840 SoC (DK version 0.9.x) then I highly recommend that you update your hardware to a non-engineering variant for future development.

    According to the sticker, it's version 1.0.0 from 2018.46. The AAC0 was found by reading the INFO.VARIANT register which returned 0x41414330.

    While testing for EVENT_STOPPED I discovered one additional issue. Enabling the EVENT_DONE and EVENT_RESULTDONE interrupts causes something to misbehave in a way that prevents it returning control to thread context.

        nrf_saadc_event_clear(NRF_SAADC_EVENT_RESULTDONE);
        nrf_saadc_event_clear(NRF_SAADC_EVENT_DONE);
        nrf_saadc_int_enable(NRF_SAADC_INT_RESULTDONE);
        nrf_saadc_int_enable(NRF_SAADC_INT_DONE);

    This seem to only happen when nrf_saadc_task_trigger(NRF_SAADC_TASK_SAMPLE) is called. I get this behavior regardless of continuous mode or burst enabled/disabled.

    The call was made directly after TASK_START, i.e., line 46 in the original post. It didn't matter to wait for EVENT_STARTED before calling TASK_SAMPLE or calling it from the interrupt handler on EVENT_STARTED.

    Thanks.

Reply
  • Hi ,

    I see now that this is missing from both the API reference for the nrf_saadc_continuous_mode_enable function documentation, and the SAADC peripheral continuous mode documentation.
    I have made an internal ticket to our technical writers to have this reviewed. Thank you for bringing this up!

    Thanks for confirming this. I haven't checked but I guess the same issue applies to all nRF52 devices PS.

    Are you saying that you need to keep calling TASK_START after every EVENT_END? That does not sound right to me.

    Yes. Otherwise I only get one EVENT_END. Is it so that the internal timer keep emitting TASK_SAMPLE and they are ignored until a TASK_START is triggered again?

    Are you getting the EVENT_STOPPED following a EVENT_END?

    No.

    If you here mean to say that you are working with an Engineering Version A variant of the nRF52840 SoC (DK version 0.9.x) then I highly recommend that you update your hardware to a non-engineering variant for future development.

    According to the sticker, it's version 1.0.0 from 2018.46. The AAC0 was found by reading the INFO.VARIANT register which returned 0x41414330.

    While testing for EVENT_STOPPED I discovered one additional issue. Enabling the EVENT_DONE and EVENT_RESULTDONE interrupts causes something to misbehave in a way that prevents it returning control to thread context.

        nrf_saadc_event_clear(NRF_SAADC_EVENT_RESULTDONE);
        nrf_saadc_event_clear(NRF_SAADC_EVENT_DONE);
        nrf_saadc_int_enable(NRF_SAADC_INT_RESULTDONE);
        nrf_saadc_int_enable(NRF_SAADC_INT_DONE);

    This seem to only happen when nrf_saadc_task_trigger(NRF_SAADC_TASK_SAMPLE) is called. I get this behavior regardless of continuous mode or burst enabled/disabled.

    The call was made directly after TASK_START, i.e., line 46 in the original post. It didn't matter to wait for EVENT_STARTED before calling TASK_SAMPLE or calling it from the interrupt handler on EVENT_STARTED.

    Thanks.

Children
  • Hello again,

    Thank you for your patience with this. The national Easter holiday has concluded here in Norway, and we are now back in office. 

    JonasJ said:
    Thanks for confirming this. I haven't checked but I guess the same issue applies to all nRF52 devices PS.

    I too would guess that this is the case - I have asked them to take this possibility into the account in their review.

    JonasJ said:
    Yes. Otherwise I only get one EVENT_END. Is it so that the internal timer keep emitting TASK_SAMPLE and they are ignored until a TASK_START is triggered again?

    Oh, well, the END event is generated when the buffer is filled. Taking a closer look at the code you shared in the initial ticket it seems that you do not provide the SAADC with a new buffer when this happens, which means that the sampling has to be restarted.
    If you want to seamlessly start sampling into another buffer you need to implement double, so that the SAADC immediately will start filling into another buffer when the first one is filled - or you can move the SAADC buffer pointer to the front of the provided buffer.

    JonasJ said:
    No.

    Then I suppose that the SAADC is ready to continue sampling, but that it has nowhere to place the samples.

    JonasJ said:
    According to the sticker, it's version 1.0.0 from 2018.46. The AAC0 was found by reading the INFO.VARIANT register which returned 0x41414330.

    You need to read the build code printed on the nRF chip itself, not the sticker placed on the debugger.
    If you take a close look at the nRF chip, you should see the build code on the second line, following the SoC name.
    The sticker indicates that this is a DK version 1.0.0, which does not use an engineering variant of the SoC, so thats fine.

    JonasJ said:
    While testing for EVENT_STOPPED I discovered one additional issue. Enabling the EVENT_DONE and EVENT_RESULTDONE interrupts causes something to misbehave in a way that prevents it returning control to thread context.

    Could you possibly provide me with the complete project you used when encountering this issue? So I may take a look at what is going on for myself, and replicate it here on my end.

    Best regards,
    Karl

  • Hi again Karl,

    If you want to seamlessly start sampling into another buffer you need to implement double, so that the SAADC immediately will start filling into another buffer when the first one is filled - or you can move the SAADC buffer pointer to the front of the provided buffer.

    I'm actually doing exactly that, switching buffer on EVENT_STARTED in the real code but I still need to use PPI to connect EVENT_END and TASK_START. Otherwise it never restarts, but I guess it need TASK_START to consider the new buffer, or?

    Could you possibly provide me with the complete project you used when encountering this issue? So I may take a look at what is going on for myself, and replicate it here on my end.

    Sure, I have sort of reproduced the issue by modifying the blinky example in SDK for nRF5 v17.0.2. It seem that it keeps calling the IRQ handler despite clearing the events even after EVENT_END.

    There are two things you could try to modify to see different behavior. Consider removing the nrf_delay_ms(20) in the IRQ handler to see that it's actually not completely dead but only really slow. Second, you could try to not enable the INT_RESULTDONE and INT_DONE to get the correct behavior of LED1 and LED2.

    /cfs-file/__key/communityserver-discussions-components-files/4/16645.main.c

    I was expecting that the 20 ms delay in the IRQ handler would allow the SAADC to complete its 20 ms work and thus clearing the events afterwards would allow the LEDs to flash with the correct frequency without any interrupts to get into its way.

    Also with short 1us delay for each event in the IRQ handler, which should only add up to some 4-5 ms, shouldn't be noticeable on LEDs.

    I tested this on the pca10056.

    Thanks.

Related