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/

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?

UserRevisionLine numberNew 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