Enter Standby mode then wake up(only restart) by RTC timer
Dependents: Check_StandBy_os2 Check_StandBy_os5 Check_StandBy_os6
see /users/kenjiArai/notebook/standby-mode-current-consumption-on-nucleo-f446re/
WakeUp_STM32.cpp@1:bbc6b5bdd75b, 2021-01-17 (annotated)
- Committer:
- kenjiArai
- Date:
- Sun Jan 17 03:05:33 2021 +0000
- Revision:
- 1:bbc6b5bdd75b
- Parent:
- 0:abaa4fd0c727
added Nucleo-L476RG and DISCO-L475VG-IOT01A
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
kenjiArai | 0:abaa4fd0c727 | 1 | /* |
kenjiArai | 0:abaa4fd0c727 | 2 | |
kenjiArai | 0:abaa4fd0c727 | 3 | Original idea & program |
kenjiArai | 0:abaa4fd0c727 | 4 | https://os.mbed.com/users/Sissors/code/WakeUp/ |
kenjiArai | 0:abaa4fd0c727 | 5 | by Erik |
kenjiArai | 1:bbc6b5bdd75b | 6 | |
kenjiArai | 0:abaa4fd0c727 | 7 | modified version |
kenjiArai | 0:abaa4fd0c727 | 8 | https://os.mbed.com/users/kenjiArai/code/WakeUp/ |
kenjiArai | 0:abaa4fd0c727 | 9 | */ |
kenjiArai | 0:abaa4fd0c727 | 10 | |
kenjiArai | 0:abaa4fd0c727 | 11 | /* |
kenjiArai | 0:abaa4fd0c727 | 12 | * Modified only for STM CPU |
kenjiArai | 0:abaa4fd0c727 | 13 | * by Kenji Arai / JH1PJL |
kenjiArai | 0:abaa4fd0c727 | 14 | * |
kenjiArai | 0:abaa4fd0c727 | 15 | * http://www7b.biglobe.ne.jp/~kenjia/ |
kenjiArai | 0:abaa4fd0c727 | 16 | * http://mbed.org/users/kenjiArai/ |
kenjiArai | 0:abaa4fd0c727 | 17 | * Created: September 21st, 2017 |
kenjiArai | 1:bbc6b5bdd75b | 18 | * Revised: January 17th, 2021 |
kenjiArai | 0:abaa4fd0c727 | 19 | */ |
kenjiArai | 0:abaa4fd0c727 | 20 | |
kenjiArai | 0:abaa4fd0c727 | 21 | #if \ |
kenjiArai | 0:abaa4fd0c727 | 22 | defined(TARGET_NUCLEO_F334R8) |
kenjiArai | 0:abaa4fd0c727 | 23 | # error Not support yet |
kenjiArai | 0:abaa4fd0c727 | 24 | #elif \ |
kenjiArai | 0:abaa4fd0c727 | 25 | defined(TARGET_NUCLEO_F401RE)\ |
kenjiArai | 0:abaa4fd0c727 | 26 | || defined(TARGET_NUCLEO_F411RE)\ |
kenjiArai | 0:abaa4fd0c727 | 27 | || defined(TARGET_NUCLEO_F446RE)\ |
kenjiArai | 0:abaa4fd0c727 | 28 | || defined(TARGET_NUCLEO_L053R8)\ |
kenjiArai | 0:abaa4fd0c727 | 29 | || defined(TARGET_NUCLEO_L073RZ)\ |
kenjiArai | 1:bbc6b5bdd75b | 30 | || defined(TARGET_NUCLEO_L152RE)\ |
kenjiArai | 1:bbc6b5bdd75b | 31 | || defined(TARGET_NUCLEO_L476RG)\ |
kenjiArai | 1:bbc6b5bdd75b | 32 | || defined(TARGET_DISCO_L475VG_IOT01A) |
kenjiArai | 0:abaa4fd0c727 | 33 | |
kenjiArai | 0:abaa4fd0c727 | 34 | #include "WakeUp.h" |
kenjiArai | 0:abaa4fd0c727 | 35 | #include "rtc_api.h" |
kenjiArai | 0:abaa4fd0c727 | 36 | |
kenjiArai | 0:abaa4fd0c727 | 37 | #define BYTE2BCD(byte) ((byte % 10) | ((byte / 10) << 4)) |
kenjiArai | 0:abaa4fd0c727 | 38 | |
kenjiArai | 0:abaa4fd0c727 | 39 | //Most things are pretty similar between the different STM targets. |
kenjiArai | 0:abaa4fd0c727 | 40 | //Only the IRQ number the alarm is connected to differs. Any errors |
kenjiArai | 0:abaa4fd0c727 | 41 | //with RTC_IRQn/RTC_Alarm_IRQn in them are related to this |
kenjiArai | 0:abaa4fd0c727 | 42 | #if defined(TARGET_M4) || defined(TARGET_M3) |
kenjiArai | 1:bbc6b5bdd75b | 43 | #define RTC_IRQ RTC_Alarm_IRQn |
kenjiArai | 0:abaa4fd0c727 | 44 | #else |
kenjiArai | 0:abaa4fd0c727 | 45 | #define RTC_IRQ RTC_IRQn |
kenjiArai | 0:abaa4fd0c727 | 46 | #endif |
kenjiArai | 0:abaa4fd0c727 | 47 | |
kenjiArai | 0:abaa4fd0c727 | 48 | // Some things to handle Disco L476VG (and similar ones) |
kenjiArai | 0:abaa4fd0c727 | 49 | #if defined(TARGET_STM32L4) |
kenjiArai | 0:abaa4fd0c727 | 50 | #define IMR IMR1 |
kenjiArai | 0:abaa4fd0c727 | 51 | #define EMR EMR1 |
kenjiArai | 0:abaa4fd0c727 | 52 | #define RTSR RTSR1 |
kenjiArai | 0:abaa4fd0c727 | 53 | #define FTSR FTSR2 |
kenjiArai | 0:abaa4fd0c727 | 54 | #define PR PR1 |
kenjiArai | 0:abaa4fd0c727 | 55 | #endif |
kenjiArai | 0:abaa4fd0c727 | 56 | |
kenjiArai | 0:abaa4fd0c727 | 57 | void WakeUp::set_ms(uint32_t ms) |
kenjiArai | 0:abaa4fd0c727 | 58 | { |
kenjiArai | 0:abaa4fd0c727 | 59 | if (ms == 0) { //Just disable alarm |
kenjiArai | 0:abaa4fd0c727 | 60 | return; |
kenjiArai | 0:abaa4fd0c727 | 61 | } |
kenjiArai | 1:bbc6b5bdd75b | 62 | |
kenjiArai | 0:abaa4fd0c727 | 63 | if (!rtc_isenabled()) { //Make sure RTC is running |
kenjiArai | 0:abaa4fd0c727 | 64 | rtc_init(); |
kenjiArai | 0:abaa4fd0c727 | 65 | wait_us(250); //The f401 seems to want a delay after init |
kenjiArai | 0:abaa4fd0c727 | 66 | } |
kenjiArai | 0:abaa4fd0c727 | 67 | |
kenjiArai | 1:bbc6b5bdd75b | 68 | #if defined(TARGET_NUCLEO_L476RG) || defined(TARGET_DISCO_L475VG_IOT01A) |
kenjiArai | 1:bbc6b5bdd75b | 69 | PWR->CR1 |= PWR_CR1_DBP; //Enable backup domain |
kenjiArai | 1:bbc6b5bdd75b | 70 | #else |
kenjiArai | 1:bbc6b5bdd75b | 71 | PWR->CR |= PWR_CR_DBP; //Enable backup domain |
kenjiArai | 1:bbc6b5bdd75b | 72 | #endif |
kenjiArai | 0:abaa4fd0c727 | 73 | RTC->WPR = 0xCA; //Disable RTC write protection |
kenjiArai | 0:abaa4fd0c727 | 74 | RTC->WPR = 0x53; |
kenjiArai | 0:abaa4fd0c727 | 75 | |
kenjiArai | 0:abaa4fd0c727 | 76 | //Alarm must be disabled to change anything |
kenjiArai | 0:abaa4fd0c727 | 77 | RTC->CR &= ~RTC_CR_ALRAE; |
kenjiArai | 0:abaa4fd0c727 | 78 | RTC->CR &= 0x00ff00ff; |
kenjiArai | 0:abaa4fd0c727 | 79 | while(!(RTC->ISR & RTC_ISR_ALRAWF)); |
kenjiArai | 0:abaa4fd0c727 | 80 | |
kenjiArai | 0:abaa4fd0c727 | 81 | //RTC prescaler + calculate how many sub-seconds should be added |
kenjiArai | 0:abaa4fd0c727 | 82 | uint32_t prescaler = (RTC->PRER & 0x7FFF) + 1; |
kenjiArai | 0:abaa4fd0c727 | 83 | uint32_t subsecsadd = ((ms % 1000) * prescaler) / 1000; |
kenjiArai | 0:abaa4fd0c727 | 84 | |
kenjiArai | 0:abaa4fd0c727 | 85 | if ((ms < 1000) && (subsecsadd < 2)) |
kenjiArai | 0:abaa4fd0c727 | 86 | subsecsadd = 2;//At least 5 subsecs delay to be sure interrupt is called |
kenjiArai | 0:abaa4fd0c727 | 87 | |
kenjiArai | 0:abaa4fd0c727 | 88 | __disable_irq(); //At this point we don't want IRQs anymore |
kenjiArai | 0:abaa4fd0c727 | 89 | |
kenjiArai | 0:abaa4fd0c727 | 90 | //Get current time |
kenjiArai | 0:abaa4fd0c727 | 91 | uint32_t subsecs = RTC->SSR; |
kenjiArai | 1:bbc6b5bdd75b | 92 | time_t secs = rtc_read(); |
kenjiArai | 0:abaa4fd0c727 | 93 | |
kenjiArai | 0:abaa4fd0c727 | 94 | //Calculate alarm values |
kenjiArai | 0:abaa4fd0c727 | 95 | //Subseconds is countdown, |
kenjiArai | 0:abaa4fd0c727 | 96 | // so substract the 'added' sub-seconds and prevent underflow |
kenjiArai | 0:abaa4fd0c727 | 97 | if (subsecs < subsecsadd) { |
kenjiArai | 0:abaa4fd0c727 | 98 | subsecs += prescaler; |
kenjiArai | 0:abaa4fd0c727 | 99 | secs++; |
kenjiArai | 0:abaa4fd0c727 | 100 | } |
kenjiArai | 0:abaa4fd0c727 | 101 | subsecs -= subsecsadd; |
kenjiArai | 0:abaa4fd0c727 | 102 | |
kenjiArai | 0:abaa4fd0c727 | 103 | //Set seconds correctly |
kenjiArai | 0:abaa4fd0c727 | 104 | secs += ms / 1000; |
kenjiArai | 0:abaa4fd0c727 | 105 | struct tm *timeinfo = localtime(&secs); |
kenjiArai | 0:abaa4fd0c727 | 106 | |
kenjiArai | 0:abaa4fd0c727 | 107 | //Enable rising edge EXTI interrupt of the RTC |
kenjiArai | 0:abaa4fd0c727 | 108 | EXTI->IMR |= RTC_EXTI_LINE_ALARM_EVENT; // enable it |
kenjiArai | 0:abaa4fd0c727 | 109 | EXTI->EMR &= ~RTC_EXTI_LINE_ALARM_EVENT; // disable event |
kenjiArai | 0:abaa4fd0c727 | 110 | EXTI->RTSR |= RTC_EXTI_LINE_ALARM_EVENT; // enable rising edge |
kenjiArai | 0:abaa4fd0c727 | 111 | EXTI->FTSR &= ~RTC_EXTI_LINE_ALARM_EVENT; // disable falling edge |
kenjiArai | 0:abaa4fd0c727 | 112 | |
kenjiArai | 0:abaa4fd0c727 | 113 | //Calculate alarm register values |
kenjiArai | 0:abaa4fd0c727 | 114 | uint32_t alarmreg = 0; |
kenjiArai | 0:abaa4fd0c727 | 115 | alarmreg |= BYTE2BCD(timeinfo->tm_sec) << 0; |
kenjiArai | 0:abaa4fd0c727 | 116 | alarmreg |= BYTE2BCD(timeinfo->tm_min) << 8; |
kenjiArai | 0:abaa4fd0c727 | 117 | alarmreg |= BYTE2BCD(timeinfo->tm_hour) << 16; |
kenjiArai | 0:abaa4fd0c727 | 118 | alarmreg |= BYTE2BCD(timeinfo->tm_mday) << 24; |
kenjiArai | 0:abaa4fd0c727 | 119 | alarmreg &= 0x3f3f7f7f; // All MSKx & WDSEL = 0 |
kenjiArai | 0:abaa4fd0c727 | 120 | |
kenjiArai | 0:abaa4fd0c727 | 121 | //Enable RTC interrupt (use Alarm-A) |
kenjiArai | 0:abaa4fd0c727 | 122 | RTC->ALRMAR = alarmreg; |
kenjiArai | 0:abaa4fd0c727 | 123 | RTC->ALRMASSR = subsecs | RTC_ALRMASSR_MASKSS; //Mask no subseconds |
kenjiArai | 1:bbc6b5bdd75b | 124 | RTC->CR |= RTC_CR_ALRAE | RTC_CR_ALRAIE; //Enable Alarm-A |
kenjiArai | 0:abaa4fd0c727 | 125 | |
kenjiArai | 0:abaa4fd0c727 | 126 | RTC->WPR = 0xFF; //Enable RTC write protection |
kenjiArai | 1:bbc6b5bdd75b | 127 | #if defined(TARGET_NUCLEO_L476RG) || defined(TARGET_DISCO_L475VG_IOT01A) |
kenjiArai | 1:bbc6b5bdd75b | 128 | PWR->CR1 &= ~PWR_CR1_DBP; //Disable backup domain |
kenjiArai | 1:bbc6b5bdd75b | 129 | #else |
kenjiArai | 1:bbc6b5bdd75b | 130 | PWR->CR &= ~PWR_CR_DBP; //Disable backup domain |
kenjiArai | 1:bbc6b5bdd75b | 131 | #endif |
kenjiArai | 0:abaa4fd0c727 | 132 | |
kenjiArai | 0:abaa4fd0c727 | 133 | __enable_irq(); //Alarm is set, so irqs can be enabled again |
kenjiArai | 0:abaa4fd0c727 | 134 | |
kenjiArai | 0:abaa4fd0c727 | 135 | //Enable everything else |
kenjiArai | 0:abaa4fd0c727 | 136 | NVIC_SetVector(RTC_IRQ, (uint32_t)WakeUp::irq_handler); |
kenjiArai | 0:abaa4fd0c727 | 137 | NVIC_EnableIRQ(RTC_IRQ); |
kenjiArai | 0:abaa4fd0c727 | 138 | } |
kenjiArai | 0:abaa4fd0c727 | 139 | |
kenjiArai | 0:abaa4fd0c727 | 140 | void WakeUp::standby_then_reset(uint32_t ms) |
kenjiArai | 0:abaa4fd0c727 | 141 | { |
kenjiArai | 1:bbc6b5bdd75b | 142 | if (ms == 0) { // just go to Reset |
kenjiArai | 0:abaa4fd0c727 | 143 | system_reset(); |
kenjiArai | 1:bbc6b5bdd75b | 144 | } |
kenjiArai | 0:abaa4fd0c727 | 145 | set_ms(ms); |
kenjiArai | 1:bbc6b5bdd75b | 146 | #if defined(TARGET_NUCLEO_L476RG) || defined(TARGET_DISCO_L475VG_IOT01A) |
kenjiArai | 1:bbc6b5bdd75b | 147 | __HAL_RCC_PWR_CLK_ENABLE(); |
kenjiArai | 1:bbc6b5bdd75b | 148 | HAL_PWREx_EnterSHUTDOWNMode(); |
kenjiArai | 1:bbc6b5bdd75b | 149 | #else |
kenjiArai | 0:abaa4fd0c727 | 150 | PWR->CR |= PWR_CR_CWUF; |
kenjiArai | 0:abaa4fd0c727 | 151 | HAL_PWR_EnterSTANDBYMode(); |
kenjiArai | 1:bbc6b5bdd75b | 152 | #endif |
kenjiArai | 0:abaa4fd0c727 | 153 | } |
kenjiArai | 0:abaa4fd0c727 | 154 | |
kenjiArai | 0:abaa4fd0c727 | 155 | void WakeUp::irq_handler(void) |
kenjiArai | 0:abaa4fd0c727 | 156 | { |
kenjiArai | 0:abaa4fd0c727 | 157 | //Clear RTC + EXTI interrupt flags |
kenjiArai | 1:bbc6b5bdd75b | 158 | #if defined(TARGET_NUCLEO_L476RG) || defined(TARGET_DISCO_L475VG_IOT01A) |
kenjiArai | 1:bbc6b5bdd75b | 159 | PWR->CR1 |= PWR_CR1_DBP; // Enable power domain |
kenjiArai | 1:bbc6b5bdd75b | 160 | #else |
kenjiArai | 0:abaa4fd0c727 | 161 | PWR->CR |= PWR_CR_DBP; // Enable power domain |
kenjiArai | 1:bbc6b5bdd75b | 162 | #endif |
kenjiArai | 0:abaa4fd0c727 | 163 | RTC->ISR &= ~RTC_ISR_ALRAF; |
kenjiArai | 1:bbc6b5bdd75b | 164 | #if defined(TARGET_NUCLEO_L476RG) || defined(TARGET_DISCO_L475VG_IOT01A) |
kenjiArai | 1:bbc6b5bdd75b | 165 | //RTC->CR &= 0x00ff00ff; // just in case |
kenjiArai | 1:bbc6b5bdd75b | 166 | #else |
kenjiArai | 0:abaa4fd0c727 | 167 | RTC->CR &= 0x00ff00ff; // just in case |
kenjiArai | 1:bbc6b5bdd75b | 168 | #endif |
kenjiArai | 0:abaa4fd0c727 | 169 | RTC->WPR = 0xCA; // Disable RTC write protection |
kenjiArai | 0:abaa4fd0c727 | 170 | RTC->WPR = 0x53; |
kenjiArai | 1:bbc6b5bdd75b | 171 | RTC->CR &= ~(RTC_CR_ALRAE | RTC_CR_ALRAIE); //Disable Alarm-A |
kenjiArai | 0:abaa4fd0c727 | 172 | RTC->WPR = 0xFF; // Enable RTC write protection |
kenjiArai | 1:bbc6b5bdd75b | 173 | EXTI->PR = RTC_EXTI_LINE_ALARM_EVENT; |
kenjiArai | 1:bbc6b5bdd75b | 174 | #if defined(TARGET_NUCLEO_L476RG) || defined(TARGET_DISCO_L475VG_IOT01A) |
kenjiArai | 1:bbc6b5bdd75b | 175 | PWR->CR1 &= ~PWR_CR1_DBP; // Disable power domain |
kenjiArai | 1:bbc6b5bdd75b | 176 | #else |
kenjiArai | 0:abaa4fd0c727 | 177 | PWR->CR &= ~PWR_CR_DBP; // Disable power domain |
kenjiArai | 1:bbc6b5bdd75b | 178 | #endif |
kenjiArai | 0:abaa4fd0c727 | 179 | system_reset(); |
kenjiArai | 0:abaa4fd0c727 | 180 | } |
kenjiArai | 0:abaa4fd0c727 | 181 | |
kenjiArai | 0:abaa4fd0c727 | 182 | #endif |