Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NRF52832 not going back to sleep completely after a wait_ms() call #7847

Closed
RobMeades opened this issue Aug 21, 2018 · 9 comments
Closed

NRF52832 not going back to sleep completely after a wait_ms() call #7847

RobMeades opened this issue Aug 21, 2018 · 9 comments

Comments

@RobMeades
Copy link
Contributor

RobMeades commented Aug 21, 2018

Description

I have a board on which I am using an NRF52832 (inside a u-blox NINA-B1 module). The board is for use in an energy harvesting application and hence low power consumption is absolutely critical.

The software behaviour is to run a timed EventQueue callback in which the main operations are performed. I can normally achieve ~2 uA current consumption for the NRF52832 outside the EventQueue callback unless I call wait_ms() inside the EventQueue callback; as soon as I call wait_ms() in the EventQueue callback (or elsewhere, for that matter) the current consumption jumps to ~7 uA and never, ever, comes down again.

You can see the effect in trace A:

trace_a

...whereas in trace B I have commented out the wait_ms() call and the power consumption recovers:

trace_b

My question is: how do I make the current consumption return to what it was before the wait_ms() call?

Here is my complete code (built for UBLOX_EVK_NINA_B1 and ARM tools), where the meat is in the wakeup() EventQueue callback. FYI, init_used_pins() calls into the Nordic HAL to set specific pins on our board for very specific purposes, which can be ignored; gpio16 is just wired to an LED to make it obvious where the EventQueue call occurs in the trace.

#include "mbed.h"

static EventQueue gWakeUpEventQueue(/* event count */ 10 * EVENTS_EVENT_SIZE);
static int wakeupCount = 0;

static DigitalOut gpio1(NINA_B1_GPIO_1, 0);
static InterruptIn gpio2(NINA_B1_GPIO_2);
static DigitalOut gpio7(NINA_B1_GPIO_7, 1);
static DigitalOut gpio16(NINA_B1_GPIO_16, 0);
static DigitalOut gpio17(NINA_B1_GPIO_17, 0);
static DigitalOut gpio18(NINA_B1_GPIO_18, 0);
static DigitalOut gpio20(NINA_B1_GPIO_20, 0);
static InterruptIn gpio22(NINA_B1_GPIO_22);
static AnalogIn gpio24(NINA_B1_GPIO_24);
static AnalogIn gpio25(NINA_B1_GPIO_25);
static DigitalOut gpio28(NINA_B1_GPIO_28, 0);
static I2C i2c(NINA_B1_GPIO_23, NINA_B1_GPIO_21);

static void wakeup(EventQueue *pEventQueue)
{
    gpio16 = 1;
    wait_ms(100);
    gpio16 = 0;
    wakeupCount++;
}

static void init_unused_pins()
{
    nrf_gpio_cfg(NINA_B1_GPIO_3,
                 NRF_GPIO_PIN_DIR_OUTPUT,
                 NRF_GPIO_PIN_INPUT_DISCONNECT,
                 NRF_GPIO_PIN_NOPULL,
                 NRF_GPIO_PIN_S0D1,
                 NRF_GPIO_PIN_NOSENSE);

     nrf_gpio_cfg(NINA_B1_GPIO_4,
                 NRF_GPIO_PIN_DIR_OUTPUT,
                 NRF_GPIO_PIN_INPUT_DISCONNECT,
                 NRF_GPIO_PIN_NOPULL,
                 NRF_GPIO_PIN_S0D1,
                 NRF_GPIO_PIN_NOSENSE);

     nrf_gpio_cfg(NINA_B1_GPIO_5,
                 NRF_GPIO_PIN_DIR_OUTPUT,
                 NRF_GPIO_PIN_INPUT_DISCONNECT,
                 NRF_GPIO_PIN_NOPULL,
                 NRF_GPIO_PIN_S0D1,
                 NRF_GPIO_PIN_NOSENSE);

     nrf_gpio_cfg(NINA_B1_GPIO_27,
                 NRF_GPIO_PIN_DIR_OUTPUT,
                 NRF_GPIO_PIN_INPUT_DISCONNECT,
                 NRF_GPIO_PIN_NOPULL,
                 NRF_GPIO_PIN_S0D1,
                 NRF_GPIO_PIN_NOSENSE);

     nrf_gpio_cfg(NINA_B1_GPIO_29,
                 NRF_GPIO_PIN_DIR_OUTPUT,
                 NRF_GPIO_PIN_INPUT_DISCONNECT,
                 NRF_GPIO_PIN_NOPULL,
                 NRF_GPIO_PIN_S0D1,
                 NRF_GPIO_PIN_NOSENSE);
}

int main()
{
    init_unused_pins();

    // Start the timed callback
    gWakeUpEventQueue.call_every(10000, callback(wakeup, &gWakeUpEventQueue));
    gWakeUpEventQueue.dispatch_forever();
}

Issue request type

[x] Question
[ ] Enhancement
[ ] Bug

@pan-
Copy link
Member

pan- commented Aug 21, 2018

Could you give us the traces obtained if MBED_SLEEP_TRACING_ENABLED is defined at compile time ?

The function wait_ms calls the function wait_us which uses the high resolution clock; that peripheral consumes a lot of power on NRF targets; a short workaround would be to use Thread::wait.

[Mirrored to Jira]

@RobMeades
Copy link
Contributor Author

RobMeades commented Aug 22, 2018

See below: basically I get the "Sleep locks held:" print line at power-on and then again around each EventQueue callback, and I get the lock count increment/decrement print as a result of the wait_ms() call.

I will try Thread::wait, though my current-measuring rig won't be available for me to confirm results until later today. The problem with this solution is likely to be that I will end up calling drivers I don't necessarily have control over in the EventQueue callback which may themselves call wait_ms().

Sleep locks held:

LOCK: mbed_wait_api_rtos.cpp, ln: 44, lock count: 1

Sleep locks held:

[id: mbed_wait_api_rtos.cpp, count: 1]
UNLOCK: mbed_wait_api_rtos.cpp, ln: 46, lock count: 0

Sleep locks held:

LOCK: mbed_wait_api_rtos.cpp, ln: 44, lock count: 1

Sleep locks held:

[id: mbed_wait_api_rtos.cpp, count: 1]
UNLOCK: mbed_wait_api_rtos.cpp, ln: 46, lock count: 0

Sleep locks held:

LOCK: mbed_wait_api_rtos.cpp, ln: 44, lock count: 1

Sleep locks held:

[id: mbed_wait_api_rtos.cpp, count: 1]
UNLOCK: mbed_wait_api_rtos.cpp, ln: 46, lock count: 0

Sleep locks held:

LOCK: mbed_wait_api_rtos.cpp, ln: 44, lock count: 1

Sleep locks held:

[id: mbed_wait_api_rtos.cpp, count: 1]
UNLOCK: mbed_wait_api_rtos.cpp, ln: 46, lock count: 0

Sleep locks held:

[Mirrored to Jira]

@RobMeades
Copy link
Contributor Author

RobMeades commented Sep 12, 2018

FYI, calling Thread::wait() as an alternative to wait_ms() does work but the more general issue is that there are places where a Timer is required and that does the same thing: once a Timer has been run the current consumption increases and never, ever, goes back down again.
[Mirrored to Jira]

@RobMeades
Copy link
Contributor Author

RobMeades commented Sep 12, 2018

I've tried making a direct call to us_ticker_free() to tidy things up after a Timer has been deleted but then everything falls over in a heap the next time a Timer is instantiated. What is the correct way to get my current consumption back down? Any hack will do, just so's I get my current down.
[Mirrored to Jira]

@deepikabhavnani
Copy link

deepikabhavnani commented Sep 20, 2018

@RobMeades - Please share your thoughts on #8189
[Mirrored to Jira]

@RobMeades
Copy link
Contributor Author

RobMeades commented Sep 20, 2018

I have a feeling that #8189 won't make a difference to the problem raised here since it is the HW clean-up when a Timer is deleted that is missing and I don't believe that #8189 adds such clean-up.
[Mirrored to Jira]

@deepikabhavnani
Copy link

deepikabhavnani commented Sep 20, 2018

I wanted to know if new proposed solution for wait_ms , will solve the issue?

wait_ms() is just the thread sleep (so rounding down). Not callable from interrupts, doesn't lock hardware sleep

[Mirrored to Jira]

@RobMeades
Copy link
Contributor Author

RobMeades commented Sep 20, 2018

It would solve the initial problem if all wait_ms() became effectively the same as Thread::wait() but it wouldn't solve my whole problem if Timer doesn't tidy up the HW on deletion. Maybe I should open another issue for the Timer problem...
[Mirrored to Jira]

@adbridge
Copy link
Contributor

adbridge commented Oct 4, 2018

Internal Jira reference: https://jira.arm.com/browse/IOTDEV-1613

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants