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 */