current in deepSleep mode STM32F103C8, STM32F401CC

Post here first, or if you can't find a relevant section!
rudi
Posts: 6
Joined: Fri Nov 10, 2023 8:45 am

current in deepSleep mode STM32F103C8, STM32F401CC

Post by rudi »

Hi,
I'm new to this forum and hope this question is at the right place.

In an OpenSource project we are developing some hardware gathering data on beehives.
These are lowpower systems so that they can run on battery for a long time.
This works very well with STM32F103C8 (Blue Pill) or STM32F401 (Black Pill) module when using shutdown modes.
We are using Arduino IDE 1.8.19 or 2.2.1, STM32 MCU Boards Ver. 2.6, STM32LowPower (1.2.4) and STM32RTC (1.3.7) libs.

With the example sketch "AlarmTimedWakeup" and "TimedWakeup" the current drawn by the complete setup is about 10uA to 30uA
using LowPower.shutdown() instead of LowPower.deepSleep().
Using LowPower.deepSleep() with the STM32F103 (Blue Pill) the current is still within the range of some 10uA.
The excact same sketch in the STM32F401 (Black Pill) needs a current of about 1,5mA, which is far to high for a battery powerd system.

Obviously there seems to be a major difference how the STM32F401 handles the deepSleep mode.
The questions are:
Are we doing something wrong?
Could the current drawn by the STM32F4 reduced with some additional coding?
I tried to get some infos on that searching several forums and going through the STM32F4 HAL documentation.
But, sorry, I didn't find the clue yet. May be I don't have enough not knowledge to get things together.

Any help or hint is appreciated.
Thanks.
rudi
Posts: 6
Joined: Fri Nov 10, 2023 8:45 am

Re: current in deepSleep mode STM32F103C8, STM32F401CC

Post by rudi »

Some additional information:
the power-led is removed from the BluePill, BlackPill module
the sketch has been modified so that the builtin-led is turned off when in sleep mode
geologic
Posts: 10
Joined: Thu Dec 15, 2022 10:12 am
Answers: 1

Re: current in deepSleep mode STM32F103C8, STM32F401CC

Post by geologic »

How are you powering the devices?
Blackpill have AP7343 regulator, Bluepill have TX6211B regulator, check the datasheet.
sallowrate
Posts: 1
Joined: Wed Nov 15, 2023 4:38 am

Re: current in deepSleep mode STM32F103C8, STM32F401CC

Post by sallowrate »

The STM32F103 (Blue Pill) with LowPower.deepSleep() allow the current to remain within a range of roughly 10uA. Is it possible to lower the current that the STM32F4 draws when performing further encoding?
rudi
Posts: 6
Joined: Fri Nov 10, 2023 8:45 am

Re: current in deepSleep mode STM32F103C8, STM32F401CC

Post by rudi »

The modules are powered through a MCP1702-33 which has an quiescent current of about 2uA.
There is no difference in powering the STM32F401 in shutdown or deepsleep mode.
If there would be a current from a voltage regulator, I expect it to be always there.
But when having the STM32F401 in shutdown the whole setup needs 20uA.Therefore I assume in deepsleep the STM32F401 itself causes the 1.5milliAmp.

In this thread is mentioned that using the Arduino IDE that some peripherials are turned on by default.
viewtopic.php?t=1921

Therefore I tried to disable them using the information given here:
https://github.com/stm32duino/Arduino_C ... figuration
So far no success.

This is my sketch for testing the LowPower modes, They are based on the examples given in the STM32RTC and STM32LowPower libraries.

Code: Select all

#include "hal_conf_extra.h"
#include <STM32LowPower.h>
#include <STM32RTC.h>
/****************************************************************/
#define  _SLEEP_MODE_   2  // 2 = DEEP_SLEEP_MODE, 3 = SHUTDOWN_MODE

#define  WakeUp_Pin   PA0  //  STM32 Shutdown Wakeup Pin
#define  Pin_WkUp     PA15 //  another Pin to Wkup in DeepSleep Mode
/****************************************************************/
uint32_t rtc_var = 0;
uint32_t ok_sleep = 1;

STM32RTC& rtc_stm = STM32RTC::getInstance(); /*Get the rtc object */

void setup() {

  blink_LED(_SLEEP_MODE_ + 1, 300);
  //----------------------------------------------------------------
  rtc_stm.setClockSource(STM32RTC::LSE_CLOCK);  // 32kHz source for RTC
  rtc_stm.begin(false);                         // initialize RTC 24H format
  rtc_stm.disableAlarm();                       //  may be User WakeupPin Interrupt, disable rtc Alarm
  LowPower.begin();
  LowPower.enableWakeupFrom(&rtc_stm, WakeUpRTC, &rtc_var );
  //----------------------------------------------------------------

  //pinMode(WakeUp_Pin, INPUT_PULLDOWN); // Prepare WakeUp pin PA0   //  a real pull-down-resistor should be used
#if _SLEEP_MODE_ == 2  // DEEP_SLEEP_MODE
  LowPower.attachInterruptWakeup(WakeUp_Pin, WakeUp, RISING, DEEP_SLEEP_MODE);
  // pinMode(Pin_WakeUp, INPUT);       // Prepare WakeUp pin,  a real pull-down-resistor should be used
  // LowPower.attachInterruptWakeup(Pin_WkUp, Pin_WakeUp, FALLING, DEEP_SLEEP_MODE);  // the other Pin to wake up
#endif
#if _SLEEP_MODE_ == 3  // SHUTDOWN_MODE
  LowPower.attachInterruptWakeup(WakeUp_Pin, WakeUp, RISING, SHUTDOWN_MODE);
#endif
}

void loop() {
  uint32_t tt = rtc_stm.getEpoch() + 120;  // every two minutes
  rtc_stm.setAlarmEpoch(tt);

#if _SLEEP_MODE_ == 2  // DEEP_SLEEP_MODE  / STOP-Mode
  LowPower.deepSleep();
#endif
#if _SLEEP_MODE_ == 3
  LowPower.shutdown(); // SHUTDOWN / STANDBY-Mode
#endif

  __HAL_RCC_CLEAR_RESET_FLAGS();
  /* Check if the system was resumed from StandBy mode */
  if (__HAL_PWR_GET_FLAG(PWR_FLAG_SB) != RESET) {
    /* Clear Standby flag */
    __HAL_PWR_CLEAR_FLAG(PWR_FLAG_SB);
  }

  /* Clear all related wakeup flags */
  __HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);

  blink_LED(ok_sleep + 1, 300);
}

void WakeUp() {
  ok_sleep = 2;
}

void Pin_WakeUp() {
  ok_sleep = 1;
}

void WakeUpRTC(void * data) {
  //UNUSED(data);
  ok_sleep = 3;
}

void blink_LED(uint8_t nmr, uint16_t bl_tm) {
  pinMode(PC13, OUTPUT);
  for (int i = 0; i < nmr; i++) {
    digitalWrite(PC13, LOW);  delay(bl_tm); // LED an
    digitalWrite(PC13, HIGH);  delay(bl_tm);
  }
  pinMode(PC13, INPUT);
}
This is the hal_conf_extra.h:

Code: Select all

#define HAL_ADC_MODULE_DISABLED
#define HAL_I2C_MODULE_DISABLED
#define HAL_SPI_MODULE_DISABLED
#define HAL_DAC_MODULE_DISABLED
#define HAL_TIM_MODULE_DISABLED
#define HAL_DAC_MODULE_DISABLED


Most of these functions like, ADC, serial, I2C are needed by the application, they need to turned off just before entering deepSleep.
The question is what is responsible for the high current and what to code to turn them off and when waking up to turn them on.
ag123
Posts: 1653
Joined: Thu Dec 19, 2019 5:30 am
Answers: 24

Re: current in deepSleep mode STM32F103C8, STM32F401CC

Post by ag123 »

if you have an external module such as a TFT LCD that can consume a lot of power, independent of stm32.

The peripherals ADC/i2c etc when they are clocked consume power, if you want to turn off the peripherals, you would need to un-clock them.
The downside is that on resume, you would need to restore all the clocks and re-configure the peripherals

for what is worth, these days NiMh and Li-ion batteries can hold quite a lot of charged capacity, e.g. a 18650 can hold like 3500 mAh
this can even keep low usage apps running without sleeping for several days to a week, and deep sleep perhaps consume few mA can last a pretty long time.

For apps that don't sleep, in place of delay(), i tend to use

Code: Select all

asm("wfi");
that waits for the systick (actually any) interrupt every milli-second, that is useful in loop() that doesn't need to be very active.
it made loop() runs once every milli-second that results in a cooler cpu and lower power consumption.
rudi
Posts: 6
Joined: Fri Nov 10, 2023 8:45 am

Re: current in deepSleep mode STM32F103C8, STM32F401CC

Post by rudi »

@ag123:
the tests using the sketch shown in the post is made only using the STM32F401 module (WeAct BlackPill).
There are no peripherials that may consume any current. All pins of the STM32F4 are set to input, if they have been used, i.e. for the LED.

I don't understand why ADC or I2C need to bee unclocked, because they are diabled using the hal_conf_extra.h.
Unclocking may be necessary later on the application sketch, but at the moment with the test sketch I try to find out what causes the current consumption.

I thought this call asm"wfi" is made by the libaries/packets for STM32F4 when using LowPower lib.

Code: Select all

asm("wfi");
And why should I replace delay with this?
In the sketch (test and application) the STM32F401 is waiting for an RTC Alarm or a signal at PA0.
Other than that, the STM32F4 has nothing to do.
This works very well, when using LowPower.shutdown().
In order to have another pin like PA15 as wakeup source I intend to / must use LowPower.deepSleep.

Due to communication that is done every some hours via GSM or LTE for some 10 seconds even with an Li-Ion Battery at 3500mAh and solar powered recharging having a constant current of about 1.5mA is to much. This is our expirience having some thousand systems in the field for some years now.
Of a very large solar panel could be used, but during winter time this is not the solution.
Older systems are based on atmega328, but the functionality of the system is growing and doens't fit in this controller anymore.
ag123
Posts: 1653
Joined: Thu Dec 19, 2019 5:30 am
Answers: 24

Re: current in deepSleep mode STM32F103C8, STM32F401CC

Post by ag123 »

for low power, normally it means putting the processor in 'suspended' mode, where the cpu is turned off until a 'wakeup' event is triggered, e.g. from a pin.
i've not tried working with low power, hence won't be good to comment much about it.
But that as I'm aware, there are options for 'sleep' modes, where for some modes sram is maintained so the state is maintained when 'wakeup' is triggered.
then there may be some 'deep sleep' modes, where perhaps sram is not maintained, and handling 'wakeup' event practically is like a reset.
hardware wise, I think peripherals e.g. ADC, I2C, GPIO etc are independently clocked. Hence, to *shutdown*, the peripherals, is to *unclock* them, but that all the states and configuration is lost and on wakeup event, the peripherals clocks needs to be setup again and configuration re-done.
that may help for truly low power setup.

with asm("wfi")' the processor is not doing any of the 'suspended' mode, it is actually running normally.
e.g. with codes like

Code: Select all

void setup() {
  // initialization codes
}

void loop() {
  call_function1();
  call_function2();
  
  asm("wfi");
}
this actually depends on a 'trick' as systick is configured to trigger *every millisecond*, normally it is used to keep time for millis() function and perhaps delay() function.
so that with asm("wfi");, the cpu would *sleep* until the next interrupt, which can be the systick interrupt or any other interrupt.
this would reduce the cpu to only process every milli second (or earlier if there is any other interrupt) instead of starting loop() immediately.
I've done some tests by checking the on-chip temperature, it runs cooler, therefore use less power with asm("wfi");.
But that this isn't 'low power' by any means, it simply reduce power consumption for those loop(), that doesn't need to run faster than once every millisecond.

I think it is quite possible that going the distance and disable systick (hence no millis()) may save even more power in regular run mode.
but that asm("wfi"); would then depend on an aribtrary interrupt that you configure / define. e.g. RTC (every second), a timer, exti etc.
keeping systick is useful to keep loop() running regularly with asm("wfi");.
It is quite possible one can write some sort of 'RTOS' and perform context switching in loop() in that sense as well.
e.g. this little 'event loop'
https://github.com/ag88/stm32duino-eventloop
rudi
Posts: 6
Joined: Fri Nov 10, 2023 8:45 am

Re: current in deepSleep mode STM32F103C8, STM32F401CC

Post by rudi »

Sorry ag123, I don't get the point from your explanations.
From my point a view it is not adressing the question using true lowpower states of the STM32F4x1 I have.
Just using asm "wfi" doesn't help any, because real LowPower is a lot more than that.
Al least that is my interpretation when loooking at the LowPower-Libraries.
Why should I implement another event loop, when the arduino framework has already a loop, that does all that is needed.
This has been proven already.

The important question is:
What causes the STM32F4x1 the current of about 1,5mA in deepSleep, i.e. STM32 Stop mode as of the datasheet?
Whereas LowPower.shutdown() is STM32 Standby Mode which causes a reset
https://github.com/stm32duino/STM32LowPower

In the Sketch the peripherials like ADC/I2C should have been shut of, according to:
https://github.com/stm32duino/Arduino_C ... figuration

May be I need to modify the LowPower-Lib?
ag123
Posts: 1653
Joined: Thu Dec 19, 2019 5:30 am
Answers: 24

Re: current in deepSleep mode STM32F103C8, STM32F401CC

Post by ag123 »

among the possibilities, peripherals e.g. ADC, USB, GPIO etc if they are clocked could be in a 'running state' even if they are 'disabled'
https://github.com/stm32duino/Arduino_C ... x.cpp#L125

Hence, I'd guess it'd help to review the ref manual e.g. rm0008, RCC section on the peripheral clocks
https://www.st.com/resource/en/referenc ... ronics.pdf

to see if you could 'turn off the peripheral clocks'.
a downside is that would 'shutdown' the peripherals, and hence need to re-clock and re-configure them on resume/wake-up.

hope that helps.
Post Reply

Return to “General discussion”