diff --git a/README.md b/README.md index 9eba8f8..16e0c75 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,64 @@ # STM32LowPower Arduino library to support Low Power + +## 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 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 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 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 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 +**param** callback: pointer to callback +**param** mode: interrupt mode (HIGH, LOW, RISING, FALLING or CHANGE) + +* **`void enableWakeupFrom(HardwareSerial *serial, voidFuncPtrVoid callback)`**: enable a UART peripheral in low power mode. See board documentation for low power mode compatibility. +**param** serial: pointer to a UART +**param** callback: pointer to a callback to call when the board is waked up. + +* **`void enableWakeupFrom(TwoWire *wire, voidFuncPtrVoid callback)`**: +enable an I2C peripheral in low power mode. See board documentation for low power mode compatibility. +**param** wire: pointer to I2C +**param** callback: pointer to a callback to call when the board is waked up. + +* **`void enableWakeupFrom(STM32RTC *rtc, voidFuncPtr callback)`** +attach a callback to the RTC peripheral. +**param** rtc: pointer to RTC +**param** callback: pointer to a callback to call when the board is waked up. + +`Begin()` function must be called at least once before `idle()`, `sleep()`, `deepSleep()` or `shutdown()` functions. + +`attachInterruptWakeup()` or `enableWakeupFrom()` functions should be called before `idle()`, `sleep()`, `deepSleep()` or `shutdown()` functions. + +The board will restart when exit the deepSleep or shutdown mode. + +## Hardware state + +* **Idle mode**: low wake-up latency (µs range) (e.g. ARM WFI). Memories and +voltage supplies are retained. Minimal power saving mainly on the core itself. + +* **sleep mode**: low wake-up latency (µs range) (e.g. ARM WFI), Memories and +voltage supplies are retained. Minimal power saving mainly on the core itself but +higher than idle mode. + +* **deep sleep mode**: medium latency (ms range), clocks are gated to reduced. Memories +and voltage supplies are retained. If supported, Peripherals wake-up is possible (UART, I2C ...). + +* **shutdown mode**: high wake-up latency (posible hundereds of ms or second +timeframe), voltage supplies are cut except always-on domain, memory content +are lost and system basically reboots. + +## Source + +You can find the source files at +https://github.com/stm32duino/STM32LowPower diff --git a/examples/AlarmTimedWakup/AlarmTimedWakup.ino b/examples/AlarmTimedWakup/AlarmTimedWakup.ino new file mode 100644 index 0000000..625f511 --- /dev/null +++ b/examples/AlarmTimedWakup/AlarmTimedWakup.ino @@ -0,0 +1,81 @@ +/* + AdvancedTimedWakeup + + This sketch demonstrates the usage of Internal Interrupts to wakeup a chip in deep sleep mode. + + In this sketch: + - RTC date and time are configured. + - Alarm is set to wake up the processor each 'atime' and called a custom alarm callback + which increment a value and reload alarm with 'atime' offset. + + This example code is in the public domain. +*/ + +#include "STM32LowPower.h" +#include + +/* Get the rtc object */ +STM32RTC& rtc = STM32RTC::getInstance(); + +// Time in second between blink +static uint32_t atime = 1; + +// Declare it volatile since it's incremented inside an interrupt +volatile int alarmMatch_counter = 0; + +// Variables for RTC configurations +static byte seconds = 0; +static byte minutes = 0; +static byte hours = 0; + +static byte weekDay = 1; +static byte day = 1; +static byte month = 1; +static byte year = 18; + +void setup() { + rtc.begin(); + rtc.setTime(hours, minutes, seconds); + rtc.setDate(weekDay, day, month, year); + + pinMode(LED_BUILTIN, OUTPUT); + + Serial.begin(9600); + 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 ); +} + +void loop() { + Serial.print("Alarm Match: "); + Serial.print(alarmMatch_counter); + Serial.println(" times."); + delay(100); + digitalWrite(LED_BUILTIN, HIGH); + LowPower.deepSleep(); + digitalWrite(LED_BUILTIN, LOW); + LowPower.deepSleep(); +} + +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 + uint32_t sec = 1; + if(data != NULL) { + sec = *(uint32_t*)data; + // Minimum is 1 second + if (sec == 0){ + sec = 1; + } + } + alarmMatch_counter++; + rtc.setAlarmEpoch( rtc.getEpoch() + sec); +} + diff --git a/examples/ExternalWakeup/ExternalWakeup.ino b/examples/ExternalWakeup/ExternalWakeup.ino new file mode 100644 index 0000000..a545494 --- /dev/null +++ b/examples/ExternalWakeup/ExternalWakeup.ino @@ -0,0 +1,52 @@ +/* + ExternalWakeup + + This sketch demonstrates the usage of External Interrupts (on pins) to wakeup + a chip in sleep mode. Sleep modes allow a significant drop in the power usage + of a board while it does nothing waiting for an event to happen. + Battery powered application can take advantage of these modes to enhance + battery life significantly. + + In this sketch, pressing a pushbutton attached to pin will wake up the board. + + This example code is in the public domain. +*/ + +#include "STM32LowPower.h" + +// Blink sequence number +// Declare it volatile since it's incremented inside an interrupt +volatile int repetitions = 1; + +// Pin used to trigger a wakeup +const int pin = USER_BTN; + +void setup() { + pinMode(LED_BUILTIN, OUTPUT); + // Set pin as INPUT_PULLUP to avoid spurious wakeup + pinMode(pin, INPUT_PULLUP); + + // Configure low power + LowPower.begin(); + // Attach a wakeup interrupt on pin, calling repetitionsIncrease when the device is woken up + LowPower.attachInterruptWakeup(pin, repetitionsIncrease, RISING); +} + +void loop() { + for (int i = 0; i < repetitions; i++) { + digitalWrite(LED_BUILTIN, HIGH); + delay(500); + digitalWrite(LED_BUILTIN, LOW); + delay(500); + } + // Triggers an infinite sleep (the device will be woken up only by the registered wakeup sources) + // The power consumption of the chip will drop consistently + LowPower.sleep(); +} + +void repetitionsIncrease() { + // 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 + repetitions ++; +} diff --git a/examples/SerialDeepSleep/SerialDeepSleep.ino b/examples/SerialDeepSleep/SerialDeepSleep.ino new file mode 100644 index 0000000..4b81415 --- /dev/null +++ b/examples/SerialDeepSleep/SerialDeepSleep.ino @@ -0,0 +1,57 @@ +/* + SerialDeepSleep + + This sketch demonstrates the usage of Serial Interrupts to wakeup a chip + in deep sleep mode. + + This sketch is compatible only with board supporting uart peripheral in + stop mode. + + This example code is in the public domain. +*/ + +#include "STM32LowPower.h" + +// Declare it volatile since it's incremented inside an interrupt +volatile int wakeup_counter = 0; + +void setup() { + Serial.begin(9600); + // initialize digital pin LED_BUILTIN as an output. + pinMode(LED_BUILTIN, OUTPUT); + // Configure low power + LowPower.begin(); + // Enable UART in Low Power mode wakeup source + LowPower.enableWakeupFrom(&Serial, SerialWakeup); + Serial.println("Start deep sleep wakeup from Serial"); +} + +void loop() { + digitalWrite(LED_BUILTIN, HIGH); + delay(500); + digitalWrite(LED_BUILTIN, LOW); + delay(500); + // Triggers an infinite deep sleep + // (the device will be woken up only by the registered wakeup sources) + // The power consumption of the chip will drop consistently + LowPower.deepSleep(); + + Serial.print(wakeup_counter); + Serial.println(" wake up"); + + // Empty Serial Rx + while(Serial.available()) { + char c = Serial.read(); + Serial.print(c); + } + Serial.println(); +} + +void SerialWakeup() { + // 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 + wakeup_counter++; +} diff --git a/examples/TimedWakeup/TimedWakeup.ino b/examples/TimedWakeup/TimedWakeup.ino new file mode 100644 index 0000000..6baac3f --- /dev/null +++ b/examples/TimedWakeup/TimedWakeup.ino @@ -0,0 +1,25 @@ +/* + TimedWakeup + + This sketch demonstrates the usage of Internal Interrupts to wakeup a chip + in deep sleep mode. + + In this sketch, the internal RTC will wake up the processor every second. + + This example code is in the public domain. +*/ + +#include "STM32LowPower.h" + +void setup() { + pinMode(LED_BUILTIN, OUTPUT); + // Configure low power + LowPower.begin(); +} + +void loop() { + digitalWrite(LED_BUILTIN, HIGH); + LowPower.deepSleep(1000); + digitalWrite(LED_BUILTIN, LOW); + LowPower.deepSleep(1000); +} diff --git a/keywords.txt b/keywords.txt new file mode 100644 index 0000000..80d9c07 --- /dev/null +++ b/keywords.txt @@ -0,0 +1,26 @@ +####################################### +# Syntax Coloring Map For Energy Saving +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +ArduinoLowPower KEYWORD1 +LowPower KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +begin KEYWORD2 +idle KEYWORD2 +sleep KEYWORD2 +deepSleep KEYWORD2 +shutdown KEYWORD2 +attachInterruptWakeup KEYWORD2 +enableWakeupFrom KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### diff --git a/library.properties b/library.properties new file mode 100644 index 0000000..708170f --- /dev/null +++ b/library.properties @@ -0,0 +1,9 @@ +name=STM32duino Low Power +version=1.0.0 +author=Wi6Labs +maintainer=stm32duino +sentence=Power save primitives features for STM32 boards +paragraph=With this library you can manage the low power states of STM32 boards +category=Device Control +url=https://github.com/stm32duino/STM32LowPower +architectures=stm32 diff --git a/src/STM32LowPower.cpp b/src/STM32LowPower.cpp new file mode 100644 index 0000000..a069a26 --- /dev/null +++ b/src/STM32LowPower.cpp @@ -0,0 +1,193 @@ +/** +****************************************************************************** +* @file STM32LowPower.cpp +* @author WI6LABS +* @version V1.0.0 +* @date 11-December-2017 +* @brief Provides a STM32 Low Power interface with Arduino +* +****************************************************************************** +* @attention +* +*

© COPYRIGHT(c) 2017 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 "STM32LowPower.h" + +STM32LowPower LowPower; + + +STM32LowPower::STM32LowPower() +{ + _configured = false; + _serial = NULL; +} + +/** + * @brief Initializes the low power mode + * @param None + * @retval None + */ +void STM32LowPower::begin(void) +{ + LowPower_init(); + _configured = true; +} + +/** + * @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). + * @retval None + */ +void STM32LowPower::idle(uint32_t millis) +{ + if(millis > 0) { + programRtcWakeUp(millis); + } + LowPower_sleep(PWR_MAINREGULATOR_ON); +} + +/** + * @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). + * @retval None + */ +void STM32LowPower::sleep(uint32_t millis) +{ + if(millis > 0) { + programRtcWakeUp(millis); + } + LowPower_sleep(PWR_LOWPOWERREGULATOR_ON); +} + +/** + * @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). + * @retval None + */ +void STM32LowPower::deepSleep(uint32_t millis) +{ + if(millis > 0) { + programRtcWakeUp(millis); + } + LowPower_stop(_serial); +} + +/** + * @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). + * @retval None + */ +void STM32LowPower::shutdown(uint32_t millis) +{ + if(millis > 0) { + programRtcWakeUp(millis); + } + LowPower_shutdown(); +} + +/** + * @brief Enable GPIO pin in interrupt mode. If the pin is a wakeup pin, it is + * configured as wakeup source. + * @param pin: pin number + * @param callback: pointer to callback function. + * @param mode: pin interrupt mode (HIGH, LOW, RISING, FALLING or CHANGE) + * @retval None + */ +void STM32LowPower::attachInterruptWakeup(uint32_t pin, voidFuncPtrVoid callback, uint32_t mode) +{ + // All GPIO for idle (smt32 sleep) and sleep (stm32 stop) + attachInterrupt(pin, callback, mode); + + // If Gpio is a Wake up pin activate it for deepSleep (standby stm32) and shutdown + LowPower_EnableWakeUpPin(pin, mode); +} + +/** + * @brief Enable a serial interface as a wakeup source. + * @param serial: pointer to a HardwareSerial + * @param callback: pointer to callback function called when leave the low power + * mode. + * @retval None + */ +void STM32LowPower::enableWakeupFrom(HardwareSerial *serial, voidFuncPtrVoid callback) +{ + if(serial != NULL) { + _serial = &(serial->_serial); + // Reconfigure serial for low power mode (using HSI as clock source) + serial->configForLowPower(); + LowPower_EnableWakeUpUart(_serial, callback); + } +} + +/** + * @brief Attach a callback to a RTC alarm. + * @param rtc: pointer to a STM32RTC + * @param callback: pointer to callback function called when leave the low power + * mode. + * @param data: optional pointer to callaback data parameters (default NULL). + * @retval None + */ +void STM32LowPower::enableWakeupFrom(STM32RTC *rtc, voidFuncPtr callback, void *data) +{ + if(rtc == NULL) { + rtc = &(STM32RTC::getInstance()); + } + // Reconfigure rtc for low power mode (using LSE as clock source) + rtc->configForLowPower(); + rtc->attachInterrupt(callback, data); +} + +/** + * @brief Configure the RTC alarm + * @param millis: time of the alarm in milliseconds. At least 1000ms. + * @retval None + */ +void STM32LowPower::programRtcWakeUp(uint32_t millis) +{ + int epoc; + uint32_t sec; + STM32RTC& rtc = STM32RTC::getInstance(); + + if(millis > 0) { + // LSE must be selected as clock source to wakeup the device from shutdown mode + rtc.configForLowPower(); + // Convert millisecond to second + sec = millis / 1000; + // Minimum is 1 second + if (sec == 0){ + sec = 1; + } + + epoc = rtc.getEpoch(); + rtc.setAlarmEpoch( epoc + sec ); + } +} diff --git a/src/STM32LowPower.h b/src/STM32LowPower.h new file mode 100644 index 0000000..e407ca5 --- /dev/null +++ b/src/STM32LowPower.h @@ -0,0 +1,93 @@ +/** +****************************************************************************** +* @file STM32LowPower.h +* @author WI6LABS +* @version V1.0.0 +* @date 11-December-2017 +* @brief Provides a STM32 Low Power interface with Arduino +* +****************************************************************************** +* @attention +* +*

© COPYRIGHT(c) 2017 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. +* +****************************************************************************** +*/ + +#ifndef _STM32_LOW_POWER_H_ +#define _STM32_LOW_POWER_H_ + +#include + +// 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" +#endif + +#include "STM32RTC.h" +#include "Wire.h" + +typedef void (*voidFuncPtrVoid)( void ) ; + +class STM32LowPower { +public: + STM32LowPower(); + + void begin(void); + + void idle(uint32_t millis = 0); + void idle(int millis) { + idle((uint32_t)millis); + } + + void sleep(uint32_t millis = 0); + void sleep(int millis) { + sleep((uint32_t)millis); + } + + void deepSleep(uint32_t millis = 0); + void deepSleep(int millis) { + deepSleep((uint32_t)millis); + } + + void shutdown(uint32_t millis = 0); + void shutdown(int millis) { + shutdown((uint32_t)millis); + } + + void attachInterruptWakeup(uint32_t pin, voidFuncPtrVoid callback, uint32_t mode); + + void enableWakeupFrom(HardwareSerial *serial, voidFuncPtrVoid callback); + void enableWakeupFrom(STM32RTC *rtc, voidFuncPtr callback, void *data = NULL); + +private: + bool _configured; /* Low Power mode initialization status */ + serial_t *_serial; /* Serial for wakeup from deep sleep */ + void programRtcWakeUp(uint32_t millis); +}; + +extern STM32LowPower LowPower; + +#endif // _STM32_LOW_POWER_H_