This class provides an API to assist with low power behaviour on an STM32F437 micro, as used on the u-blox C030 board. If you need to operate from battery for any significant period, or are mains powered and don't want to take the planet down with you, you should design your code with this in mind. This library uses the https://developer.mbed.org/users/Sissors/code/WakeUp/ library and so could be extended to support all of the MCUs that library supports.

Dependencies:   WakeUp

Dependents:   example-low-power-sleep aconnoCellularGnss

Committer:
RobMeades
Date:
Mon Jun 05 14:28:14 2017 +0000
Revision:
4:691e6b38fc54
Parent:
3:442c9afc0229
Update readme.txt.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
rob.meades@u-blox.com 1:4f2c412dc013 1 /* mbed Microcontroller Library
rob.meades@u-blox.com 1:4f2c412dc013 2 * Copyright (c) 2017 u-blox
rob.meades@u-blox.com 1:4f2c412dc013 3 *
rob.meades@u-blox.com 1:4f2c412dc013 4 * Licensed under the Apache License, Version 2.0 (the "License");
rob.meades@u-blox.com 1:4f2c412dc013 5 * you may not use this file except in compliance with the License.
rob.meades@u-blox.com 1:4f2c412dc013 6 * You may obtain a copy of the License at
rob.meades@u-blox.com 1:4f2c412dc013 7 *
rob.meades@u-blox.com 1:4f2c412dc013 8 * http://www.apache.org/licenses/LICENSE-2.0
rob.meades@u-blox.com 1:4f2c412dc013 9 *
rob.meades@u-blox.com 1:4f2c412dc013 10 * Unless required by applicable law or agreed to in writing, software
rob.meades@u-blox.com 1:4f2c412dc013 11 * distributed under the License is distributed on an "AS IS" BASIS,
rob.meades@u-blox.com 1:4f2c412dc013 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
rob.meades@u-blox.com 1:4f2c412dc013 13 * See the License for the specific language governing permissions and
rob.meades@u-blox.com 1:4f2c412dc013 14 * limitations under the License.
rob.meades@u-blox.com 1:4f2c412dc013 15 */
rob.meades@u-blox.com 1:4f2c412dc013 16
rob.meades@u-blox.com 1:4f2c412dc013 17 /**
rob.meades@u-blox.com 1:4f2c412dc013 18 * @file low_power.cpp
rob.meades@u-blox.com 1:4f2c412dc013 19 * This file defines a class intended to assist with obtaining lowest power
rob.meades@u-blox.com 1:4f2c412dc013 20 * operation on an STM32F437 microprocessor.
rob.meades@u-blox.com 1:4f2c412dc013 21 */
rob.meades@u-blox.com 1:4f2c412dc013 22
rob.meades@u-blox.com 1:4f2c412dc013 23 // Define this to print debug information
rob.meades@u-blox.com 1:4f2c412dc013 24 //#define DEBUG_LOW_POWER
rob.meades@u-blox.com 1:4f2c412dc013 25
rob.meades@u-blox.com 1:4f2c412dc013 26 #include <mbed.h>
rob.meades@u-blox.com 1:4f2c412dc013 27 #include <low_power.h>
rob.meades@u-blox.com 1:4f2c412dc013 28 #ifdef TARGET_STM
rob.meades@u-blox.com 1:4f2c412dc013 29 #include <stm32f4xx_hal_pwr.h>
rob.meades@u-blox.com 1:4f2c412dc013 30 #include <stm32f4xx_hal_rcc.h>
rob.meades@u-blox.com 1:4f2c412dc013 31 #endif
rob.meades@u-blox.com 1:4f2c412dc013 32
rob.meades@u-blox.com 1:4f2c412dc013 33 #ifdef DEBUG_LOW_POWER
rob.meades@u-blox.com 1:4f2c412dc013 34 # include <stdio.h>
rob.meades@u-blox.com 1:4f2c412dc013 35 #endif
rob.meades@u-blox.com 1:4f2c412dc013 36
RobMeades 3:442c9afc0229 37 /* ----------------------------------------------------------------
RobMeades 3:442c9afc0229 38 * COMPILE-TIME MACROS
RobMeades 3:442c9afc0229 39 * -------------------------------------------------------------- */
rob.meades@u-blox.com 1:4f2c412dc013 40
RobMeades 3:442c9afc0229 41 // Location of backup SRAM in memory (on STM23F4, has no effect otherwise).
rob.meades@u-blox.com 1:4f2c412dc013 42 #define BACKUP_SRAM_START_ADDRESS ((uint32_t *) ((uint32_t) BKPSRAM_BASE))
rob.meades@u-blox.com 1:4f2c412dc013 43
RobMeades 3:442c9afc0229 44 /* ----------------------------------------------------------------
RobMeades 3:442c9afc0229 45 * PRIVATE VARIABLES
RobMeades 3:442c9afc0229 46 * -------------------------------------------------------------- */
RobMeades 3:442c9afc0229 47
RobMeades 3:442c9afc0229 48 /* ----------------------------------------------------------------
RobMeades 3:442c9afc0229 49 * PRIVATE FUNCTIONS
RobMeades 3:442c9afc0229 50 * -------------------------------------------------------------- */
rob.meades@u-blox.com 1:4f2c412dc013 51
RobMeades 3:442c9afc0229 52 // Check whether an interrupt is enabled or not.
rob.meades@u-blox.com 1:4f2c412dc013 53 inline uint32_t LowPower::myNVIC_GetEnableIRQ(IRQn_Type IRQn)
rob.meades@u-blox.com 1:4f2c412dc013 54 {
rob.meades@u-blox.com 1:4f2c412dc013 55 if ((int32_t)(IRQn) >= 0) {
rob.meades@u-blox.com 1:4f2c412dc013 56 return((uint32_t)(((NVIC->ISER[(((uint32_t)(int32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL));
rob.meades@u-blox.com 1:4f2c412dc013 57 } else {
rob.meades@u-blox.com 1:4f2c412dc013 58 return(0U);
rob.meades@u-blox.com 1:4f2c412dc013 59 }
rob.meades@u-blox.com 1:4f2c412dc013 60 }
rob.meades@u-blox.com 1:4f2c412dc013 61
RobMeades 3:442c9afc0229 62 /* ----------------------------------------------------------------
RobMeades 3:442c9afc0229 63 * PUBLIC FUNCTIONS
RobMeades 3:442c9afc0229 64 * -------------------------------------------------------------- */
rob.meades@u-blox.com 1:4f2c412dc013 65
RobMeades 3:442c9afc0229 66 // Constructor.
rob.meades@u-blox.com 1:4f2c412dc013 67 LowPower::LowPower(void)
rob.meades@u-blox.com 1:4f2c412dc013 68 {
rob.meades@u-blox.com 1:4f2c412dc013 69 #ifdef TARGET_STM
rob.meades@u-blox.com 1:4f2c412dc013 70 // Enable back-up SRAM access, see section 5.1.2 of the STM32F437
rob.meades@u-blox.com 1:4f2c412dc013 71 // detailed manual and stm32f4xx_hal_pwr.c
rob.meades@u-blox.com 1:4f2c412dc013 72 __HAL_RCC_PWR_CLK_ENABLE();
rob.meades@u-blox.com 1:4f2c412dc013 73 HAL_PWR_EnableBkUpAccess();
rob.meades@u-blox.com 1:4f2c412dc013 74 __HAL_RCC_BKPSRAM_CLK_ENABLE();
rob.meades@u-blox.com 1:4f2c412dc013 75
rob.meades@u-blox.com 1:4f2c412dc013 76 // Determine if we've already been active
rob.meades@u-blox.com 1:4f2c412dc013 77 if (!__HAL_PWR_GET_FLAG(PWR_FLAG_BRR)) {
rob.meades@u-blox.com 1:4f2c412dc013 78 // If the backup regulator is not running, we've not woken
rob.meades@u-blox.com 1:4f2c412dc013 79 // up from Standby with data in there and so we
rob.meades@u-blox.com 1:4f2c412dc013 80 // should zero the backup SRAM to clean it up.
rob.meades@u-blox.com 1:4f2c412dc013 81 memset (BACKUP_SRAM_START_ADDRESS, 0, BACKUP_SRAM_SIZE);
rob.meades@u-blox.com 1:4f2c412dc013 82 }
rob.meades@u-blox.com 1:4f2c412dc013 83 #endif
rob.meades@u-blox.com 1:4f2c412dc013 84 }
rob.meades@u-blox.com 1:4f2c412dc013 85
RobMeades 3:442c9afc0229 86 // Destructor.
rob.meades@u-blox.com 1:4f2c412dc013 87 LowPower::~LowPower(void)
rob.meades@u-blox.com 1:4f2c412dc013 88 {
rob.meades@u-blox.com 1:4f2c412dc013 89 }
rob.meades@u-blox.com 1:4f2c412dc013 90
RobMeades 3:442c9afc0229 91 // Enter Stop mode.
rob.meades@u-blox.com 1:4f2c412dc013 92 void LowPower::enterStop(uint32_t stopPeriodMilliseconds)
rob.meades@u-blox.com 1:4f2c412dc013 93 {
rob.meades@u-blox.com 1:4f2c412dc013 94 if (stopPeriodMilliseconds > 0) {
rob.meades@u-blox.com 1:4f2c412dc013 95 // If the RTC is not running, call set_time with
rob.meades@u-blox.com 1:4f2c412dc013 96 // a value of zero to kick it into life
rob.meades@u-blox.com 1:4f2c412dc013 97 if (time(NULL) <= 0) {
rob.meades@u-blox.com 1:4f2c412dc013 98 set_time(0);
rob.meades@u-blox.com 1:4f2c412dc013 99 }
rob.meades@u-blox.com 1:4f2c412dc013 100
rob.meades@u-blox.com 1:4f2c412dc013 101 #ifdef DEBUG_LOW_POWER
rob.meades@u-blox.com 1:4f2c412dc013 102 time_t timeNow = time(NULL);
rob.meades@u-blox.com 1:4f2c412dc013 103 time_t timeThen = timeNow + stopPeriodMilliseconds / 1000;
rob.meades@u-blox.com 1:4f2c412dc013 104 char buf[32];
rob.meades@u-blox.com 1:4f2c412dc013 105 strftime(buf, sizeof (buf), "%Y-%m-%d %H:%M:%S", localtime(&timeThen));
rob.meades@u-blox.com 1:4f2c412dc013 106 printf ("LowPower: going to Stop mode for %.3f second(s) (will awake at ~%s).\n",
rob.meades@u-blox.com 1:4f2c412dc013 107 (float) stopPeriodMilliseconds / 1000, buf);
rob.meades@u-blox.com 1:4f2c412dc013 108 wait_ms(100); // Let printf leave the building
rob.meades@u-blox.com 1:4f2c412dc013 109 #endif
rob.meades@u-blox.com 1:4f2c412dc013 110
rob.meades@u-blox.com 1:4f2c412dc013 111 // Set the RTC alarm
rob.meades@u-blox.com 1:4f2c412dc013 112 WakeUp::set_ms(stopPeriodMilliseconds);
rob.meades@u-blox.com 1:4f2c412dc013 113 // Now enter Stop mode, allowing flash to power down
rob.meades@u-blox.com 1:4f2c412dc013 114 // also if we can
rob.meades@u-blox.com 1:4f2c412dc013 115 #ifdef TARGET_STM
rob.meades@u-blox.com 1:4f2c412dc013 116 HAL_PWREx_EnableFlashPowerDown();
rob.meades@u-blox.com 1:4f2c412dc013 117 #endif
rob.meades@u-blox.com 1:4f2c412dc013 118 hal_deepsleep();
rob.meades@u-blox.com 1:4f2c412dc013 119 #ifdef TARGET_STM
rob.meades@u-blox.com 1:4f2c412dc013 120 HAL_PWREx_DisableFlashPowerDown();
rob.meades@u-blox.com 1:4f2c412dc013 121 #endif
rob.meades@u-blox.com 1:4f2c412dc013 122 }
rob.meades@u-blox.com 1:4f2c412dc013 123 }
rob.meades@u-blox.com 1:4f2c412dc013 124
RobMeades 3:442c9afc0229 125 // Enter Standby mode.
rob.meades@u-blox.com 1:4f2c412dc013 126 void LowPower::enterStandby(uint32_t standbyPeriodMilliseconds, bool powerDownBackupSram)
rob.meades@u-blox.com 1:4f2c412dc013 127 {
rob.meades@u-blox.com 1:4f2c412dc013 128 if (standbyPeriodMilliseconds > 0) {
rob.meades@u-blox.com 1:4f2c412dc013 129 // If time the RTC is not running, call set_time with
rob.meades@u-blox.com 1:4f2c412dc013 130 // a value of zero to kick it into life
rob.meades@u-blox.com 1:4f2c412dc013 131 if (time(NULL) <= 0) {
rob.meades@u-blox.com 1:4f2c412dc013 132 set_time(0);
rob.meades@u-blox.com 1:4f2c412dc013 133 }
rob.meades@u-blox.com 1:4f2c412dc013 134
rob.meades@u-blox.com 1:4f2c412dc013 135 #ifdef TARGET_STM
rob.meades@u-blox.com 1:4f2c412dc013 136 // Set the backup regulator (for backup SRAM) into the right state
rob.meades@u-blox.com 1:4f2c412dc013 137 if (powerDownBackupSram) {
rob.meades@u-blox.com 1:4f2c412dc013 138 HAL_PWREx_DisableBkUpReg();
rob.meades@u-blox.com 1:4f2c412dc013 139 } else {
rob.meades@u-blox.com 1:4f2c412dc013 140 HAL_PWREx_EnableBkUpReg();
rob.meades@u-blox.com 1:4f2c412dc013 141 }
rob.meades@u-blox.com 1:4f2c412dc013 142 #endif
rob.meades@u-blox.com 1:4f2c412dc013 143
rob.meades@u-blox.com 1:4f2c412dc013 144 #ifdef DEBUG_LOW_POWER
rob.meades@u-blox.com 1:4f2c412dc013 145 time_t timeNow = time(NULL);
rob.meades@u-blox.com 1:4f2c412dc013 146 time_t timeThen = timeNow + standbyPeriodMilliseconds / 1000;
rob.meades@u-blox.com 1:4f2c412dc013 147 char buf[32];
rob.meades@u-blox.com 1:4f2c412dc013 148 strftime(buf, sizeof (buf), "%Y-%m-%d %H:%M:%S", localtime(&timeThen));
rob.meades@u-blox.com 1:4f2c412dc013 149 printf ("LowPower: going to Standby mode for %.3f second(s) (will awake at ~%s).\n",
rob.meades@u-blox.com 1:4f2c412dc013 150 (float) standbyPeriodMilliseconds / 1000, buf);
rob.meades@u-blox.com 1:4f2c412dc013 151 wait_ms(100); // Let printf leave the building
rob.meades@u-blox.com 1:4f2c412dc013 152 #endif
rob.meades@u-blox.com 1:4f2c412dc013 153
rob.meades@u-blox.com 1:4f2c412dc013 154 // Set the RTC alarm
rob.meades@u-blox.com 1:4f2c412dc013 155 WakeUp::set_ms(standbyPeriodMilliseconds);
rob.meades@u-blox.com 1:4f2c412dc013 156 #ifdef TARGET_STM
rob.meades@u-blox.com 1:4f2c412dc013 157 // Now enter Standby mode, clearing the wake-up flag first
rob.meades@u-blox.com 1:4f2c412dc013 158 // in case we've done this before
rob.meades@u-blox.com 1:4f2c412dc013 159 PWR->CR = PWR_CR_CWUF;
rob.meades@u-blox.com 1:4f2c412dc013 160 HAL_PWR_EnterSTANDBYMode();
rob.meades@u-blox.com 1:4f2c412dc013 161 #else
rob.meades@u-blox.com 1:4f2c412dc013 162 MBED_ASSERT(false);
rob.meades@u-blox.com 1:4f2c412dc013 163 #endif
rob.meades@u-blox.com 1:4f2c412dc013 164 }
rob.meades@u-blox.com 1:4f2c412dc013 165 }
rob.meades@u-blox.com 1:4f2c412dc013 166
RobMeades 3:442c9afc0229 167 // Get the number of user interrupts that are enabled.
rob.meades@u-blox.com 1:4f2c412dc013 168 int32_t LowPower::numUserInterruptsEnabled(uint8_t *pList, uint32_t sizeOfList)
rob.meades@u-blox.com 1:4f2c412dc013 169 {
rob.meades@u-blox.com 1:4f2c412dc013 170 int32_t userInterruptsEnabled = 0;
rob.meades@u-blox.com 1:4f2c412dc013 171 uint8_t *pEndOfList = pList + sizeOfList;
rob.meades@u-blox.com 1:4f2c412dc013 172
rob.meades@u-blox.com 1:4f2c412dc013 173 #ifdef DEBUG_LOW_POWER
rob.meades@u-blox.com 1:4f2c412dc013 174 printf ("Checking enabled interrupts...");
rob.meades@u-blox.com 1:4f2c412dc013 175 #endif
rob.meades@u-blox.com 1:4f2c412dc013 176 for (uint8_t x = 0; x < NVIC_NUM_VECTORS - NVIC_USER_IRQ_OFFSET; x++) {
rob.meades@u-blox.com 1:4f2c412dc013 177 if (myNVIC_GetEnableIRQ((IRQn_Type) x)) {
rob.meades@u-blox.com 1:4f2c412dc013 178 userInterruptsEnabled++;
rob.meades@u-blox.com 1:4f2c412dc013 179 if ((pList != NULL) && (pList < pEndOfList)) {
rob.meades@u-blox.com 1:4f2c412dc013 180 *pList = x;
rob.meades@u-blox.com 1:4f2c412dc013 181 pList++;
rob.meades@u-blox.com 1:4f2c412dc013 182 }
rob.meades@u-blox.com 1:4f2c412dc013 183 #ifdef DEBUG_LOW_POWER
rob.meades@u-blox.com 1:4f2c412dc013 184 printf (" %d", x);
rob.meades@u-blox.com 1:4f2c412dc013 185 #endif
rob.meades@u-blox.com 1:4f2c412dc013 186 }
rob.meades@u-blox.com 1:4f2c412dc013 187 }
rob.meades@u-blox.com 1:4f2c412dc013 188
rob.meades@u-blox.com 1:4f2c412dc013 189 #ifdef DEBUG_LOW_POWER
rob.meades@u-blox.com 1:4f2c412dc013 190 if (userInterruptsEnabled == 0) {
rob.meades@u-blox.com 1:4f2c412dc013 191 printf (" (none were enabled)");
rob.meades@u-blox.com 1:4f2c412dc013 192 }
rob.meades@u-blox.com 1:4f2c412dc013 193 printf (".\n");
rob.meades@u-blox.com 1:4f2c412dc013 194 #endif
rob.meades@u-blox.com 1:4f2c412dc013 195
rob.meades@u-blox.com 1:4f2c412dc013 196 return userInterruptsEnabled;
rob.meades@u-blox.com 1:4f2c412dc013 197 }
rob.meades@u-blox.com 1:4f2c412dc013 198
RobMeades 3:442c9afc0229 199 // Exit debug mode.
rob.meades@u-blox.com 1:4f2c412dc013 200 void LowPower::exitDebugMode(void)
rob.meades@u-blox.com 1:4f2c412dc013 201 {
rob.meades@u-blox.com 1:4f2c412dc013 202 #ifdef TARGET_STM
rob.meades@u-blox.com 1:4f2c412dc013 203 // If this is a power on reset, do a system
rob.meades@u-blox.com 1:4f2c412dc013 204 // reset to get us out of our debug-mode
rob.meades@u-blox.com 1:4f2c412dc013 205 // entanglement with the debug chip on the
rob.meades@u-blox.com 1:4f2c412dc013 206 // mbed board
rob.meades@u-blox.com 1:4f2c412dc013 207 if (__HAL_RCC_GET_FLAG(RCC_FLAG_PORRST)) {
rob.meades@u-blox.com 1:4f2c412dc013 208 __HAL_RCC_CLEAR_RESET_FLAGS();
rob.meades@u-blox.com 1:4f2c412dc013 209 NVIC_SystemReset();
rob.meades@u-blox.com 1:4f2c412dc013 210 }
rob.meades@u-blox.com 1:4f2c412dc013 211 #else
rob.meades@u-blox.com 1:4f2c412dc013 212 MBED_ASSERT(false);
rob.meades@u-blox.com 1:4f2c412dc013 213 #endif
rob.meades@u-blox.com 1:4f2c412dc013 214 }
rob.meades@u-blox.com 1:4f2c412dc013 215
RobMeades 3:442c9afc0229 216 /* End Of File */