Problems putting UART into PM_DEVICE_ACTION_SUSPEND

This is my environment

  • IDE: VSC
  • SDK: NCS v2.2.0
  • nRF52-DK

I've been trying to get my current consumption down during System On Idle mode (spec sheet says I can get sub-2uA).  I can get this to work with a simple example code I've put together, and I simply make a call  to:

pm_device_action_run(uart, PM_DEVICE_ACTION_SUSPEND);
This seems to drop the current from ~ 200uA down to around 1.5uA.
However, in my more complex version (that is enabled with all the functionality I need for my custom hardware), it looks like I'm having issues getting the UART to actually go into the mode it needs to to get the current down.  This version is using the Async UART functionality, and I have a separate thread to process all the UART RX.  When this code goes into idle mode, I'm seeing around 300-400uA current drain.
In this version, I actually stop the UART RX first, then attempt to put the UART into suspend mode:
ret = uart_rx_disable(uart);
if (ret !=0) {
	LOG_WRN("Error disabling UART: err %d\n", ret);
}

ret = pm_device_action_run(uart, PM_DEVICE_ACTION_SUSPEND);
if (ret !=0) {
	LOG_WRN("Error suspending device: err %d\n", ret);
}
What I am seeing when I attempt to put the UART into low power mode is the following LOG info:
[00:12:21.031,707] <wrn> idle_mode: Error suspending device: err -120
[00:12:22.031,860] <wrn> idle_mode: Error suspending device: err -120
This is the return error from the pm_device_action_run(uart,PM_DEVICE_ACTION_SUSPEND) API, and according to Zephyr it means:
EALREADY   120 Operation already in progress.
What I'm trying to work out is:
1. Can I check somehow that the UART is actually suspended using a call to an API?  I'm trying to confirm if it is actually going into suspend mode and hence is the cause of my higher than expended current drain.  I am pretty sure it is, but wanted to check
2. I'm not getting these error codes in my simple version of firmware, so what might be causing this?  I can see the call to uart_rx_disable is successful (return code = 0),but the attempt at suspending the UART isn't.
Regards,
Mike
  • Hi Mike

    In versions prior to NCS v2.4.0, there is a known issue where after suspending UARTE0 with the PM device, you need to also make sure UARTE1 is disabled, as it was enabled by default in the devicetree in these older SDK versions. Here for more details: https://github.com/nrfconnect/sdk-zephyr/blob/fcaa60a99fa9d5256078ed28557856ec3709cfa9/boards/arm/nrf52840dk_nrf52840/nrf52840dk_nrf52840.dts#L151 

    Best regards,

    Simon

  • Hi Simon,

    Thanks for that info. Not sure that’s my issue though as I’m using an nRF52832 that only has the one UART. Sorry, I should have mentioned that in my original post.

    Also, I started with a very simple version of my firmware that just uses a timer to go in and out of idle mode. That shows the behavior I was expecting, with idle state current down around 2uA.

    I’m slowly adding the functionality I need to this and monitoring the idle state current to see if I can see what causes it to jump up once it’s been added. Haven’t found anything as yet!

    I did add a call to pm_device_state_get() before the calls I have to suspend and resume the UART, just to ensure I’m only attempting to do that when the UART is in the appropriate state. That seems to prevent the -120 errors I was seeing, so my firmware must have been making multiple calls to the API’s to suspend the device for some reason (not sure why yet)

    Anyway, I’ll keep going with my “add functionality to a simple version of code that works until it breaks” approach and see what I uncover. Then, if I need further help, I’ll report back here.

    Thansks again,

    Mike

  • Hi Simon,

    OK - I've got to the bottom of the issue.  I'm using the I2C via &i2c0 in my firmware as well.  I tried putting that into PM_SUSPEND, but it didn't seem to have any impact on the current.  If I set the status of &i2c0 to disabled in my overlay file, that sees the current in idle drop down to 5uA, but with it enabled, its up around 300uA

    I stumbled across this ticket.  Seems the OP is having a similar issue.  He doesn't say if he was able to solve it or not, but I did follow the recommendations in the errata link in that ticket, and added this to my code once I've put the I2C into PM_SUSPEND:

    	*(volatile uint32_t *)0x40003FFC = 0;
    	*(volatile uint32_t *)0x40003FFC;
    	*(volatile uint32_t *)0x40003FFC = 1;

    That saw the idle current in my test code go from ~ 300uA down to 5uA.  So, I think that was the issue.

    I'm still seeing higher than this level in my final version of code (its up around 70uA), but I think I need to follow a similar process as above to isolate what's causing the increased current and see if I can find a solution for it.  Some of my other peripherals on my hardware are probably drawing more than the nRF52 is now anyway, so it might be OK to just park this problem for the moment

    Regards,

    Mike

  • Hi Mike

    Thank you for your thorough feedback. This is sure to help other users with the same issue in the future. I'll keep this case open for now then, so that you can reach out to me if you get stuck somewhere. Don't hesitate to reach out!

    Best regards,

    Simon

Related