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

ADC interupt based on SAADC limit monitoring or LPCOMP

Greetings,

We are using nrf-sdk v1.3.0.

We would like to monitor an adc channel using either limit event monitoring or maybe LPCOMP.

I was able to find "low level" documentation, describing the registers and such, but no actual example code using zephyr.
https://infocenter.nordicsemi.com/index.jsp?topic=%2Fps_nrf52840%2Flpcomp.html&cp=4_0_0_5_11
https://infocenter.nordicsemi.com/index.jsp?topic=%2Fps_nrf52840%2Fsaadc.html&cp=4_0_0_5_22_6&anchor=saadc_limits

What we would like to achieve is the following:
1. On device startup, sample the adc channel 1000x -> calculate average baseline value. This value would then used as the trigger threshold.
2. go to sleep
3. when the sample value on the channel is bellow 70% of threshold or above 130% of threshold, trigger an event handler in code (waking the system).

NOTE:
we know how to do #1.
The percentages in #3 are just an example, we would like to be able to change them in the code every so often.
We need to consume as little power as possible.
The comparison should be "continious", if possible. Or, if ADC must be sampled, once per second should be OK

Reading this thread:
https://devzone.nordicsemi.com/f/nordic-q-a/20895/saadc-low-power-scan-mode

I can see that this can be done, but there are not enough code samples to be able to produce something working. 
Must I set the registers directly? is there no wrapper API for this?

I would be very happy to see a working code example.

Regards,
Tjaž

  • Hello, 

    There are some ADC samples in Zephyr e.g. Battery Voltage Measurement. Unfortunately, there are very few for ADC.

    You are referring to nRF52840 documentation, while the DevZone tags show nRF9160. Can you please elaborate?

    Kind regards,
    Øyvind

  • Yes, sorry.

    We are trying to do this using nrf9160.

    The docs are these:
    https://infocenter.nordicsemi.com/index.jsp?topic=%2Fps_nrf9160%2Fsaadc.html&cp=2_0_0_5_11_8&anchor=saadc_limits

    Regardless of the wrong links, the question remains the same: how to register a handler to run when adc sample is "out of range", and to consume as little power as possible?

    If this can not be done through zephyrs APIs, is it possible in some other way?

  •  Note that this is a 4 year old answer which is not related to nRF Connect SDK.

     

    Tjaz said:
    Regardless of the wrong links, the question remains the same: how to register a handler to run when adc sample is "out of range", and to consume as little power as possible?

     There is currently no API for this in Zephyr, but you can use the nrfx saadc driver directly (modules\hal\nordic\nrfx\drivers\include\nrfx_saadc.h)

    /**
     * @brief Function for setting the SAADC channel limits.
     *
     * When limits are enabled and the conversion result exceeds the defined bounds,
     * the handler function is called with the corresponding event as parameter.
     *
     * @note Before the limits are set, the driver operation mode (simple or advanced) has
     *       to be configured. Only non-blocking conversions can be monitored.
     *
     * @note Changing of the driver operation mode disables all configured limits.
     *
     * @param[in] channel    Channel index.
     * @param[in] limit_low  Limit low value to generate interrupt. Use @c INT16_MIN
     *                       to disable interrupt generation.
     * @param[in] limit_high Limit high value to generate interrupt. Use @c INT16_MAX
     *                       to disable interrupt generation.
     *
     * @retval NRFX_SUCCESS             Requested channel limits were set.
     * @retval NRFX_ERROR_INVALID_PARAM Attempt to activate the limits on disabled channel.
     * @retval NRFX_ERROR_FORBIDDEN     Attempt to activate the limits for blocking conversions.
     * @retval NRFX_ERROR_INVALID_STATE Attempt to activate the limits without configured mode.
     */
    nrfx_err_t nrfx_saadc_limits_set(uint8_t channel, int16_t limit_low, int16_t limit_high);

  • Thank you for the link.

    I have some further questions:

    1. Is there a driver for setting RTC to trigger SAADC sampling on an interval?

    2. Can I use this driver you linked in addition to my existing code, that uses zephyrs driver (#include <drivers/adc.h>)? Or will using nrfx_saadc.h directly mess up things that I configure with adc.h?

    Regards,
    Tjaž

  • Tjaz said:
    1. Is there a driver for setting RTC to trigger SAADC sampling on an interval?

     Yes, I believe the DPPI can be used for this purpose. Have a look here. Just change TIMER0 to RTC.

    One-to-one connection

    This example shows how to create a one-to-one connection between TIMER compare register and SAADC start task.

    The channel configuration is set up first. TIMER0 will publish its COMPARE0 event on channel 0, and SAADC will subscribe its START task to events on the same channel. After that, the channel is enabled through the DPPIC.

    
    NRF_TIMER0->PUBLISH_COMPARE0 = (DPPI_PUB_CHIDX_Ch0) | 
                                   (DPPI_PUB_EN_Msk);
    NRF_SAADC->SUBSCRIBE_START   = (DPPI_SUB_CHIDX_Ch0) | 
                                   (DPPI_SUB_EN_Msk);
      
    NRF_DPPIC->CHENSET = (DPPI_CHENSET_CH0_Set << DPPI_CHENSET_CH0_Pos);

     

    Tjaz said:
    2. Can I use this driver you linked in addition to my existing code, that uses zephyrs driver (#include <drivers/adc.h>)? Or will using nrfx_saadc.h directly mess up things that I configure with adc.h?
    The Zephyr ADC (zephyr\include\drivers\adc.h-->zephyr\drivers\adc\adc_nrfx_saadc.c) uses the functions from hal/nrf_saadc.h. If you configure stuff on the lowest level first (nrf_saadc.h.) the Zephyr layer will not know about it. I would recommend sticking to one layer. But if you know what you're doing, I think it should be possible to mix them
Related