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

NRFX SAADC in Zephyr fast and slow interleaved sampling

Hi Nordic team,

I have successfully developed an application using nrfx (Timer/PPI/SAADC) combo in NCS 1.5.x to be able to sample 2x differential channels very fast.

Similar to the method advised here

I have a few questions:

Since using advanced mode and PPI,  everything is set to work automatically, very fast (16K sample per sec) for 2x differential channels, and 4x oversample, adding more channels is impossible w/o lowering the overall sample rate.

1- How do I add other channels that I don't need to be sampled very fast? e.g. a few times ( < 20sps) per second. 

does this mean I  have to stop PPI and uninit and reinit  saadc to get the samples for low freq channels, then uninit reinit for the fast sampling? and switch between the two operations constantly? if this is the only way, can I do this in an interrupt context that is initiated by the timer? hence keeping it in sync with the timer/ppi/saadc combo.

Or is there a better way I cannot think of?

Unfortunately I cannot sample the high frequency channels less than 16ksps, so lowering that is not an option.

2- Hardware question: What are the noise/performance figures for the GAIN amplifier inside the nRF52840 SAADC for different gain/attenuate settings? 
Basically we do have an AGC amplifier circuit that feeds those high frequency channels into nRF ADC pins, therefore we're curious to see what gain or attenuate setting inside SAADC results in best performance, and hence adjust our external AGC accordingly.

Thanks,

  • Since using advanced mode and PPI,  everything is set to work automatically, very fast (16K sample per sec) for 2x differential channels, and 4x oversample, adding more channels is impossible w/o lowering the overall sample rate.

     As mentioned in nRF52840 Product Specification - SAADC - Oversampling, it is not possible to use more than one channel when using oversampling:

    "Note: Oversampling should only be used when a single input channel is enabled, as averaging is performed over all enabled channels."

    One way of going about this, is to only have one channel enabled at the time, and when you're done oversampling on that channel you reconfigure the SAADC to use the next channel. As Kenneth suggests in this ticket: https://devzone.nordicsemi.com/f/nordic-q-a/71704/right-way-to-oversample-burst-multiple-saadc-input-pins.

    You could probably also disable oversampling and sample over several channels and do the averaging in software.

    1- How do I add other channels that I don't need to be sampled very fast? e.g. a few times ( < 20sps) per second. 

    does this mean I  have to stop PPI and uninit and reinit  saadc to get the samples for low freq channels, then uninit reinit for the fast sampling? and switch between the two operations constantly? if this is the only way, can I do this in an interrupt context that is initiated by the timer? hence keeping it in sync with the timer/ppi/saadc combo.

     "does this mean I have to stop PPI and unitit and reinit saadc...". Yes, this would be the way to go about this, since there is no way of configuring separate sampling rates for separate channels. I will get back to you next week about the specifics of the implementation.

    2- Hardware question: What are the noise/performance figures for the GAIN amplifier inside the nRF52840 SAADC for different gain/attenuate settings? 
    Basically we do have an AGC amplifier circuit that feeds those high frequency channels into nRF ADC pins, therefore we're curious to see what gain or attenuate setting inside SAADC results in best performance, and hence adjust our external AGC accordingly.

     I will look into this next week as well.

    Best regards,

    Simon

  • if this is the only way, can I do this in an interrupt context that is initiated by the timer? hence keeping it in sync with the timer/ppi/saadc combo.

    It may be fine re-initializing the ADC from the interrupt since it such a small operation. However, I can't say this for certain.

    The section Offloading ISR work recommends ISRs to execute quickly, to ensure predictable system operation. So the optimal approach would be to offload the ADC re-initialization to a Workqueue Thread, or another thread. Offloading ISR work says the following 

    "When an ISR offloads work to a thread, there is typically a single context switch to that thread when the ISR completes, allowing interrupt-related processing to continue almost immediately. However, depending on the priority of the thread handling the offload, it is possible that the currently executing cooperative thread or other higher-priority threads may execute before the thread handling the offload is scheduled."

    If you make sure the thread handling the offload is of high priority, you may not encounter any issues with synchronization/not being able to reconfigure it fast enough. Check out Torbjørn's NCS ADC code snippet to see how to offload work to a Work Queue.

  • Thanks for this info.

    I have been facing a new challenge lately with nrfx/ncs where at high sampling rate, very randomly/rarely, the data buffer in RAM would be misaligned.

    e.g. if i have 2 channels configured, and doing sampling via Timer/PPI/nrfx_saadc, sometimes instead of the order of channels being, ch1, ch2, ch1, ch2 etc in "RESULT BUFFER" I get ch2,ch1, ch2, ch1.. I can tell when this happens usinga a breakpoint, because I intentionally have ch1 connected to positive potential (differential measurement, V_ch1+ > V_ch1- ) and ch2 is negative. 

    Could this be related to interrupt handling delays in zephyr?

    I'm sampling at 22KHz which is ~ 44us timer tick that send the SAMPLE TASK to saadc (3us sampling).

    My guess is there is a race condition at nrfx_saadc interrupt handling around when EVT_BUF_REQ happens.

    e.g. If an extra timer tick happens when the new buffer is being handed over to nrfx/saadc, when the previous buffer has ENDed what is the expected behavior? This isn't explained very clearly in the datasheet of nrf52840.

    I increased the IRQ priority of nrfx_saadc from 7 to 0. The problem seems to have gone away, but I'm doing long term testing to see if it ever happens rarely.

    another question: Do I need to use IRQ_DIRECT_CONNECT? I'm currently using IRQ_CONNECT. I've read that DIRECT makes the IRQ handling faster potentially.

    I have also disabled start_on_end int the nrfx_saadc config, so I can take control of START TASK, I stop the timer after EVT_DONE, to ensure no extra SAMPLE TASKS are triggered to saadc one it is done. Then I send the start task and wait for BUF_EVT and then the timer starts.

    If there are any relevant posts that you are aware of please share.

    I can share my code if needed in a PM.

    Thanks

  • Farhang said:
    I can share my code if needed in a PM.

    Yes, this would be nice. 

  • Hello Farhang, sorry for the delay on this. I got the code from you in PM, but I forgot about it. Since this ticket is in not in my queue of cases (because it's in a waiting state, since I answered last and waited for a reply). My apologies for that. I will test your project the next days.

    Best regards,

    Simon

Related