diff --git a/README.md b/README.md
index 5e68e00..223d7ee 100644
--- a/README.md
+++ b/README.md
@@ -3,23 +3,24 @@ Arduino library to support STM32 Low Power.
## Requirement
* [Arduino_Core_STM32](https://github.com/stm32duino/Arduino_Core_STM32) version >= 1.3.0
- * [STM32RTC](https://github.com/stm32duino/STM32RTC)
## API
* **`void begin()`**: configure the Low Power
-* **`void idle(uint32_t millis)`**: enter in idle mode
-**param** millis (optional): number of milliseconds before to exit the mode. At least 1000 ms. The RTC is used in alarm mode to wakeup the chip in millis milliseconds.
+* **`void idle(uint32_t ms)`**: enter in idle mode
+**param** ms (optional): number of milliseconds before to exit the mode. The RTC is used in alarm mode to wakeup the chip in ms milliseconds.
-* **`void sleep(uint32_t millis)`**: enter in sleep mode
-**param** millis (optional): number of milliseconds before to exit the mode. At least 1000 ms. The RTC is used in alarm mode to wakeup the chip in millis milliseconds.
+* **`void sleep(uint32_t ms)`**: enter in sleep mode
+**param** ms (optional): number of milliseconds before to exit the mode. he RTC is used in alarm mode to wakeup the chip in ms milliseconds.
-* **`void deepSleep(uint32_t millis)`**: enter in deepSleep mode
-**param** millis (optional): number of milliseconds before to exit the mode. At least 1000 ms. The RTC is used in alarm mode to wakeup the chip in millis milliseconds.
+* **`void deepSleep(uint32_t ms)`**: enter in deepSleep mode
+**param** ms (optional): number of milliseconds before to exit the mode. The RTC is used in alarm mode to wakeup the chip in ms milliseconds.
-* **`void shutdown(uint32_t millis)`**: enter in shutdown mode
-**param** millis (optional): number of milliseconds before to exit the mode. At least 1000 ms. The RTC is used in alarm mode to wakeup the board in millis milliseconds.
+* **`void shutdown(uint32_t ms)`**: enter in shutdown mode
+**param** ms (optional): number of milliseconds before to exit the mode. The RTC is used in alarm mode to wakeup the board in ms milliseconds.
+
+**Note: With [STM32RTC](https://github.com/stm32duino/STM32RTC) version lower than 1.1.0, the minimum number of milliseconds is 1000 ms.**
* **`void attachInterruptWakeup(uint32_t pin, voidFuncPtrVoid callback, uint32_t mode)`**: Enable GPIO pin in interrupt mode. If the pin is a wakeup pin, it is configured as wakeup source (see board documentation).
**param** pin: pin number
diff --git a/examples/AlarmTimedWakeup/AlarmTimedWakeup.ino b/examples/AlarmTimedWakeup/AlarmTimedWakeup.ino
index 625f511..4204b6f 100644
--- a/examples/AlarmTimedWakeup/AlarmTimedWakeup.ino
+++ b/examples/AlarmTimedWakeup/AlarmTimedWakeup.ino
@@ -17,8 +17,14 @@
/* Get the rtc object */
STM32RTC& rtc = STM32RTC::getInstance();
+#if defined(STM32_RTC_VERSION) && (STM32_RTC_VERSION >= 0x01010000)
+/* Change this value to set alarm match offset in millisecond */
+/* Note that STM32F1xx does not manage subsecond only second */
+static uint32_t atime = 567;
+#else
// Time in second between blink
static uint32_t atime = 1;
+#endif
// Declare it volatile since it's incremented inside an interrupt
volatile int alarmMatch_counter = 0;
@@ -41,21 +47,21 @@ void setup() {
pinMode(LED_BUILTIN, OUTPUT);
Serial.begin(9600);
- while(!Serial) {}
+ while (!Serial) {}
// Configure low power
LowPower.begin();
LowPower.enableWakeupFrom(&rtc, alarmMatch, &atime);
// Configure first alarm in 2 second then it will be done in the rtc callback
- rtc.setAlarmEpoch( rtc.getEpoch() + 2 );
+ rtc.setAlarmEpoch( rtc.getEpoch() + 2);
}
void loop() {
Serial.print("Alarm Match: ");
Serial.print(alarmMatch_counter);
Serial.println(" times.");
- delay(100);
+ Serial.flush();
digitalWrite(LED_BUILTIN, HIGH);
LowPower.deepSleep();
digitalWrite(LED_BUILTIN, LOW);
@@ -67,6 +73,41 @@ void alarmMatch(void* data)
// This function will be called once on device wakeup
// You can do some little operations here (like changing variables which will be used in the loop)
// Remember to avoid calling delay() and long running functions since this functions executes in interrupt context
+#if defined(STM32_RTC_VERSION) && (STM32_RTC_VERSION >= 0x01010000)
+ uint32_t epoc;
+ uint32_t epoc_ms;
+ uint32_t sec = 0;
+ uint32_t _millis = 1000;
+
+ if (data != NULL) {
+ _millis = *(uint32_t*)data;
+ // Minimum is 1 second
+ if (sec == 0) {
+ sec = 1;
+ }
+ }
+
+ sec = _millis / 1000;
+#ifdef STM32F1xx
+ // Minimum is 1 second
+ if (sec == 0) {
+ sec = 1;
+ }
+ epoc = rtc.getEpoch(&epoc_ms);
+#else
+ _millis = _millis % 1000;
+ epoc = rtc.getEpoch(&epoc_ms);
+
+ //Update epoch_ms - might need to add a second to epoch
+ epoc_ms += _millis;
+ if (epoc_ms >= 1000) {
+ sec ++;
+ epoc_ms -= 1000;
+ }
+#endif
+ alarmMatch_counter++;
+ rtc.setAlarmEpoch(epoc + sec, STM32RTC::MATCH_SS, epoc_ms);
+#else
uint32_t sec = 1;
if(data != NULL) {
sec = *(uint32_t*)data;
@@ -77,5 +118,5 @@ void alarmMatch(void* data)
}
alarmMatch_counter++;
rtc.setAlarmEpoch( rtc.getEpoch() + sec);
+#endif
}
-
diff --git a/library.properties b/library.properties
index 995a912..ccd31be 100644
--- a/library.properties
+++ b/library.properties
@@ -1,5 +1,5 @@
name=STM32duino Low Power
-version=1.0.3
+version=1.1.0
author=Wi6Labs
maintainer=stm32duino
sentence=Power save primitives features for STM32 boards
diff --git a/src/STM32LowPower.cpp b/src/STM32LowPower.cpp
index f205373..a0d96db 100644
--- a/src/STM32LowPower.cpp
+++ b/src/STM32LowPower.cpp
@@ -1,15 +1,13 @@
/**
******************************************************************************
* @file STM32LowPower.cpp
-* @author WI6LABS
-* @version V1.0.0
-* @date 11-December-2017
+* @author Frederic Pillon
* @brief Provides a STM32 Low Power interface with Arduino
*
******************************************************************************
* @attention
*
-*
© COPYRIGHT(c) 2017 STMicroelectronics
+* © COPYRIGHT(c) 2020 STMicroelectronics
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
@@ -62,13 +60,13 @@ void STM32LowPower::begin(void)
/**
* @brief Enable the idle low power mode (STM32 sleep). Exit this mode on
* interrupt or in n milliseconds.
- * @param millis: optional delay before leave the idle mode (default: 0).
+ * @param ms: optional delay before leave the idle mode (default: 0).
* @retval None
*/
-void STM32LowPower::idle(uint32_t millis)
+void STM32LowPower::idle(uint32_t ms)
{
- if ((millis > 0) || _rtc_wakeup) {
- programRtcWakeUp(millis, IDLE_MODE);
+ if ((ms != 0) || _rtc_wakeup) {
+ programRtcWakeUp(ms, IDLE_MODE);
}
LowPower_sleep(PWR_MAINREGULATOR_ON);
}
@@ -76,13 +74,13 @@ void STM32LowPower::idle(uint32_t millis)
/**
* @brief Enable the sleep low power mode (STM32 sleep). Exit this mode on
* interrupt or in n milliseconds.
- * @param millis: optional delay before leave the sleep mode (default: 0).
+ * @param ms: optional delay before leave the sleep mode (default: 0).
* @retval None
*/
-void STM32LowPower::sleep(uint32_t millis)
+void STM32LowPower::sleep(uint32_t ms)
{
- if ((millis > 0) || _rtc_wakeup) {
- programRtcWakeUp(millis, SLEEP_MODE);
+ if ((ms != 0) || _rtc_wakeup) {
+ programRtcWakeUp(ms, SLEEP_MODE);
}
LowPower_sleep(PWR_LOWPOWERREGULATOR_ON);
}
@@ -90,13 +88,13 @@ void STM32LowPower::sleep(uint32_t millis)
/**
* @brief Enable the deepsleep low power mode (STM32 stop). Exit this mode on
* interrupt or in n milliseconds.
- * @param millis: optional delay before leave the deepSleep mode (default: 0).
+ * @param ms: optional delay before leave the deepSleep mode (default: 0).
* @retval None
*/
-void STM32LowPower::deepSleep(uint32_t millis)
+void STM32LowPower::deepSleep(uint32_t ms)
{
- if ((millis > 0) || _rtc_wakeup) {
- programRtcWakeUp(millis, DEEP_SLEEP_MODE);
+ if ((ms != 0) || _rtc_wakeup) {
+ programRtcWakeUp(ms, DEEP_SLEEP_MODE);
}
LowPower_stop(_serial);
}
@@ -104,13 +102,13 @@ void STM32LowPower::deepSleep(uint32_t millis)
/**
* @brief Enable the shutdown low power mode (STM32 shutdown or standby mode).
* Exit this mode on interrupt or in n milliseconds.
- * @param millis: optional delay before leave the shutdown mode (default: 0).
+ * @param ms: optional delay before leave the shutdown mode (default: 0).
* @retval None
*/
-void STM32LowPower::shutdown(uint32_t millis)
+void STM32LowPower::shutdown(uint32_t ms)
{
- if ((millis > 0) || _rtc_wakeup) {
- programRtcWakeUp(millis, SHUTDOWN_MODE);
+ if ((ms != 0) || _rtc_wakeup) {
+ programRtcWakeUp(ms, SHUTDOWN_MODE);
}
LowPower_shutdown();
}
@@ -169,13 +167,13 @@ void STM32LowPower::enableWakeupFrom(STM32RTC *rtc, voidFuncPtr callback, void *
/**
* @brief Configure the RTC alarm
- * @param millis: time of the alarm in milliseconds. At least 1000ms.
+ * @param ms: time of the alarm in milliseconds.
* @param lp_mode: low power mode targeted.
* @retval None
*/
-void STM32LowPower::programRtcWakeUp(uint32_t millis, LP_Mode lp_mode)
+void STM32LowPower::programRtcWakeUp(uint32_t ms, LP_Mode lp_mode)
{
- int epoc;
+ uint32_t epoc;
uint32_t sec;
STM32RTC &rtc = STM32RTC::getInstance();
STM32RTC::Source_Clock clkSrc = rtc.getClockSource();
@@ -201,15 +199,31 @@ void STM32LowPower::programRtcWakeUp(uint32_t millis, LP_Mode lp_mode)
}
rtc.configForLowPower(clkSrc);
- if (millis > 0) {
+ if (ms != 0) {
// Convert millisecond to second
- sec = millis / 1000;
+ sec = ms / 1000;
+
+#if defined(STM32_RTC_VERSION) && (STM32_RTC_VERSION >= 0x01010000)
+ uint32_t epoc_ms;
+ ms = ms % 1000;
+ epoc = rtc.getEpoch(&epoc_ms);
+
+ //Update epoch_ms - might need to add a second to epoch
+ epoc_ms += ms;
+ if (epoc_ms >= 1000) {
+ sec ++;
+ epoc_ms -= 1000;
+ }
+
+ rtc.setAlarmEpoch(epoc + sec, STM32RTC::MATCH_DHHMMSS, epoc_ms);
+#else
// Minimum is 1 second
if (sec == 0) {
sec = 1;
}
-
epoc = rtc.getEpoch();
+
rtc.setAlarmEpoch(epoc + sec);
+#endif
}
}
diff --git a/src/STM32LowPower.h b/src/STM32LowPower.h
index 8c39d81..69be1c0 100644
--- a/src/STM32LowPower.h
+++ b/src/STM32LowPower.h
@@ -1,15 +1,13 @@
/**
******************************************************************************
* @file STM32LowPower.h
-* @author WI6LABS
-* @version V1.0.0
-* @date 11-December-2017
+* @author Frederic Pillon
* @brief Provides a STM32 Low Power interface with Arduino
*
******************************************************************************
* @attention
*
-* © COPYRIGHT(c) 2017 STMicroelectronics
+* © COPYRIGHT(c) 2020 STMicroelectronics
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
@@ -41,6 +39,10 @@
#include
+#if defined(STM32_CORE_VERSION) && (STM32_CORE_VERSION > 0x01090000)
+ #include "low_power.h"
+#endif
+
// Check if PWR HAL enable in variants/board_name/stm32yzxx_hal_conf.h
#ifndef HAL_PWR_MODULE_ENABLED
#error "PWR configuration is missing. Check flag HAL_PWR_MODULE_ENABLED in variants/board_name/stm32yzxx_hal_conf.h"
@@ -64,28 +66,28 @@ class STM32LowPower {
void begin(void);
- void idle(uint32_t millis = 0);
- void idle(int millis)
+ void idle(uint32_t ms = 0);
+ void idle(int ms)
{
- idle((uint32_t)millis);
+ idle((uint32_t)ms);
}
- void sleep(uint32_t millis = 0);
- void sleep(int millis)
+ void sleep(uint32_t ms = 0);
+ void sleep(int ms)
{
- sleep((uint32_t)millis);
+ sleep((uint32_t)ms);
}
- void deepSleep(uint32_t millis = 0);
- void deepSleep(int millis)
+ void deepSleep(uint32_t ms = 0);
+ void deepSleep(int ms)
{
- deepSleep((uint32_t)millis);
+ deepSleep((uint32_t)ms);
}
- void shutdown(uint32_t millis = 0);
- void shutdown(int millis)
+ void shutdown(uint32_t ms = 0);
+ void shutdown(int ms)
{
- shutdown((uint32_t)millis);
+ shutdown((uint32_t)ms);
}
void attachInterruptWakeup(uint32_t pin, voidFuncPtrVoid callback, uint32_t mode, LP_Mode LowPowerMode = SHUTDOWN_MODE);
@@ -97,7 +99,7 @@ class STM32LowPower {
bool _configured; // Low Power mode initialization status
serial_t *_serial; // Serial for wakeup from deep sleep
bool _rtc_wakeup; // Is RTC wakeup?
- void programRtcWakeUp(uint32_t millis, LP_Mode lp_mode);
+ void programRtcWakeUp(uint32_t ms, LP_Mode lp_mode);
};
extern STM32LowPower LowPower;
diff --git a/src/low_power.c b/src/low_power.c
new file mode 100644
index 0000000..54774fe
--- /dev/null
+++ b/src/low_power.c
@@ -0,0 +1,362 @@
+/**
+ ******************************************************************************
+ * @file LowPower.c
+ * @author Frederic Pillon
+ * @brief Provides a Low Power interface
+ *
+ ******************************************************************************
+ * @attention
+ *
+ * © COPYRIGHT(c) 2020 STMicroelectronics
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of STMicroelectronics nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ******************************************************************************
+ */
+
+#include "Arduino.h"
+#include "low_power.h"
+
+#if defined(STM32_CORE_VERSION) && (STM32_CORE_VERSION > 0x01090000) &&\
+ defined(HAL_PWR_MODULE_ENABLED) && !defined(HAL_PWR_MODULE_ONLY)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(UART_IT_WUF) && defined(HAL_UART_MODULE_ENABLED) && !defined(HAL_UART_MODULE_ONLY)
+/* Save UART handler for callback */
+static UART_HandleTypeDef *WakeUpUart = NULL;
+#endif
+/* Save callback pointer */
+static void (*WakeUpUartCb)(void) = NULL;
+
+#ifdef STM32G0xx
+#define PWR_FLAG_WU PWR_FLAG_WUF
+#endif
+
+/**
+ * @brief Initialize low power mode
+ * @param None
+ * @retval None
+ */
+void LowPower_init()
+{
+#if !defined(STM32H7xx) && !defined(STM32MP1xx) && !defined(STM32WBxx)
+ /* Enable Power Clock */
+ __HAL_RCC_PWR_CLK_ENABLE();
+#endif
+ /* Allow access to Backup domain */
+ HAL_PWR_EnableBkUpAccess();
+
+#ifdef __HAL_RCC_WAKEUPSTOP_CLK_CONFIG
+ /* Ensure that HSI is wake-up system clock */
+ __HAL_RCC_WAKEUPSTOP_CLK_CONFIG(RCC_STOP_WAKEUPCLOCK_HSI);
+#endif
+ /* 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);
+}
+
+/**
+ * @brief Configure a pin as wakeup source if compatible.
+ * @param pin: pin to configure
+ * @param mode: pin mode (edge or state). The configuration have to be compatible.
+ * @retval None
+ */
+void LowPower_EnableWakeUpPin(uint32_t pin, uint32_t mode)
+{
+#if !defined(PWR_WAKEUP_PIN1_HIGH)
+ UNUSED(mode);
+#endif
+ uint32_t wkup_pin;
+ PinName p = digitalPinToPinName(pin);
+ if (p != NC) {
+ switch (p) {
+ default :
+#ifdef PWR_WAKEUP_PIN1
+ case SYS_WKUP1 :
+ wkup_pin = PWR_WAKEUP_PIN1;
+#ifdef PWR_WAKEUP_PIN1_HIGH
+ if (mode != RISING) {
+ wkup_pin = PWR_WAKEUP_PIN1_LOW;
+ }
+#endif
+ break;
+#endif /* PWR_WAKEUP_PIN1 */
+#ifdef PWR_WAKEUP_PIN2
+ case SYS_WKUP2 :
+ wkup_pin = PWR_WAKEUP_PIN2;
+#ifdef PWR_WAKEUP_PIN2_HIGH
+ if (mode != RISING) {
+ wkup_pin = PWR_WAKEUP_PIN2_LOW;
+ }
+#endif
+ break;
+#endif /* PWR_WAKEUP_PIN2 */
+#ifdef PWR_WAKEUP_PIN3
+ case SYS_WKUP3 :
+ wkup_pin = PWR_WAKEUP_PIN3;
+#ifdef PWR_WAKEUP_PIN3_HIGH
+ if (mode != RISING) {
+ wkup_pin = PWR_WAKEUP_PIN3_LOW;
+ }
+#endif
+ break;
+#endif /* PWR_WAKEUP_PIN3 */
+#ifdef PWR_WAKEUP_PIN4
+ case SYS_WKUP4 :
+ wkup_pin = PWR_WAKEUP_PIN4;
+#ifdef PWR_WAKEUP_PIN4_HIGH
+ if (mode != RISING) {
+ wkup_pin = PWR_WAKEUP_PIN4_LOW;
+ }
+#endif
+ break;
+#endif /* PWR_WAKEUP_PIN4 */
+#ifdef PWR_WAKEUP_PIN5
+ case SYS_WKUP5 :
+ wkup_pin = PWR_WAKEUP_PIN5;
+#ifdef PWR_WAKEUP_PIN5_HIGH
+ if (mode != RISING) {
+ wkup_pin = PWR_WAKEUP_PIN5_LOW;
+ }
+#endif
+ break;
+#endif /* PWR_WAKEUP_PIN5 */
+#ifdef PWR_WAKEUP_PIN6
+ case SYS_WKUP6 :
+ wkup_pin = PWR_WAKEUP_PIN6;
+#ifdef PWR_WAKEUP_PIN6_HIGH
+ if (mode != RISING) {
+ wkup_pin = PWR_WAKEUP_PIN6_LOW;
+ }
+#endif
+ break;
+#endif /* PWR_WAKEUP_PIN6 */
+#ifdef PWR_WAKEUP_PIN7
+ case SYS_WKUP7 :
+ wkup_pin = PWR_WAKEUP_PIN7;
+ break;
+#endif /* PWR_WAKEUP_PIN7 */
+#ifdef PWR_WAKEUP_PIN8
+ case SYS_WKUP8 :
+ wkup_pin = PWR_WAKEUP_PIN8;
+ break;
+#endif /* PWR_WAKEUP_PIN8 */
+ }
+ HAL_PWR_EnableWakeUpPin(wkup_pin);
+ }
+}
+
+/**
+ * @brief Enable the sleep mode.
+ * @param None
+ * @retval None
+ */
+void LowPower_sleep(uint32_t regulator)
+{
+ /*
+ * Suspend Tick increment to prevent wakeup by Systick interrupt.
+ * Otherwise the Systick interrupt will wake up the device within
+ * 1ms (HAL time base)
+ */
+ HAL_SuspendTick();
+
+ /* Enter Sleep Mode , wake up is done once User push-button is pressed */
+ HAL_PWR_EnterSLEEPMode(regulator, PWR_SLEEPENTRY_WFI);
+
+ /* Resume Tick interrupt if disabled prior to SLEEP mode entry */
+ HAL_ResumeTick();
+
+ if (WakeUpUartCb != NULL) {
+ WakeUpUartCb();
+ }
+}
+
+/**
+ * @brief Enable the stop mode.
+ * @param obj : pointer to serial_t structure
+ * @retval None
+ */
+void LowPower_stop(serial_t *obj)
+{
+ __disable_irq();
+
+#if defined(UART_IT_WUF) && defined(HAL_UART_MODULE_ENABLED) && !defined(HAL_UART_MODULE_ONLY)
+ if (WakeUpUart != NULL) {
+ HAL_UARTEx_EnableStopMode(WakeUpUart);
+ }
+#endif
+
+#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
+#ifdef __HAL_RCC_WAKEUPSTOP_CLK_CONFIG
+ /* Select MSI or HSI as system clock source after Wake Up from Stop mode */
+#ifdef RCC_STOP_WAKEUPCLOCK_MSI
+ __HAL_RCC_WAKEUPSTOP_CLK_CONFIG(RCC_STOP_WAKEUPCLOCK_MSI);
+#else
+ __HAL_RCC_WAKEUPSTOP_CLK_CONFIG(RCC_STOP_WAKEUPCLOCK_HSI);
+#endif
+#endif
+
+ /* Enter Stop mode */
+#if defined(STM32L4xx)
+ if ((WakeUpUart == NULL) || (WakeUpUart->Instance == (USART_TypeDef *)LPUART1_BASE)) {
+ // STM32L4xx supports STOP2 mode which halves consumption
+ HAL_PWREx_EnterSTOP2Mode(PWR_STOPENTRY_WFI);
+ } else
+#endif
+ {
+ HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);
+ }
+
+ /* Exit Stop mode reset clocks */
+ SystemClock_ConfigFromStop();
+#if defined(UART_IT_WUF) && defined(HAL_UART_MODULE_ENABLED) && !defined(HAL_UART_MODULE_ONLY)
+ if (WakeUpUart != NULL) {
+ /* In case of WakeUp from UART, reset its clock source to HSI */
+ uart_config_lowpower(obj);
+ HAL_UARTEx_DisableStopMode(WakeUpUart);
+ }
+#else
+ UNUSED(obj);
+#endif
+ __enable_irq();
+
+ HAL_Delay(10);
+
+ if (WakeUpUartCb != NULL) {
+ WakeUpUartCb();
+ }
+}
+
+/**
+ * @brief Enable the standby mode. The board reset when leaves this mode.
+ * @param None
+ * @retval None
+ */
+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();
+}
+
+/**
+ * @brief Enable the shutdown mode.The board reset when leaves this mode.
+ * If shutdown mode not available, use standby mode instead.
+ * @param None
+ * @retval None
+ */
+void LowPower_shutdown()
+{
+ __disable_irq();
+#ifdef STM32L4xx
+ /* LSE must be on to use shutdown mode */
+ if (__HAL_RCC_GET_FLAG(RCC_FLAG_LSERDY) == SET) {
+ HAL_PWREx_EnterSHUTDOWNMode();
+ } else
+#endif
+ {
+ LowPower_standby();
+ }
+}
+
+/**
+ * @brief Configure the UART as a wakeup source. A callback can be called when
+ * the chip leaves the low power mode. See board datasheet to check
+ * with which low power mode the UART is compatible.
+ * Warning This function will change UART clock source to HSI
+ * @param serial: pointer to serial
+ * @param FuncPtr: pointer to callback
+ * @retval None
+ */
+void LowPower_EnableWakeUpUart(serial_t *serial, void (*FuncPtr)(void))
+{
+#if defined(UART_IT_WUF) && defined(HAL_UART_MODULE_ENABLED) && !defined(HAL_UART_MODULE_ONLY)
+ UART_WakeUpTypeDef WakeUpSelection;
+ if (serial == NULL) {
+ return;
+ }
+ /* Save Uart handler and Serial object */
+ WakeUpUart = &(serial->handle);
+
+ /* make sure that no UART transfer is on-going */
+ while (__HAL_UART_GET_FLAG(WakeUpUart, USART_ISR_BUSY) == SET);
+ /* make sure that UART is ready to receive
+ * (test carried out again later in HAL_UARTEx_StopModeWakeUpSourceConfig) */
+ while (__HAL_UART_GET_FLAG(WakeUpUart, USART_ISR_REACK) == RESET);
+
+ /* set the wake-up event:
+ * specify wake-up on RXNE flag
+ */
+ WakeUpSelection.WakeUpEvent = UART_WAKEUP_ON_READDATA_NONEMPTY;
+ HAL_UARTEx_StopModeWakeUpSourceConfig(WakeUpUart, WakeUpSelection);
+
+ /* Enable the UART Wake UP from STOP1 mode Interrupt */
+ __HAL_UART_ENABLE_IT(WakeUpUart, UART_IT_WUF);
+#else
+ UNUSED(serial);
+#endif
+ /* Save callback */
+ WakeUpUartCb = FuncPtr;
+}
+
+/**
+ * @brief Configures system clock after wake-up from STOP
+ * @note Weaked function which can be redefined by user at the sketch level.
+ * By default, call 'SystemClock_Config()'.
+ * @param None
+ * @retval None
+ */
+WEAK void SystemClock_ConfigFromStop(void)
+{
+ SystemClock_Config();
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HAL_PWR_MODULE_ENABLED && !HAL_PWR_MODULE_ONLY */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/src/low_power.h b/src/low_power.h
new file mode 100644
index 0000000..811c8fd
--- /dev/null
+++ b/src/low_power.h
@@ -0,0 +1,71 @@
+/**
+ ******************************************************************************
+ * @file LowPower.h
+ * @author Frederic Pillon
+ * @brief Header for Low Power module
+ ******************************************************************************
+ * @attention
+ *
+ * © COPYRIGHT(c) 2020 STMicroelectronics
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of STMicroelectronics nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ******************************************************************************
+ */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __LOW_POWER_H
+#define __LOW_POWER_H
+
+/* Includes ------------------------------------------------------------------*/
+#include "stm32_def.h"
+#include "uart.h"
+
+#if defined(STM32_CORE_VERSION) && (STM32_CORE_VERSION > 0x01090000) &&\
+ defined(HAL_PWR_MODULE_ENABLED) && !defined(HAL_PWR_MODULE_ONLY)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Exported types ------------------------------------------------------------*/
+/* Exported constants --------------------------------------------------------*/
+/* Exported macro ------------------------------------------------------------*/
+/* Exported functions ------------------------------------------------------- */
+
+void LowPower_init();
+void LowPower_EnableWakeUpPin(uint32_t pin, uint32_t mode);
+void LowPower_EnableWakeUpUart(serial_t *serial, void (*FuncPtr)(void));
+void LowPower_sleep(uint32_t regulator);
+void LowPower_stop(serial_t *obj);
+void LowPower_standby();
+void LowPower_shutdown();
+/* Weaked function */
+void SystemClock_ConfigFromStop(void);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HAL_PWR_MODULE_ENABLED && !HAL_PWR_MODULE_ONLY */
+
+#endif /* __LOW_POWER_H */