nRF5340 high sleep current with short-duration sleep

I'm looking into the power consumption of our code, and have reached the point where it looks like our application isn't going into sleep mode properly, and is using several hundred microamps more power than it should be.

We want to sample from the SAADC every millisecond, but in testing our board, I've been running some sample code instead. The most basic example is just a while loop that sleeps for 1 ms.

In this case, doing nothing but sleeping in a loop, our board is drawing 671 uA. If I increase the sleep duration to 5 ms then it's drawing 200 uA. If it sleeps for 1000 ms it's drawing something like 23 uA.

I guess some current overhead is expected when waking more frequently, but profiling the current using an otii it looks like the 1ms sleep code doesn't ever drop below about 650 uA. Whereas for longer sleep durations I can see the current drop much lower.

So, my question is - how long does it take the nRF5340 to go into sleep mode? If it's > 1 ms then that would explain what I'm seeing - the chip never gets to sleep as it wakes up before it can turn off the HF clock. If so, is there any way to make it enter sleep faster?

Alternatively, I guess it could be the otii - it's sampling at 4 kHz, so maybe that's just not enough to catch the drop in power in sleep mode.

Parents
  • Hello,

    Could you show some of the code that ran when you did these measurements?

    The most basic example is just a while loop that sleeps for 1 ms.

    I suspect that this means that you are doing direct calls to the manual call to sample, is this correct? This will require that the CPU is involved with every sample taken, which will increase your power consumption significantely.
    To achieve the lowest power consumption when doing periodic SAADC readings we recommend that you connect the SAADC sample TASK to a CC event of a TIMER (or other periodic event generator), so that you avoid the CPU waking up to perform every sampling. If you do not immediately need to process every sample you can store them in a larger buffer, so that the CPU can wake to process them less often.
    Please try this, and let me know if you see a sufficient reduction in your average power consumption.

    Best regards,
    Karl

  • I mean that literally just sleeping in a while loop draws hundreds of uA. No sampling, no interrupts, nothing.

    void main(void)
    {
        while (1) {
            k_msleep(1);
        }
    }

    Whereas sleeping for 1000 instead of 1 there draws ~23 uA

  • Okay, this is the code I'm profiling - I've removed everything that isn't just sitting in a while loop sleeping, and checked it's still behaving the same way. The 1 ms sleep version doesn't seem to drop below about 650 uA at any point, although I can see the current going up and down as the CPU goes in and out of sleep.

    What I think is happening is that the HF oscillator doesn't have time to turn off if the sleep duration is only 1 ms, so we draw 650 or so uA. Whereas with a longer sleep duration it turns off in between and we can get a much lower current.

    The reason I'm looking at this is that in our actual code we're using a GPIOTE interrupt to trigger sampling via PPI as you recommended above, and this is resulting in the same sort of behaviour, with, I think, the HF clock on permanently.

    So I'm trying to work out whether a) this is correct, and the HF clock is staying on, b) If it is, is it possible to turn it off quicker and so save current, or c) if it isn't, is it possible to run the SAADC without turning the HF clock on at all.

    minimal_current_profiling.zip

  • Thank you for providing the minimal project, I'll do some testing here on my end and get back to you by the end of the week.

    Rory Morrison said:
    The reason I'm looking at this is that in our actual code we're using a GPIOTE interrupt to trigger sampling via PPI as you recommended above, and this is resulting in the same sort of behaviour, with, I think, the HF clock on permanently.

    Ah, yes, the PPI will require the HF clock, but the draw of the HF clock is much lower than that of the CPU. CPU triggered sampling is only really more energy efficient if you sample very seldomly, or non-periodically.

    Rory Morrison said:
    a) this is correct, and the HF clock is staying on, b) If it is, is it possible to turn it off quicker and so save current, or c) if it isn't, is it possible to run the SAADC without turning the HF clock on at all.

    It is correct that the HF clock will need to be enabled for the PPI to function, but it is also possible to run the SAADC from CPU triggered sampling, without PPI as well, but this usually comes with a higher power consumption for periodic / high frequency sampling. However, if you were to only sample once every second you could instead consider using the CPU to trigger this, rather than the PPI.

    Best regards,
    Karl

  • Ignoring all the PPI and SAADC stuff for the moment - this is just a while loop with a k_msleep for 1 millisecond. 

    Is this keeping the HF clock on all the time? Or is my current profiling out somehow?

    I've been using an otii sampling at 4 kHz so it's possible it's smoothing out the current and what looks like a small oscillation around 650 uA is actually a spike up to ~4 mA when the CPU turns on, and a dip down to 20 uA the rest of the time.

    So, when I call k_msleep, how quickly does the CPU turn off, and how quickly does the HF clock turn off?

  • Rory Morrison said:

    Ignoring all the PPI and SAADC stuff for the moment - this is just a while loop with a k_msleep for 1 millisecond. 

    Is this keeping the HF clock on all the time? Or is my current profiling out somehow?

    Just for good measure, could you detail your setup? How is everything connected to your kit?
    For good measure, we've also got this Power Measuring guide for the nRF5340 DK that could be useful to reference in regards to the setup.

    Rory Morrison said:
    So, when I call k_msleep, how quickly does the CPU turn off, and how quickly does the HF clock turn off?

    The HFCLK will not turn of if it is being used / requested by any other peripherals, like the PPI or GPIOTE (for high accuracy events).
    In your minimal application you do not use any such
    However, when you use the k_msleep(1) it would mean that your CPU has to wake up every 1 ms to process the next k_msleep instruction, which likely is skewing your measurements.
    If you have no operations/processing other than the k_msleep happening in your main loop you could instead leave it empty, which will have it go into the sleep thread/SYSTEM_ON sleep, which should give you lower overall power consumption (if you only would like to measure power consumption of a background process anyways, no CPU actions).

    Rory Morrison said:
    I've been using an otii sampling at 4 kHz so it's possible it's smoothing out the current and what looks like a small oscillation around 650 uA is actually a spike up to ~4 mA when the CPU turns on, and a dip down to 20 uA the rest of the time.

    I would think that you would see the spike to ~4mA if this was the case, when sampling with 4 kHz. I unfortunately do not have any personal experience with the otii tools (I primarily use the PPK II myself), but I would not imagine that it would miss the spike of the CPU turning on.

    Best regards,
    Karl

  • It's occurred to me that when I call k_msleep(1) the operating system has to time a 1 ms sleep. It can't accurately do that without using the HF clock, because 32768 clock cycles doesn't divide into 1000. So presumably something in the OS has to decide if it's worth using the LF clock and turning off the HF clock for part of the sleep time, or whether to just to keep the HF clock on throughout.

    So the question is, how does the OS decide that? Is there any way I can get zephyr to turn off the HF clock faster?

Reply
  • It's occurred to me that when I call k_msleep(1) the operating system has to time a 1 ms sleep. It can't accurately do that without using the HF clock, because 32768 clock cycles doesn't divide into 1000. So presumably something in the OS has to decide if it's worth using the LF clock and turning off the HF clock for part of the sleep time, or whether to just to keep the HF clock on throughout.

    So the question is, how does the OS decide that? Is there any way I can get zephyr to turn off the HF clock faster?

Children
  • Hello,

    The system clock is the RTC1, which is a ultra low power clock source - it will not need to keep the HF clock on in order to time the kernel sleeps, so that should not be what you are seeing here.
    I would rather think you are seeing the increased current from having to wake up to process the k_msleep every 1 ms.
    Did you try to keep the loop empty, and measured the power consumption in this case? If you are then seeing the expected levels we would be able to confirm that the excess draw is indeed related to the CPU wakeup to process k_msleep.

    Best regards,
    Karl

  • Possibly, although I don't think that explains all of it. I can measure the CPU wake up and sleep using EVENTS_SLEEPENTER and EVENTS_SLEEPEXIT, and that gives me 80 us awake (sometimes only 40), then 1000 us asleep. A back-of-the-envelope calculation gives me about 320 uA from that, when I'm seeing twice that on the otii.

    However, I've realised that the board I'm testing on (a prototype of our device) has an LDO that drops the voltage going to the nRF module, and I think smooths the current draw. So that would explain why I'm not seeing a big ~4 mA spike when the CPU turns on, and also why I don't necessarily see the full dip in current in sleep mode.

    I'm going to try it on a dev kit hooked up to an oscilloscope to see if I can actually see the spike, and confirm what the idle current is in between.

  • Rory Morrison said:
    However, I've realised that the board I'm testing on (a prototype of our device)

    Oh, I was under the impression that you were conducting these measurements on a DK - then that could indeed explain it.

    Rory Morrison said:
    I'm going to try it on a dev kit hooked up to an oscilloscope to see if I can actually see the spike, and confirm what the idle current is in between.

    Great, I look forward to hearing your results from this! :) 

    Best regards,
    Karl

Related