Low power SAADC

Hi,

I have a very high consumption when using the ADC of the nRF9160, I am using the NCS 2.0, the firmware used is inspired by the sample provided on github below:

https://github.com/Rallare/fw-nrfconnect-nrf/blob/nrf9160_samples/samples/nrf9160/adc/src/main.c

Attached is the developed firmware, it is as simple as possible, reading only one channel from the ADC!

adc_nh3.7z

The consumption of the reading of 1 channel from the ADC every 2 seconds can be observed below, I find a floor current of 2.81 mA, something totally unexpected.

This consumption refers to firmware with log and serial disabled, in addition to the problem with consumption, I found a problem related to the use of timer, when I use a timer (it is commented on in the code) to perform the reading of the ADC, I have the first 2 readings totally wrong, regardless of the interval between readings, always the first reading is 0 and the second is a totally inconsistent value, but this disappears when I read through a while inside main.

I looked in several topics related to SAADC how to reduce consumption, but I didn't find anything related to NCS, zephyr. There are many samples for nRF5, but for NCS the information and samples regarding SAADC are limited to the basics or theory.

In the github below, you can see that through nRF5, it is possible to reach an average consumption of 5uA using SAADC, how could you get close to that using NCS 2.0?

https://github.com/NordicPlayground/nRF52-ADC-examples/tree/master/saadc_low_power

Could you give me some example or tips to reduce consumption when using SAADC?

Thank you.

  • Hi. 

    You can achieve similar average current in NCS, by combining the ADC example with the system_off example. 

    In system_off, they use PM_STATE_SOFT_OFF with the power manager, which you shouldn't be using. Instead use PM_STATE_SUSPEND_TO_RAM, and put the system to sleep between ADC reads, using k_msleep() or k_sleep().

    Attached is an image of the current profile I was able to achieve on nRF52832 using NCS. The sleep current is 2.8 uA. 

  • Hi  ,

    Thanks for the answer!

    Should this work on the nRF9160? I changed my code forcing to use the recommended power management mode "PM_STATE_SUSPEND_TO_RAM", during idle state between ADC reads, but there was no change in consumption... did I miss any details?

    while (1) {
    		err = adc_sample();
    		if (err) {
    			printk("Error in adc sampling: %d\n", err);
    		}
    		pm_state_force ( 0u , &( struct pm_state_info){PM_STATE_SUSPEND_TO_RAM, 0 , 0 });
    		k_sleep(K_MSEC(2000));
    	}
  • It took me a while to get the code, personally I have it in form of an easy to read function

    bool force_low_power_state()
    {
        struct pm_state_info info =
        {
            .state            = PM_STATE_SUSPEND_TO_RAM,
            .substate_id      = 0,
            .exit_latency_us  = 0,
            .min_residency_us = 0,
        };
        return pm_state_force(CPU_ID, &info);
    }

    But yeah, your code checks out, and it should not be taking THAT much current.

    Are you sure it isn't being consumed by some some other component or peripheral? 

  • Yes, I'm sure it's not being consumed by any other peripheral, this code is exclusive to the ADC, I don't have threads and this while is in the main, I only execute the ADC reads every 2 seconds.

    I added the necessary libs and CONFIG, so I didn't have any errors, but my consumption didn't change.

    I take the opportunity to leave a question, this approach only reduces consumption (or should) when the entire system is idle right? So in a real application, where I will have other threads, will the high consumption of the ADC remain even when I wake up the CPU to run other threads that are not related to the ADC? If that's the case, I don't think it's ideal for my application.

  • You can choose to turn off the ADC when it is not needed. That being said, I leave it as is, and it doesn't consume any power unless I perform an ADC operation (capture, process etc.)

    I find it very strange that the baseline current for sleep is 2.8 mA, that is extremely high. 

    I would advise that you thoroughly check your measurement process, and make sure nothing else is running in the background. GPIOs, i2c, PWM, could be any of those. 

Related