Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs

nrf5340 SDK 1.9.1 idle mode consumption and power management

Problem: I see a constant 1.4-1.5mA power consumption that I am unable to explain, can;t reduce despite trying a few things and need help debugging further

SDK: 1.9.1

MCU: nrf5340 running at 128MHz (not the default 64MHz)

Board: custom with multiple external components (PMIC, Accel, and few other things)

Environment: SES

Build: secure build 

We have BLE enabled (few 100 bytes being sent exactly every second), MCUBoot, and DFU.. everything works as expected with zero issues (functionally and timing wise).. except for this current consumption we can not explain

What I have done

1. Basic stuff
Turned off serial/uart/log in prj.conf (for application core AND network core (hci_rpmsg).. we use MCUboot and turned off UART there too
CONFIG_ASSERT=n
CONFIG_LOG=n
CONFIG_CONSOLE=n
CONFIG_SERIAL=n

// UART debug port
&uart0 {
status = "okay";
//status = "disabled";
/delete-property/ rts-pin;
/delete-property/ cts-pin;
tx-pin = < 0x19 >;
rx-pin = < 0x1a >;
current-speed = <460800>;
};

#power management
CONFIG_PM=y
CONFIG_PM_DEVICE=y
CONFIG_PM_DEVICE_RUNTIME=y

and i have added  the following too

#include <pm/pm.h>
#include <device.h> 

I have added 
/* Prevent deep sleep (system off) from being entered */
pm_constraint_set(PM_STATE_SOFT_OFF);

Questions:

1a. FPU is ON.. does it make any difference (we need it and hence can't turn it off).. 

1b: shutting UART off should reduce power by 500uA right ? or is it more ? 

2. I have a few GPIOs configured as interrupt pins.. most are edge triggered GPIO_INT_EDGE_FALLING or GPIO_INT_EDGE_RISING (won;t work otherwise so, i cant go for level triggered at this time)..Only button is GPIO_INT_LEVEL_INACTIVE..  Looks like in 1.9.1 we need to add an entry in overlay to take care of masking for sense-edge and i did..

&gpio0 {
status = "okay";
sense-edge-mask = < 0xffffffff >;
};

&gpio1 {
status = "okay";
sense-edge-mask = < 0xffffffff >;
};

Will making interrupts edge triggered add 100s of uA like it is mentioned in some older tickets ? is there a way around that I am missing ?

3. do we have to add CONFIG_PM=y  and CONFIG_PM_DEVICE=y to mcuboot and hci_rpmsg conf files too ? I haven't tried it yet

4. looks like idle thread runs.. (i even added a dummy idle with low priority to see if CPU is always busy doing stuff.. and i see that my dummy thread gets called ample times too..

just for testing, I enabled UART and added a print  (

if (pm_system_suspend(_kernel.idle) == false) {
printk("\n suspend failed");
k_cpu_idle();
}

and I see that print suspend failed ALL the time which is worrying.. but wasn't sure if it's the print that's making it fail or is it really failing.. hence asking you guys if this is something worth worrying  and investigating

5. using my PMIC , I cut off power for all external components and I still see suspend failed and still this additional power consumption.  I disconnect the JTAG and reset the board after flashing .. just to avoid answering "is JTAG somehow enabled.. have you reset the board"

6. I do have I2c2 and 3 turned on  configured at I2C_BITRATE_STANDARD (not doing transactions at the time of measurement).. according to datasheet, this should not add 100s of uAs  but may be 10of uA..  I also have one SPI port configured (but NOT doing any transactions).. Is this ok  or should I shut down everything except when i am using (makes the application design a bit more complex :-) )

7. I use QSPI (single wire) to talk to a Display controller and when display is not in use, QSPI is shutdown and pins are disconnected.

8. Eventually, I shutdown all peripherals and I still see no evidence of CPU going to idle and power consumption is close to 1 mA which really kind of shocked me.so I am questioning what else do i have to do .. base don what i have read, CONFIG_PM=y will ensure idle thread will run (and i verified that it does) and will ALSO push the cores to a lower power mode (which I don't see).. 
CONFIG_PM_DEVICE=y will need explicit power management api calls and implementations from individual drivers.. i have done that for my display driver (and have verified that it shuts down)
CONFIG_PM_DEVICE_RUNTIME=y --> I am not sure if this needed or should I removed it

I am close to the point of factory production of our device and this issue has become critical given this extra current consumption has reduced the battery life to half of what we would need it to be

  • @simon, 
    I use the same board files as nrf5340dk.. a few pins are modified using overlay.. 
    i put a few prints and can confirm that we never enter idle.. 

    No suitable power state found for cpu: 0! ---->from struct pm_state_info pm_policy_next_state(uint8_t cpu, int32_t ticks)
    No PM operations done. id 0 ---> from function bool pm_system_suspend(int32_t ticks) in pm.c
    suspend failed ---> added this line in idle.c if (pm_system_suspend(_kernel.idle) == false)

    why would this be ? in the zephyr.dts file created after build, i don;t see any entries for cpu-power-states  or min-residency-us which is needed by PM to go to low power modes..

    Can you please help me understand this ?

  • @simon, 
    I use the same board files as nrf5340dk.. a few pins are modified using overlay.. 
    i put a few prints and can confirm that we never enter idle.. 

    No suitable power state found for cpu: 0! ---->from struct pm_state_info pm_policy_next_state(uint8_t cpu, int32_t ticks)
    No PM operations done. id 0 ---> from function bool pm_system_suspend(int32_t ticks) in pm.c
    suspend failed ---> added this line in idle.c if (pm_system_suspend(_kernel.idle) == false)

    why would this be ? in the zephyr.dts file created after build, i don;t see any entries for cpu-power-states  or min-residency-us which is needed by PM to go to low power modes..

    Can you please help me understand this ?

  • I ran the hello_world sample with nrf5340dk_nrf5340_cpuapp with the following modification in idle.c-->idle():

    if (pm_system_suspend(_kernel.idle) == false) {
    	printk("pm_system_suspend() returned false");
    	k_cpu_idle();
    }else{
    	printk("pm_system_suspend() returned true");
    }

    I disabled UART/serial logging and used RTT instead

    I saw that "pm_system_suspend() returned false" was printed, which means that k_cpu_idle() will run and put the system to System ON sleep.

    Do you see the same? Even in the case where pm_system_suspend() does not suspend the system (returns false), the k_cpu_idle() should still be called and put the chip into system ON sleep (2-3uA).

    Best regards,

    Simon

  • Unfortunately,  I was stupid enough to trust "Tool chain manager" update and updated.. now my environment is broken as observed by many in the community and plenty of tickets flying around exactly like this one.. so can't do much.. I really have  no idea why do you guys do this to us :-)

  • I'm sorry to hear about that. Feel free to open a new ticket about that issue, or engage in  (Missing Forum Thread) 

    Best regards,

    Simon 

Related