I noticed that the deep sleep current differs between the two languages.
The deep sleep current I measured for MicroPython code is 10 µA and for Arduino code it is 40 µA.
This was very surprising to me, because I would asume that if one of them would be greater than the other it would be the deep sleep current of the MicroPython code.
I tried to look into this by digging in the source code, but I can’t seem to find why the currents aren't the same.
First of all here is the code that I used, it is just a simple program that puts the microcontroller to sleep for 1 second as soon as it wakes up:
This is the Arduino code:
Code: Select all
#include "STM32LowPower.h"
void setup() {
LowPower.begin();
}
void loop() {
LowPower.shutdown(1000);
}
Code: Select all
import machine
machine.deepsleep(1000)
Code: Select all
STATIC mp_obj_t machine_deepsleep(size_t n_args, const mp_obj_t *args) {
if (n_args != 0) {
mp_obj_t args2[2] = {MP_OBJ_NULL, args[0]};
pyb_rtc_wakeup(2, args2);
}
powerctrl_enter_standby_mode();
return mp_const_none;
}
Code: Select all
void powerctrl_enter_standby_mode(void) {
rtc_init_finalise();
#if defined(MICROPY_BOARD_ENTER_STANDBY)
MICROPY_BOARD_ENTER_STANDBY
#endif
// We need to clear the PWR wake-up-flag before entering standby, since
// the flag may have been set by a previous wake-up event. Furthermore,
// we need to disable the wake-up sources while clearing this flag, so
// that if a source is active it does actually wake the device.
// See section 5.3.7 of RM0090.
// Note: we only support RTC ALRA, ALRB, WUT and TS.
// TODO support TAMP and WKUP (PA0 external pin).
#if defined(STM32F0) || defined(STM32L0)
#define CR_BITS (RTC_CR_ALRAIE | RTC_CR_WUTIE | RTC_CR_TSIE)
#define ISR_BITS (RTC_ISR_ALRAF | RTC_ISR_WUTF | RTC_ISR_TSF)
#else
#define CR_BITS (RTC_CR_ALRAIE | RTC_CR_ALRBIE | RTC_CR_WUTIE | RTC_CR_TSIE)
#define ISR_BITS (RTC_ISR_ALRAF | RTC_ISR_ALRBF | RTC_ISR_WUTF | RTC_ISR_TSF)
#endif
// save RTC interrupts
uint32_t save_irq_bits = RTC->CR & CR_BITS;
// disable register write protection
RTC->WPR = 0xca;
RTC->WPR = 0x53;
// disable RTC interrupts
RTC->CR &= ~CR_BITS;
// clear RTC wake-up flags
RTC->ISR &= ~ISR_BITS;
#if defined(STM32F7)
// disable wake-up flags
PWR->CSR2 &= ~(PWR_CSR2_EWUP6 | PWR_CSR2_EWUP5 | PWR_CSR2_EWUP4 | PWR_CSR2_EWUP3 | PWR_CSR2_EWUP2 | PWR_CSR2_EWUP1);
// clear global wake-up flag
PWR->CR2 |= PWR_CR2_CWUPF6 | PWR_CR2_CWUPF5 | PWR_CR2_CWUPF4 | PWR_CR2_CWUPF3 | PWR_CR2_CWUPF2 | PWR_CR2_CWUPF1;
#elif defined(STM32H7)
EXTI_D1->PR1 = 0x3fffff;
PWR->WKUPCR |= PWR_WAKEUP_FLAG1 | PWR_WAKEUP_FLAG2 | PWR_WAKEUP_FLAG3 | PWR_WAKEUP_FLAG4 | PWR_WAKEUP_FLAG5 | PWR_WAKEUP_FLAG6;
#elif defined(STM32L4) || defined(STM32WB)
// clear all wake-up flags
PWR->SCR |= PWR_SCR_CWUF5 | PWR_SCR_CWUF4 | PWR_SCR_CWUF3 | PWR_SCR_CWUF2 | PWR_SCR_CWUF1;
// TODO
#else
// clear global wake-up flag
PWR->CR |= PWR_CR_CWUF;
#endif
// enable previously-enabled RTC interrupts
RTC->CR |= save_irq_bits;
// enable register write protection
RTC->WPR = 0xff;
#if defined(STM32F7)
// Enable the internal (eg RTC) wakeup sources
// See Errata 2.2.2 "Wakeup from Standby mode when the back-up SRAM regulator is enabled"
PWR->CSR1 |= PWR_CSR1_EIWUP;
#endif
// enter standby mode
HAL_PWR_EnterSTANDBYMode();
// we never return; MCU is reset on exit from standby
}
Then if we look at the Arduino implementation (it uses a library from github called STM32LowPower) we see that “LowPower.shutdown()” is implemented in STM32LowPower.cpp in STM32LowPower-master/src/. Like so:
Code: Select all
void STM32LowPower::shutdown(uint32_t ms)
{
if ((ms != 0) || _rtc_wakeup) {
programRtcWakeUp(ms, SHUTDOWN_MODE);
}
LowPower_shutdown();
}
Code: Select all
void LowPower_shutdown()
{
__disable_irq();
#if defined(STM32L4xx) || defined(STM32L5xx)
/* LSE must be on to use shutdown mode */
if (__HAL_RCC_GET_FLAG(RCC_FLAG_LSERDY) == SET) {
HAL_PWREx_EnterSHUTDOWNMode();
} else
#endif
{
LowPower_standby();
}
}
Code: Select all
void LowPower_standby()
{
__disable_irq();
#if defined(STM32L0xx) || defined(STM32L1xx)
/* Enable Ultra low power mode */
HAL_PWREx_EnableUltraLowPower();
/* Enable the fast wake up from Ultra low power mode */
HAL_PWREx_EnableFastWakeUp();
#endif
HAL_PWR_EnterSTANDBYMode();
}
So my question is why do the deep sleep currents differ. Both the MicroPython and Arduino code call this “HAL_PWR_EnterSTANDBYMode()” function. Which is one of the Hardware Abstraction Layer functions provided by STM to get into the 'standby low-power mode'.
So one would think that the deep sleep current would be exactly the same. But it isn’t, so does anyone know why this is the case?