nRF5340 SAADC power consumption

I'm profiling the current consumption of our device, on an nRF5340 module, at SDK 2.1.0.

So far as I can tell, the ADC is using approximately 1000 uA. It's sampling via PPI, and is triggered from an external clock signal at 1 kH.

The current consumption figures for the SAADC here show typical current consumption based on different configuration options. It looks like ~1000 uA is on the high end of what is expected, and that setting LPOP=LowPower would save us a considerable amount of current.

However I can't find anything about LPOP or LowPower anywhere else, either in the SAADC documentation or in the SDK.

Any tips as to where This can be enabled? I've seen this for an old version of the SDK, but it seems to come down to setting saadc_config.low_power_mode = true; which isn't part of the config struct in the current SDK.

Parents
  • Okay, I had the wrong idea a couple of days ago - in the sample button code, it sleeps for 1 ms in a while loop, and if I make that 1000 ms instead, the current consumption drops massively. I think that whole reply can be safely ignored!

    I've now copied over our interrupt code, so I can test it in isolation from the rest of our code. If I initialise the interrupt using a spare unconnected pin, I get current consumption of ~90 uA, and this is with the sense set to NRF_GPIOTE_POLARITY_HITOLO, which I suspect means we're doing edge detection, which adds some extra current. So that's encouraging.

    If I go back to using our external 1000 Hz RTC signal, I get just over 1 mA consumption. But I can set the prescaler on our external RTC to give different interrupt frequencies, and this is where things get weird...

    The pink line is 1000 Hz interrupts, and just over 1 mA current. The blue line is 250 Hz interrupts, and about 220 uA. The purple line is 500 Hz and oscillates between ~90 uA and ~220 uA.

    (The low power at the beginning is 2.5 seconds of sleep, the code to set up our external RTC over spi, and then 2.5 seconds of sleep again)

    All I can think is that the timing of the MCU going to sleep somehow requires > 1 ms for it to kick in, and so at 1000 Hz interrupts, we never get there. Or rather, I guess the idle current still has the HF oscillator on for ~1 ms?

    This is the config/init code I'm using - so the interrupt is disabled, and so button_pressed shouldn't be being executed. And I've done nothing to initialise the ADC or PPI.

        static const nrfx_gpiote_in_config_t pin_interrupt_config = {
            .sense = NRF_GPIOTE_POLARITY_HITOLO,
            .pull = NRF_GPIO_PIN_PULLUP,
            .is_watcher = false,
            .hi_accuracy = true,
            .skip_gpio_setup = false,
        };

        nrfx_gpiote_in_init(pin, &pin_interrupt_config, button_pressed);
        nrfx_gpiote_in_event_enable(pin, false);
  • Hi,

    Have you checked how long the execution time of the interrupt is? You can use GPIO toggling in the interrupt handler to check that, or toggle a GPIO at the end of the handler and compare this to the GPIO input. It is also possible to use DPPI and GPIOTE to toggle a GPIO from the POWER->EVENTS_SLEEPENTER and EVENTS_SLEEPEXIT to see when the CPU is actually in sleep.

    If for instance the interrupt takes 250us to complete, the ~1mA avereage current makes sense as it will make the Application CPU running about 25% of the time. This also makes sense for the 250Hz current. The 500Hz current does not make sense, but there could be some other error with this. Have you checked that the interrupt actually happens at 500Hz with this configuration? Is there anything in your application that corresponds with the rate that it toggles between high and low current consumption?

    Best regards,
    Jørgen

  • Those EVENTS_SLEEPENTER and EVENTS_SLEEPEXIT sound useful - I'll give that a try to confirm how long the CPU is asleep/awake.

    Just to clarify, the current consumption above is in the sample button project with the code to initialise our external RTC copied in, and the interrupt changed to the RTC pin on our board. I also swapped the interrupt code to use nrfx_gpiote in the same way as our main project.

    As far as I'm aware there shouldn't be any interrupt callback actually running, as nrfx_gpiote_in_event_enable(pinfalse); will mean it doesn't actually call the handler.

    Since all it does is initialise the RTC and enable the interrupt, there shouldn't be any other code running. I'm assuming that when the interrupt fires it wakes up the CPU, there's no ISR and no PPI/SAADC configured either, so it should just go straight back to sleep.

    I opened this support request to try to get to the bottom of what might be going on with the CPU sleep without worrying about the SAADC, PPI, interrupts etc. and just looking at the current consumption if we sleep in a while loop. As I mentioned before, I was getting ~650 uA in the button sample project just sitting in a while loop sleeping for 1 ms at a time, but only 23 uA if I set the sleep time to 1000 ms.

    I guess based on your reply, it might be taking ~250 us to go back to sleep from a GPIO interrupt, and ~150 us to go to sleep when just sat in a while loop. At least that would be consistent with the current figures. Is that longer than you would expect?

Reply
  • Those EVENTS_SLEEPENTER and EVENTS_SLEEPEXIT sound useful - I'll give that a try to confirm how long the CPU is asleep/awake.

    Just to clarify, the current consumption above is in the sample button project with the code to initialise our external RTC copied in, and the interrupt changed to the RTC pin on our board. I also swapped the interrupt code to use nrfx_gpiote in the same way as our main project.

    As far as I'm aware there shouldn't be any interrupt callback actually running, as nrfx_gpiote_in_event_enable(pinfalse); will mean it doesn't actually call the handler.

    Since all it does is initialise the RTC and enable the interrupt, there shouldn't be any other code running. I'm assuming that when the interrupt fires it wakes up the CPU, there's no ISR and no PPI/SAADC configured either, so it should just go straight back to sleep.

    I opened this support request to try to get to the bottom of what might be going on with the CPU sleep without worrying about the SAADC, PPI, interrupts etc. and just looking at the current consumption if we sleep in a while loop. As I mentioned before, I was getting ~650 uA in the button sample project just sitting in a while loop sleeping for 1 ms at a time, but only 23 uA if I set the sleep time to 1000 ms.

    I guess based on your reply, it might be taking ~250 us to go back to sleep from a GPIO interrupt, and ~150 us to go to sleep when just sat in a while loop. At least that would be consistent with the current figures. Is that longer than you would expect?

Children
No Data
Related