Skip to content

STM32L152RE deepsleep state power too high #11853

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

Closed
star297 opened this issue Nov 13, 2019 · 27 comments · Fixed by #13777
Closed

STM32L152RE deepsleep state power too high #11853

star297 opened this issue Nov 13, 2019 · 27 comments · Fixed by #13777

Comments

@star297
Copy link
Contributor

star297 commented Nov 13, 2019

Description of defect

Deepsleep not working, appears to be working in sleep mode (750uA) only. Deepsleep should be around 3uA normally.

Target(s) affected by this defect ?

STM32L152RE (Nucleo-L152RE)

Toolchain(s) (name and version) displaying this defect ?

ARM(On-Line)

What version of Mbed-os are you using (tag or sha) ?

5.14.1 bare-metal

What version(s) of tools are you using. List all that apply (E.g. mbed-cli)

On-Line compiler

How is this defect reproduced ?

Call 'sleep();' and measure on the MCU IDD
I'm using this in my mbed_app.json file. the other targets appear to working correctly.

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

"target_overrides": {
    "*": {
        "platform.stdio-baud-rate": 115200
    },                        
    "NUCLEO_L476RG": {
        "target.clock_source": "USE_PLL_HSE_XTAL",
        "target.macros_remove": ["MBED_TICKLESS"],       
        "target.lpticker_lptim_clock": 4,
        "target.lpticker_lptim": 0
    },
    "NUCLEO_F401RE": {
        "target.clock_source": "USE_PLL_HSE_XTAL",
        "target.macros_remove": ["MBED_TICKLESS"],       
        "target.lpticker_lptim_clock": 4,
        "target.lpticker_lptim": 0
    },
    "NUCLEO_L152RE": {
        "target.clock_source": "USE_PLL_HSE_XTAL",
        "target.macros_remove": ["MBED_TICKLESS"],       
        "target.lpticker_lptim_clock": 4,
        "target.lpticker_lptim": 0
    }
}    

}

@LMESTM
Copy link
Contributor

LMESTM commented Nov 13, 2019

@star297 One preliminary question: have you modified the board to get an HSE XTAL mounted ?

@star297
Copy link
Contributor Author

star297 commented Nov 13, 2019

Yes both Xtals fitted, 8Mhz and 32Khz and are starting. I use RTC alarm registers for wake up that is also working correctly, wakes up on HSE.

Remember I'm using bare-bare metal OS rev.5.14.1 so in theory there should be no interference from RTOS or the Power Management API's, the other two targets in my mbed_app.json file are working correctly. Later I will test the rest of my ST boards.

I did have an issue before a couple of years age and I used a workaround code as below to achieve 3uA deepsleep by configuring the GPIO's registers before defining the pins, as below. Since then I don't know if this was resolved in later Mbed libraries.

#include "mbed.h"
#include "WakeUp.h"
 
void LowPowerConfiguration(void);
 
int main() { 
 
    LowPowerConfiguration();
 
// define pins after LowPowerConfiguration

    InterruptIn sw1(PC_13);
    DigitalOut led(LED1);
    Serial pc(PC_10, PC_11);
 
 
    while(1) {
        
        led=1;        
        wait_ms(1000);
        WakeUp::set_ms(4000);
        led=0;       
        deepsleep();
    }
}
 
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);
}

@kjbracey
Copy link
Contributor

You say it works in other targets, so this may not be relevant, but sleep shouldn't really be called directly even in a bare-metal build, as there are a bunch of subtleties about correct operation (assuming you want to wake up reliably).

Since 5.14, it's safer to use a higher-level RTOS-like call such as ThisThread::sleep_for(). (Add "rtos-api" to the requires list).

Bare metal or not sleep (or ThisThread:;sleep_for()), does still use the sleep manager deep sleep lock to autoselect between normal and deep sleep. Could be there's a deep sleep lock held.

To do a really low-level test bypassing everything and going strait to the HAL you can do

core_util_critical_section_enter();
for (;;) {
    hal_deepsleep();
}

Note that a single hal_sleep() or hal_deepsleep() call may return immediately, eg if there is pending serial TX data. A single sleep() may not be sufficient - you need to always call it in a loop. You can't assume that sleep() returning means your wake up interrupt has occurred. Again, ThisThread::sleep_for or EventFlags::wait_for will deal with all this for you.

For your example above, your WakeUp should set an event flag, and the main loop should wait for that event flag.

@LMESTM
Copy link
Contributor

LMESTM commented Nov 13, 2019

There are some hints here:
https://os.mbed.com/forum/mbed/topic/5863/
And I think this confirms @star297 comment about need for void LowPowerConfiguration(void);

I don't remember seeing any github issue about it before this one, and I don't think this has been solved. Actually I'm not sure how to apply this default configuration without messing up with application GPIO settings.

@star297 - I have verified that deep sleep is entered as expected as well on NUCLEO_L152RE, so could you check power consumption after calling void LowPowerConfiguration(void) ?

@star297
Copy link
Contributor Author

star297 commented Nov 13, 2019

I'll go through some tests tonight, but I'm surprised about the bare-metal, reading the very limited information I could find I got the impression that all RTOS thread type functions were not engaged. So not really sure. However the only reliable wake-up from deepsleep I can achieve is using interrupt from the RTC alarm registers to the extent of a L476 based application running for several months on battery power. This is using an earlier version of Mbed-2, and now with OS bare-metal its so far working reliably as well.

I'll try those suggestions....

@star297
Copy link
Contributor Author

star297 commented Nov 13, 2019

Calling void LowPowerConfiguration(void); as I have it shown above does actually work on OS(bare-metal build) just as it did before on Mbed-2.

Unfortunately I think this is pretty academic. When configuring GPIO pins the sleep IDD goes up in sleep mode so you would need to call that LowPowerConfiguration(void); again which wipes out the GPIO settings.

Unless these XDOT guys have missed a trick, it looks like it may be a pita. That's gonna take some clock cycles so short sleep functions would be pointless.

https://github.com/ARMmbed/mbed-os/blob/master/targets/TARGET_STM/TARGET_STM32L1/TARGET_XDOT_L151CC/xdot_low_power.c

In original example for the DISCO-L476;
https://os.mbed.com/teams/ST/code/DISCO_L476VG_Sleep/rev/3201a7da544e/

void LowPowerConfiguration(void);
Looks very similar and was removed and replaced with something in the Mbed library files.

@LMESTM
Copy link
Contributor

LMESTM commented Nov 14, 2019

I'm not sure we can easily handle this in a generic way.

I think that

  • The GPIOs that are used by application or drivers, need to be configured by those application and drivers: when the drivers aren't active they're supposed to select an optimized GPIOs configuration.
  • For the unused GPIOs, I think that application may configure them once at boot and later leave them untouched.

The core drivers don't / can't know what GPIOs are being or will be used or not.

@kjbracey
Copy link
Contributor

Not really following the details of the low power configuration for this chip, but...

Deep sleep as currently specified to the HAL is required to be transparent with respect to external GPIO - all GPIOs work as wake-up sources.

A more specific suspend API could limit the wake-up sources, and that could include a chance for the HAL to reconfigure the pins based on which (if any) GPIOs were wake-ups.

Beyond that, the HAL does which GPIOs have been configured (gpio_init). Until very recently (#11032 - not reached a release yet) there has been no gpio_free call to the HAL to deconfigure a pin. That call now exists, but I don't believe any C++ class uses that yet.

That could be part of the toolkit to get your power down.

reading the very limited information I could find I got the impression that all RTOS thread type functions were not engaged

This is a new facility in 5.14 - largely motivated by the desire to make sleeping and waking easy and reliable in bare-metal. See #10104.

@LMESTM
Copy link
Contributor

LMESTM commented Nov 14, 2019

It's not only about pins being used as GPIOs, we should not mess up with configuration of pins that have been configured as Alternate Peripheral Functions (I2C, UART, ..). Maintaining a dynamic list of those is not so straightforward.

Maybe could we consider adding a generic API or configuration scheme to let application provide a list of unused pins that need to be configured appropriately by HAL ?

@kjbracey
Copy link
Contributor

Maintaining a dynamic list of those is not so straightforward.

My thought is that for pinmapping it wouldn't need to be a dynamic list, it could just be reading and restoring alternate functions registers around the suspend operation. (Extreme hand-waving and glossing over fine detail detected).

@LMESTM
Copy link
Contributor

LMESTM commented Nov 14, 2019

My thought is that for pinmapping it wouldn't need to be a dynamic list, it could just be reading and restoring alternate functions registers around the suspend operation. (Extreme hand-waving and glossing over fine detail detected).

I am not sure whether you'd want to change the state of peripheral pins. The low power mode is Analog with no pull, but few peripherals may want to use Pull Up or Pull Down and keep them as well in Low Power in order to not impact the peripheral behavior ... don't you think ? Also some peripherals can be located in Always-on domain (like LP UART) and can be kept running or have wake-up capability which require their configuration to be maintained ... those are just thoughts but this makes me reluctant to change most of GPIOs states when suspending ..

@star297
Copy link
Contributor Author

star297 commented Nov 17, 2019

In a real life application I have using the L476 on a production board, there are 23 pins connected to various external devices including i2c, SPI and AnalogIn. In deepsleep mode the power is 140uA, that includes the connected devices. What is important is on start up the pin states are initialized in low power mode.
I found with the same pin set up on the L152 the power is 50uA (MCU only and using LowPowerConfiguration(void)).
Unless you want to drive the power right down then I would suggest to only implement the LowPowerConfiguration(void) code similar to what I have above just after RAM initialization as a minimum quick fix. At least then you can achieve a reasonable power saving during the sleep modes.

@LMESTM
Copy link
Contributor

LMESTM commented Nov 18, 2019

What is important is on start up the pin states are initialized in low power mode.
Unless you want to drive the power right down then I would suggest to only implement the LowPowerConfiguration(void) code similar to what I have above just after RAM initialization as a minimum quick fix. At least then you can achieve a reasonable power saving during the sleep modes.

Sounds like a plan. Let's keep this issue open to track this down.

@0xc0170
Copy link
Contributor

0xc0170 commented Nov 25, 2019

@LMESTM It's not clear to me what should be the outcome of this issue- what should be done to have this fixed.

Is this adding GPIO functionality to power down the pins - gpio_deinit ? IF that is the case, this should be treated as enhancement and provided via forum (it could be considered as a bug but wont be fixed via a bug fix , rather by adding a new functionality that addresses it).

@LMESTM
Copy link
Contributor

LMESTM commented Nov 25, 2019

@0xc0170 What I think is achievable is to apply a default low power configuration very early during init before the peripheral drivers get initialized. (to be checked by @ARMmbed/team-st-mcd )

@ARMmbed ARMmbed deleted a comment from ciarmcom Oct 6, 2020
@ciarmcom
Copy link
Member

@star297 thank you for raising this issue.Please take a look at the following comments:

Could you add some more detail to the description? A good description should be at least 25 words.

NOTE: If there are fields which are not applicable then please just add 'n/a' or 'None'.This indicates to us that at least all the fields have been considered.
Please update the issue header with the missing information, the issue will not be mirroredto our internal defect tracking system or investigated until this has been fully resolved.

@star297
Copy link
Contributor Author

star297 commented Oct 13, 2020

I suppose we need to finalize this.
I do not know what is in the pipeline for Mbed, perhaps this target is just too 'small' to worry about on V6 and moving on, and when will it become obsolete from a production and user angle?
The situation is with most of the STM targets from this era is that it is necessary to change the GPIO settings to achieve text book low power levels.
The XDOT vendors did have this hard coded in their Mbed library, I believe this is now depreciated on Mbed v6.
This really needs some input from ST to decide what they want to do, hopefully the R&D team at ST will have realized sleep modes must have GPIO conditions for low power 'built in' to the MCU design and not rely on time consuming software.
Otherwise tbh time to close this issue.

@LMESTM
Copy link
Contributor

LMESTM commented Oct 13, 2020

@jeromecoutant could we consider implementing proposal from #11853 (comment) ?

I would suggest to only implement the LowPowerConfiguration(void) code similar to what I have above just after RAM initialization as a minimum quick fix. At least then you can achieve a reasonable power saving during the sleep modes.

@adbridge
Copy link
Contributor

@LMESTM @jeromecoutant please let us know how you wish to proceed so we can determine what to do with this issue.

@jeromecoutant
Copy link
Collaborator

Hi
I propose this patch: 3fc77df

@star297
Copy link
Contributor Author

star297 commented Oct 16, 2020

Will it be necessary to re-define the GPIO pins on wake up using this patch?

@jeromecoutant
Copy link
Collaborator

This patch only affects boot.
Full test non regression is OK.

@ciarmcom
Copy link
Member

@star297 it has been 5 days since the last reminder. Could you please update the issue header as previously requested?

@star297
Copy link
Contributor Author

star297 commented Oct 19, 2020

Its as good as can be expected with most of the earlier (and perhaps current?) STM targets. Probably no problem with bare metal build as the user can call always call this GPIO_Full_Init(); before sleep functions and re initialise the GPIO's on wake up.
I have been using similar with good results.
Mainly useful for extended sleep periods to conserve power on battery operated applications. Not really usable in short Thread based sleep functions due to the MCU up time processing the GPIO switching.

If this update does get merged, please, please, document this somewhere in the Mbed v6 docs otherwise no one has a clue that it exists.

@ciarmcom
Copy link
Member

@star297 it has been 5 days since the last reminder. Could you please update the issue header as previously requested?

@star297 star297 changed the title STM32L152RE not going into deepsleep STM32L152RE deepsleep state power too high Oct 23, 2020
@ciarmcom
Copy link
Member

@star297 it has been 5 days since the last reminder. Could you please update the issue header as previously requested?

@star297 star297 closed this as completed Oct 28, 2020
@evandavey
Copy link
Contributor

@star297 - are there examples of the deinit / reinit functionality? I am experiencing this issue on a STM32L0 target with an SX126X. Deep sleep current is approx 50uA and I know with other frameworks this board can achieve 2uA. The SX126X driver has a number of digital outputs and uses SPI. If I manually set these pins (e.g. MISO.MOSI, SCLK) to AnalogIn on radio sleep, this falls to 7uA. This is a bit of a hack, not sure if there are global MBED before_sleep, on_wakeup functions that can be hook in as part of the sleep manager. I am not sure then how to re-initialise the pins (SPI in particular) on wakeup. Also, shouldn't this be a built-in functionality of peripheral drivers e.g. SPI to configure GPIOs to a low power state on sleep - would think this functionality requirement would be common among many targets.

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

Successfully merging a pull request may close this issue.

9 participants