Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs

SAADC samples missing

Hi,

I'm implementing a hard real-time system (few us jitter) on nRF52840, SDK17.1, based on FreeRTOS project.

In the project, I need to sync GPIOs toggling with ADC sampling. There is heavy EGU-Timers-PPI-GPIOTE/SAADC work done (see attached picture)

However, I can't get the SAADC work reliably, and I get samples missed.

The setup is as follows:

I need to sample 4 adc channels (AIN4-7) at 4 specific times t1-t4 (200-250us apart)

For that I use PPI channel and tie T3_COMPARE1 event to SAADC_SAMPLE task.

I set up T3CCR1 = t1(=200us) and enable T3 interrupts

As T3 needs to run in sync with T4 (that toggles 5 GPIOTEs), both are started using another PPI channel that ties EGU1.1->T4_START and T3_START (as fork)

When T3CC1 gets to t1=200us, SAADC_SAMPLE is triggered (by the PPI) and the saadc samples 4 channels in SCAN mode

Concurrently T3 interrupt is triggered in which I set T3CC1 = t2 (& t3 & t4=850us on subsequent interrupts)

The same trick is used on T4 to generate a sequence of signals (T4CC0 used to generate interrupts).

The last T4 interrupt is triggered at t4+100us=950us, at this point I should get 4*4=16 adc samples in the buffer

(side note - converting AIn4-7 consume 35us, far less than 100us span from tast T3CC1 interrupt to T4CC0 interrupt)

For debug I use 2 counters - SamplesCounter incremented in saadc_hadler() & SequncesCounter incremented at the last interrupt of T4 (t=950us)

On each 'burst's last interrupt (t=950us) I check that these counters are identical.

Now, occasionally I find that these counters do not match and the SamplesCounter was not incremented.

Looking at SAADC.AMOUNT register shows 0 or another small number of samples actually taken (e.g. 2 samples) instead of the expected 0x10 (see image)

To debug I replaced the T3_COMPARE1 --> SAADC_SAMPLE ppi trigger with nrfx_saadc_sample() call in T3CC1 interrupt and count these invocation as well.

This way I can count the actual SAMPLE tasks triggered, which should be 4*SamplesCounter but this verification also fails.

Looked though the erratas as well. I noticed Errata 212, not sure if its relevant but I've extended acquisition times to 10us or more on all 4 channels (and pushed 200us forward the 950us interrupt just to give some room for the last conversion). Still not helping.

I know its complicated description, but it's a complicated situation ;)

Thanks for reading this far.

Any advice is appreciated as I'm scratching the bottom of the ideas bucket...

Thanks

  • Hey ,

    In reality,  the sequence shown above is only part of the full EGU--Timers-PPI-Saadc sequences that are going on.

    In practice, AIN0-3 are being sampled @ 1KHz with PPI channel T2CC0 ->SAADC_SAMPLE

    The sampled data is fed into an algorithm that decides when to generate the burst mentioned above.

    When its time to generate the burst, saad is being uninitialized and reinitialized with AIN4-7 as input.

    Then the software requests a ~1200us timeslot from the SD, once its  granted T3 & T4 are triggered bu EGU and the aforementioned sequence begins.

    This sequence of sequences goes no and on.

    This is depicted in the attached image.

    UPDATE -

    I followed errata 212 workaround each time saadc_init() runs (before saadc_channel_init()) and it seems to overcome the problem above (at least at first glance). I will keep testing and will update if I find something new.

    @Nordic_engineers@ - I suspect that errata 212 appears in a broader set of conditions than described in the errata sheet. As described above, I experienced the problem when switching from one set of channels to another set of channels back and forth. All channels were 10us (for testing), and BURST was off.

  • Hi,

    Do you have a minimal code example without BURST enabled, and T_acq >= 10 μs that will trigger errata 212?

    Best regards,
    Jørgen

  • Hi

    The code is quite extensive, I'll try to summarize it -

    This is a freertos application with some hard real time requirement.

    There are two modules involved: Analog.c & Sequencer.c - Analog.c constantly sample Ain0-Ain3 @ 1KHz, 10us acq time, driven by T2 & PPI.. Each sample is send to freertos algo task queue.

    The algo runs in task context. Once it decides a GPIOTE sequence  is requested it signals the sequencer task.

    The sequencer task:

    1. uninits the current saadc (that was controlled in the analog module)
    2. requesters 1150us timeslot from SD

      Now sequencer task is blocked and the rest is happening in realtime (PPIs & ISR)

    3. A radio callback is fired with  NRF_RADIO_CALLBACK_SIGNAL_TYPE_START signal
    4. In the callback EGU1.1 is triggered. It was previously tied to T4 & T3 start tasks hence timers begin to run synchronously.
    5. T4CC0 generates interrupts, al other T4CCRs (T4CCR1-5, ) are tied to toggling GPIOTE and T3CC1 is tied to SAADC_START
    6. On the first 'state' interrupt @100us, I initialize the saadc (AIN4-7, 10usacq time)
    7. T4CC0 intr is used as a state machine arbiter. On each T4CC0 interrupt, the other CC registers are modified as needed (according to the current state) to generate the sequence.
    8. Note that SAADC_START is triggered 4 times in the sequence (@200,400,600,850us) total of 16 samples need to be stored in the buffer
    9. On the last intr (@950us) I inspect guard variables, EGU flags and/or SAADC.AMOUNT register.
      1. If I find mismatch (EGU Flag tied to SAADC_END not set or AMOUNT != 0x10 or guard variable counting saadc_handler() invocations) I breakpoint and inspect.
    10. If everything is OKI stop T3, T4, saadc_unint() and restarts saadc_init() with the analog module's and reenable the PPI

    This way the saadc repeatedly : saadc_init() - samples several (of several hndereds) of samples - saadc_uninit() and the switch 'owner' to the other module.

    Now, occasionally branch to step 9a and brealpoint, Inspecting the EGU flags, AMOIUNt register and the variables or show that though 4 START tasks were triggered (=16 samples), no END task triggered. AMOUNT register display a relatively small number when this happens 0/1/2 instead of 0x10.

    The problem was resolved only when I added errata 212 workaround code right before the saadc_init()  command in both modules

    I Hope this helps to recreate the problem.

  • Hi,

    Have you tried recreating the problem with a simpler code? If you are not able to reproduce the errata with a simple code (i.e. enabling the first channels, sample, change enable the other channels, sample, and so on), it would be hard to recreate the problem on our end. It would then be hard to link it to the same errata, or prove that the errata conditions are wider. With such a complex procedure/code as you describe, there may be other sources of error that can cause issues, which we can't simply recreate on our end.

    Best regards,
    Jørgen

Related