Mbed-os: DISCO-L475VG-IOT01A wakes up every second

Created on 25 Mar 2019  路  22Comments  路  Source: ARMmbed/mbed-os

Description

This is a power profile of 10 second blinky on DISCO-L475VG-IOT01A. Every second the MCU wakes up. What's going on here?

image

main.cpp

#include "mbed.h"
#include "mbed_stats.h"

static DigitalOut led(LED1);

int main() {
    printf("Hello world!\n");

    while (1) {
        led = !led;
        mbed_stats_cpu_t stats;
        mbed_stats_cpu_get(&stats);
        printf("Uptime: %llu ", stats.uptime / 1000);
        // printf("Idle: %llu ", stats.idle_time);
        printf("Sleep time: %llu ", stats.sleep_time / 1000);
        printf("Deep Sleep: %llu\n", stats.deep_sleep_time / 1000);
        wait_ms(10000);
    }
}

mbed_app.json

{
    "target_overrides": {
        "*": {
            "platform.stdio-convert-newlines": true,
            "platform.cpu-stats-enabled": 1,
            "platform.heap-stats-enabled": 1,
            "platform.sys-stats-enabled": 1,
            "platform.default-serial-baud-rate": 115200,
            "platform.stdio-baud-rate": 115200
        }
    },
    "macros": [
        "MBED_TICKLESS=1",
        "MBED_CONF_TARGET_TICKLESS_FROM_US_TICKER=0",
        "MBED_CONF_APP_IDLE_THREAD_STACK_SIZE=2048"
    ]
}

Mbed OS 5.12 (pre-release) rev. 7dd791e2f992d872b2dab4a7f061d05f7283090a compiled with GCC ARM 6.

Issue request type


[ ] Question
[ ] Enhancement
[X] Bug

CLOSED bug

Most helpful comment

Should we keep this issue opened on ST side ?

Don't think so. My input:

Suspending the kernel does not in itself do anything to stop the timer. Normally when the kernel is suspended, we want the timer to carry on running, so we know how long we were asleep for.

Therefore in this case the device wakes up periodically to note the timer wrap. (Or to run any other scheduled events). This would be less of a problem on a chip with a slower-wrapping timer.

If you really want to stay asleep in this scenario, then you will need to mask off the interrupts you don't want - have a limited set of "wake" interrupts.

This is something we're planning to do - have a "system suspend" that masks off all interrupts except a specific set, then calls kernel suspend.

You can experiment with this sort of thing yourself. As of 5.14 you can do this

bool want_wake;

void my_wake_irq_handler()
{
    want_wake = true;
}

bool do_i_need_to_wake(void *)
{
     return want_wake;
}

void system_suspend()
{
      osKernelSuspend();
      // reprogram NVIC to mask all interrupts apart from your wake interrupt here
      mbed::internal::do_untimed_sleep(do_i_need_to_wake, nullptr);
      // restore original NVIC mask here
      osKernelResume(0);
}

There are a bunch of tricky race issues there (eg what if someone else is messing with interrupt masks after we record it - might not restore it accurately), but basic concept should force the system down.

If we wanted to time the sleep we have more work to do - we'd want to stop the LPTIM and instead time it with the RTC. (And maybe use RTC as a wakeup source). Getting that all done smoothly and neatly and generically is a work package, but for a local app you can kind of do whatever you need manually.

All 22 comments

Hi @janjongboom

Could you try adding
"target.lpticker_lptim_clock": 4
in your mbed_app.json file ?

@LMESTM

This can be related to the maximum timeout period that can be programmed in HW,
Probably the HW Low Power timer cannot sleep for more than about 1sec. So mbed-os scheduler will program it for 1 sec, wake-up, check for anything to be done, then sleep again.

@LMESTM @jeromecoutant Yeah that works indeed! Which brings me to the question on why we aren't using this clock by default. Is there perhaps an application note on picking lpticker clock sources on STM32?

Hi gents.
I have the same problem with STM32L432KC target. I wrote about it on the mbed forum 4 months ago but nobody wrote back so I am joining the topic. Below oscillogram with current spikes on STM2L432KC:
DS1Z_QuickPrint1
The results are the same for "target.lpticker_lptim_clock": 1 and 4 so the change from @jeromecoutant does not solve the problem for STM32L432KC.
Time between the spikes are about 1s and the current value is near 1mA. Below my mbed_app.json settings:
{ "config": { "main_stack_size": { "value": 4096 }, "lpticker_lptim": { "value": 4 } }, "target_overrides": { "*": { "platform.stdio-convert-newlines": true, "platform.stdio-baud-rate": 115200, "platform.default-serial-baud-rate": 115200, "platform.stack-stats-enabled": true, "platform.heap-stats-enabled": true, "platform.cpu-stats-enabled": true, "platform.thread-stats-enabled": true, "platform.sys-stats-enabled": true, "lora.public-network" : false, "lora.duty-cycle-on": false, "lora.phy": "EU868", "mbed-trace.enable": true }, "NUCLEO_L432KC": { "target.stdio_uart_tx": "PA_9", "target.stdio_uart_rx": "PA_10" } }, "macros": ["MBEDTLS_USER_CONFIG_FILE=\"mbedtls_lora_config.h\""] }
Program works on LoRaWAN mbed-os example.
Please help to fix it?

@elforce what do you exactly want to solve ?
mbed-os scheduler relies on the LPTIM counter which wraps-up regularly, at least once per second. The target will wakes-up very shortly then go back to sleep. Is this really an issue ? How much is the power overhead ?

Note: In your above mbed_app.json extract I do not see Jerome recommendation:
"target.lpticker_lptim_clock": 4

@LMESTM If the device is working on the battery, eg. CR2032, and need to send data every 1 hour then should be in stop mode about 99.9% and wake only to send the data. Waking it up every 1s with mbed-os 5 from stop mode with the cyclical momentary power consumption about 1mA, it will drain the battery quite quickly. My question is how to be in stop mode and have the same behaviour like in mbed 2, static power consumption at the level of a few uA (with peripheries) all time? In mbed-os 5 with ST uC's (I do not know how with others) in stop mode current consumption is not static (tested on STM32L476 and STM32L432). For example about 8 minutes beeing in stop mode with this peaks is equivalent to sending 1 LoRaWAN frame. I think that is a big problem that's why @janjongboom reported it as a Bug.
About "target.lpticker_lptim_clock": 4 and last topic, my fault, I did not include proper code.
Proper is
"config": { "main_stack_size": { "value": 4096 }, "lpticker_lptim_clock": { "value": 4 } },

@ARMmbed/mbed-os-core this is a question to you - not something specific to STM32. Users are asking for vert long period of Deep Sleep without any wake-ups (RTC alarm like I think).

I have RTC running in the project and I wake up the device every 30 min, 1h, 3h. There is no problem with that. Probably this 1s awakening are needed for the mbed-os itself so that it can validate events or other stuff. @ARMmbed/mbed-os-core even if it can not be turned off, how this 1s peaks time can be extended?

@elforce Out of curiosity, what RTC alarm API are you using ?

It should not matter because I did tests without and with supported RTC. I am using mbed-os rtc_api functions: rtc_read() and rtc_write() but to set Timer and Alarm I use my own functions written using HAL libraries.
On the mbed forum similar threads with awakening every 1s have already been raised 2 or 3 times. In this forum is also a similar thread
https://os.mbed.com/questions/85125/Whats-causing-this-power-spike/
Nobody has given a solution yet, even a partial one. I have tested all.

It should not matter because I did tests without and with supported RTC. I am using mbed-os rtc_api functions: rtc_read() and rtc_write() but to set Timer and Alarm I use my own functions written using HAL libraries.

That was my point. As of now, there is no standard MBED API in case you want to sleep for hours without any wake-up.

On the mbed forum similar threads with awakening every 1s have already been raised 2 or 3 times. In this forum is also a similar thread
https://os.mbed.com/questions/85125/Whats-causing-this-power-spike/
Nobody has given a solution yet, even a partial one. I have tested all.

The 1sec wake-up is due to the wrap-around of the 16 bits LPTIM HW in STM32. Scheduler relies on this continuous always-running clock and will always schedule next interrupt within a few seconds to count for the next wrap-up. So as long as RTC is not used, you will have wake-ups every seconds or so.
The only solution I would see is to have an official RTC API is to be able to enter some 'standby mode', i.e. the scheduler would not schedule anything anymore until next wake-up from RTC ....
Maybe you could use a service like osKernelSuspend(); to disable the wake-ups and osKernelResume(0); from Alarm ... but I don't know if this is safe or not.

Internally for the mbed-os operation, the system does not use the RTC clock and there is probably a problem here. Although my overwrites and reconfigures the RTC, the peak problem still exists every 1s.
It is a good starting point with osKernelSuspend(). This function occurs in the mbed code about 10 times, so the mbed-os uses it. Maybe someone from @mbed-os will write how to suspend and resume safely mbed-os with LPTIM. That would solve the problem.
When device is in shutdown mode (also own code on HAL libs) the problem does not exist but shutdown is not good because it cuts off the power supply from the bank 1 RAM and I lose the initialized LoRa stack and I have to do the join every time I exit the shutdown.

Calling osKernelSuspend () does not work. Maybe I do not comply with conditions to stop the Kernel scheduler.

@MarceloSalazar - in case you can help.

Hi

Should we keep this issue opened on ST side ?

Calling osKernelSuspend () does not work. Maybe I do not comply with conditions to stop the Kernel scheduler.

@bulislaw @kjbracey-arm

Thx

I agree that this is not st specific.
Is it possible for an application to suspend the Kernel in order to avoid regular wake-ups and rely only other-than-timer related interrupts for waking-up and then resume the Kernel ?

Should we keep this issue opened on ST side ?

Don't think so. My input:

Suspending the kernel does not in itself do anything to stop the timer. Normally when the kernel is suspended, we want the timer to carry on running, so we know how long we were asleep for.

Therefore in this case the device wakes up periodically to note the timer wrap. (Or to run any other scheduled events). This would be less of a problem on a chip with a slower-wrapping timer.

If you really want to stay asleep in this scenario, then you will need to mask off the interrupts you don't want - have a limited set of "wake" interrupts.

This is something we're planning to do - have a "system suspend" that masks off all interrupts except a specific set, then calls kernel suspend.

You can experiment with this sort of thing yourself. As of 5.14 you can do this

bool want_wake;

void my_wake_irq_handler()
{
    want_wake = true;
}

bool do_i_need_to_wake(void *)
{
     return want_wake;
}

void system_suspend()
{
      osKernelSuspend();
      // reprogram NVIC to mask all interrupts apart from your wake interrupt here
      mbed::internal::do_untimed_sleep(do_i_need_to_wake, nullptr);
      // restore original NVIC mask here
      osKernelResume(0);
}

There are a bunch of tricky race issues there (eg what if someone else is messing with interrupt masks after we record it - might not restore it accurately), but basic concept should force the system down.

If we wanted to time the sleep we have more work to do - we'd want to stop the LPTIM and instead time it with the RTC. (And maybe use RTC as a wakeup source). Getting that all done smoothly and neatly and generically is a work package, but for a local app you can kind of do whatever you need manually.

Should we keep this issue opened on ST side ?
Don't think so. My input:

Maybe, you should then remove the "device st" label,
and assign the issue to core team ?
Thx

we closed the issue as we have feature request for this being tracked separately.

For anyone running into this, I put together a quick standby example for STM32 on Mbed OS some years ago: https://github.com/janjongboom/stm32-standby-rtc-wakeup

Was this page helpful?
0 / 5 - 0 ratings