How to deep sleep?

Trying to demonstrate low power with periodic wakeup on my NUCLEO_L152RE board using Mbed OS 5

After initializing the project with mbed new myproject I dumped the snip below in mail.cpp. Nothing in mbed_app.json.

#include "mbed.h"

int main() {
    while(true)
        ThisThread::sleep_for(10000);
}

Now I had hoped to measure only a very little current across the IDD breakout on the board. (as I understand it, the IDD is where I should hook in my ammeter)

Anyway, I measure 3.8mA which isn’t exactly what I will call low power.

What am I missing?

You need to shut down the GPIO’s first, well, set them to analog input mode.

This is for the L152.

void LowPowerConfiguration(void)
{
    RCC->AHBENR |= (RCC_AHBENR_GPIOAEN | RCC_AHBENR_GPIOBEN | RCC_AHBENR_GPIOCEN |
                    RCC_AHBENR_GPIODEN | RCC_AHBENR_GPIOHEN);
                    
    GPIO_InitTypeDef GPIO_InitStruct;
    // All other ports are analog input mode
    GPIO_InitStruct.Pin = GPIO_PIN_All;
    GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
    HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
    HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
    HAL_GPIO_Init(GPIOH, &GPIO_InitStruct);
    
    RCC->AHBENR &= ~(RCC_AHBENR_GPIOAEN | RCC_AHBENR_GPIOBEN |RCC_AHBENR_GPIOCEN |
                    RCC_AHBENR_GPIODEN | RCC_AHBENR_GPIOHEN);
}

Call this BEFORE defining your connected device pins.
If you call this after it will overwrite those device pin settings, however you can define them again.
In some case’s you have to define them twice. But the more pins you define AFTER will result in increase sleep current.

If you have both Xtals fitted, you may need this in mbed_app.json ;

"NUCLEO_L152RE": {
            "target.clock_source": "USE_PLL_HSE_XTAL",
            "target.macros_remove": ["MBED_TICKLESS"],       
            "target.lpticker_lptim_clock": 4,
            "target.lpticker_lptim": 0
        }

You are looking at around 3.2uA on that IDD connector, no pins defined.
I tend to use ‘baremetal’ with an external wake-up driver and use;

hal_deepsleep();

Paul

I copied in your LowPowerConfiguration function and added a call to it as the first thing in my main(), before the endless loop.

Current dropped to 3.2mA

I haven’t fitted an extra Xtal on the board, so I didn’t do the mbed_app.json part.

Can it be the debugging lines and other stuff on the nucleo board that suck the juice?

There’s so much going on with the Mbed OS RTOS functions, I could never get any useful low power functions.
Try setting ‘baremetal’ put this in the mbed_app.json file, you don’t need anything else.

{
    "requires": ["bare-metal"]
}

Then call

hal_deepsleep();

After the LowPowerConfiguration code.
It won’t wake up, but it should go to 3.2uA

Bingo. 2.99uA (measured on a multimeter which has not been calibrated for 25 years)

So at least I know the IDD breakout was indeed the place to measure.
A side effect of disabling RTOS is a much faster build process and smaller image - hard to complain here.

Now, to get my timer going I switched

hal_deepsleep();

for

 thread_sleep_for(10000);

With this I measure 4.3uA with peaks every 10 second. Seems reasonable I think.

Not entirely sure if this is how to do it, thread sounds like a thing from RTOS.

And with reading a little further I managed to get similar results with the full Mbed OS in place as well.
I enabled tickless in mbed_app.json

{
    "target_overrides": {
        "*": {
            "target.macros_add": ["MBED_TICKLESS"]
        }
    }
}

And then reverted to use

ThisThread::sleep_for(10000);

If you don’t need RTOS then stick to baremetal it compiles faster and you wont get so many hard faults coming up.

thread_sleep_for()

is the sleep/deep sleep replacement in baremetal.
The only issue is the lowpowerconfig code is a pain and if you use another board it will be a different set up.

It is considered that in baremetal, the main function is the one and only thread, thus the thread_sleep_for

Ok, now I’m with a NUCLEO_F091RC board instead. So I will need to do somehow the same as your code above, but for a F091.
Trying to do so I realized I don’t really understand much of whats going on.
Lets break it down, and then I hope for someone to step in and explain the pieces:

  1. The RCC->AHBENR seems to enable some port access, why do we need to do this?
  2. GPIO_InitStruct makes sense, since all ports are going to get the same configuration. but I have a hard time to find the palette to choose from, where see if this chip has fx. GPIO_SPEED_LOW ?
  3. then it gets applied to ports A, B, C, D, E and H. Oh my, what do I look for in the datasheet to figure out which ports are on my F091 ?
  4. lastly we disable the access again, I guess this wont need any explanation if i manage to understand #1

It’s like I miss the glue between mbed and the ST datasheets.

/mogul

Yes things don’t always match the MCU reference manuals here.

Generally all the defines should be in the Target main header fiile.

https://github.com/ARMmbed/mbed-os/blob/master/targets/TARGET_STM/TARGET_STM32F0/TARGET_STM32F091xC/device/stm32f091xc.h

It is a case of scanning through these and pick out the right names.

I haven’t actually tried anything low power on the F series MCU’s only the L’s .
I would check that setting these to ‘analogue’ does in fact have the same effect.

Have a look here too:

Still the L MCU but these guys have produced a proper library.
With Target conditional code this could be evolved to cover all the STM targets as an external library rather than integrated inside the official Mbed library.

They have an eeprom library there too, that could be handy!

Hi everyone,
I would like to summarize deep-sleep, standby, shutdown mode base on above discussion.

Condition:

COMPILER: on-line compiler (windows10 Google Chrome)
Mbed-os: os5.15.1 and os6.6.0
CPU board: Nucleo-L152RE, -L476RG,-F411RE, -F446RE, DISCO-L475VG-IOT01A
Measurement Date: Jan. 16th, 17th, 2021
Equipment: DMM6500(KEITHLEY)

Programs:

/users/kenjiArai/code/Check_DeepSleep_os5/
/users/kenjiArai/code/Check_DeepSleep_os6/
/users/kenjiArai/code/Check_StandBy_os5/
/users/kenjiArai/code/Check_StandBy_os6/

Tips:

DEEPSLEEP

On Mbed-os5.15.1, you can use below one of the following three.

            ThisThread::sleep_for(10000);
            thread_sleep_for(10000);
            wait_ms(10000);

Case for Nucleo-L152RE, IDD(measure at JP6 -> This is only CPU power line) is 4.23uA(microampere).
This value was achieved with the all peripheral ports set to analog input in advance(call LowPowerConfiguration() -> Thanks Paul) .
Restart is starting from RESET condition(call sys_reset()) due to complexity of back to main program.
During deep-sleep condition, you can push “USER_BUTTON” to restart the program.
For os6.6.0, control program is not so easy!
You need additional command before call above “sleep_for” function.

            // 1) removes the receive interrupt handler(UART)
            pc.enable_input(false);
            // 2) and releases the deep sleep lock
            sleep_manager_can_deep_sleep();
            // 3) then enter Deep Sleep mode
            ThisThread::sleep_for(10s);

More detail, you can reach this explanation.
https://os.mbed.com/docs/mbed-os/v6.6/apis/power-management-sleep.html

STANDBY(SHUTDOWN)

For Nucleo-F411RE and -F446RE, DeepSleep is not enough performance for a power consumption.
Nucleo-F411RE case is 1.91mA(NOT microampere but milliampere!) and F446 is 1.76mA.
Erick made a good program in the past.
https://os.mbed.com/users/Sissors/code/WakeUp/
I modified it only for STM CPU’s.
The program can go to “StandBy Mode” which is more low power consumption compare with “DeepSleep Mode”.
Nucleo-F411RE reached 3.40uA duaring “StandBy Mode”.
I could NOT control Nucleo-L476RG board due to different control architecture for the PWR control module in the CPU.
Today, I can reach one solution.
This is not “StandBy Mode” but “ShutDown Mode”.
Nucleo-L476RG reached 620nA(nanoampere) during “ShutDown Mode”.

Attention:

As you know well, most of Mbed boards are equipped two CPU, Main CPU and Interface CPU.
This explanation, I just measured Main CPU VDD line current.
Total system power consumption, you need to concern how to reduce peripheral IC’s, such as I2C device, external EEPROM and so on, even +3.3V regulator.
If you use an evaluation board(like Nucleo series), you need to power off Interface CPU.
Otherwise, total power (came from USB line) is not reached enough level!

Enjoy low power consumption!

2 Likes

This is a contentious issue, as you say Erik did a very good (the best!!) wake-up library and although this concept has been attempted in later Mbed libraries right up to v6, I’m afraid it is a no go now.

There’s way to much emphasis on thread based architecture in the current mbed OS.
Yes you can do quite a lot of low power projects but there are limitations.

Unfortunately for Mbed there are better solutions out there , the rapid development side of mbed has gone a long time ago.

There’s been way to much depreciation and to many ‘RAPID’ library changes that makes mbed the underdog now.

Dam shame, I love the online compiler and Studio (off line ).

But I need to get some work done, can’t do that on mbed unless they get new staff and a new direction.

Give Arduino a try, you will absolutely hate the IDE, but I’ve been working with some 16MB ESP32 device’s and it blows mbed out the water. Although you do have to approach low power from a different angle.