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:
Thu Mar 12 09:27:30 2020 +0000
Revision:
0:abaa4fd0c727
Child:
1:bbc6b5bdd75b
Enter Standby mode then wake up(only restart) by RTC timer

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 0:abaa4fd0c727 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 0:abaa4fd0c727 18 * Revised: March 12th, 2020
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 0:abaa4fd0c727 30 || defined(TARGET_NUCLEO_L152RE)
kenjiArai 0:abaa4fd0c727 31
kenjiArai 0:abaa4fd0c727 32 #include "WakeUp.h"
kenjiArai 0:abaa4fd0c727 33 #include "rtc_api.h"
kenjiArai 0:abaa4fd0c727 34
kenjiArai 0:abaa4fd0c727 35 #define BYTE2BCD(byte) ((byte % 10) | ((byte / 10) << 4))
kenjiArai 0:abaa4fd0c727 36
kenjiArai 0:abaa4fd0c727 37 //Most things are pretty similar between the different STM targets.
kenjiArai 0:abaa4fd0c727 38 //Only the IRQ number the alarm is connected to differs. Any errors
kenjiArai 0:abaa4fd0c727 39 //with RTC_IRQn/RTC_Alarm_IRQn in them are related to this
kenjiArai 0:abaa4fd0c727 40 #if defined(TARGET_M4) || defined(TARGET_M3)
kenjiArai 0:abaa4fd0c727 41 #define RTC_IRQ RTC_Alarm_IRQn
kenjiArai 0:abaa4fd0c727 42 #else
kenjiArai 0:abaa4fd0c727 43 #define RTC_IRQ RTC_IRQn
kenjiArai 0:abaa4fd0c727 44 #endif
kenjiArai 0:abaa4fd0c727 45
kenjiArai 0:abaa4fd0c727 46 // Some things to handle Disco L476VG (and similar ones)
kenjiArai 0:abaa4fd0c727 47 #if defined(TARGET_STM32L4)
kenjiArai 0:abaa4fd0c727 48 #define IMR IMR1
kenjiArai 0:abaa4fd0c727 49 #define EMR EMR1
kenjiArai 0:abaa4fd0c727 50 #define RTSR RTSR1
kenjiArai 0:abaa4fd0c727 51 #define FTSR FTSR2
kenjiArai 0:abaa4fd0c727 52 #define PR PR1
kenjiArai 0:abaa4fd0c727 53 #endif
kenjiArai 0:abaa4fd0c727 54
kenjiArai 0:abaa4fd0c727 55 void WakeUp::set_ms(uint32_t ms)
kenjiArai 0:abaa4fd0c727 56 {
kenjiArai 0:abaa4fd0c727 57 if (ms == 0) { //Just disable alarm
kenjiArai 0:abaa4fd0c727 58 return;
kenjiArai 0:abaa4fd0c727 59 }
kenjiArai 0:abaa4fd0c727 60
kenjiArai 0:abaa4fd0c727 61 if (!rtc_isenabled()) { //Make sure RTC is running
kenjiArai 0:abaa4fd0c727 62 rtc_init();
kenjiArai 0:abaa4fd0c727 63 wait_us(250); //The f401 seems to want a delay after init
kenjiArai 0:abaa4fd0c727 64 }
kenjiArai 0:abaa4fd0c727 65
kenjiArai 0:abaa4fd0c727 66 PWR->CR |= PWR_CR_DBP; //Enable power domain
kenjiArai 0:abaa4fd0c727 67 RTC->WPR = 0xCA; //Disable RTC write protection
kenjiArai 0:abaa4fd0c727 68 RTC->WPR = 0x53;
kenjiArai 0:abaa4fd0c727 69
kenjiArai 0:abaa4fd0c727 70 //Alarm must be disabled to change anything
kenjiArai 0:abaa4fd0c727 71 RTC->CR &= ~RTC_CR_ALRAE;
kenjiArai 0:abaa4fd0c727 72 RTC->CR &= 0x00ff00ff;
kenjiArai 0:abaa4fd0c727 73 while(!(RTC->ISR & RTC_ISR_ALRAWF));
kenjiArai 0:abaa4fd0c727 74
kenjiArai 0:abaa4fd0c727 75 //RTC prescaler + calculate how many sub-seconds should be added
kenjiArai 0:abaa4fd0c727 76 uint32_t prescaler = (RTC->PRER & 0x7FFF) + 1;
kenjiArai 0:abaa4fd0c727 77 uint32_t subsecsadd = ((ms % 1000) * prescaler) / 1000;
kenjiArai 0:abaa4fd0c727 78
kenjiArai 0:abaa4fd0c727 79 if ((ms < 1000) && (subsecsadd < 2))
kenjiArai 0:abaa4fd0c727 80 subsecsadd = 2;//At least 5 subsecs delay to be sure interrupt is called
kenjiArai 0:abaa4fd0c727 81
kenjiArai 0:abaa4fd0c727 82 __disable_irq(); //At this point we don't want IRQs anymore
kenjiArai 0:abaa4fd0c727 83
kenjiArai 0:abaa4fd0c727 84 //Get current time
kenjiArai 0:abaa4fd0c727 85 uint32_t subsecs = RTC->SSR;
kenjiArai 0:abaa4fd0c727 86 time_t secs = rtc_read();
kenjiArai 0:abaa4fd0c727 87
kenjiArai 0:abaa4fd0c727 88 //Calculate alarm values
kenjiArai 0:abaa4fd0c727 89 //Subseconds is countdown,
kenjiArai 0:abaa4fd0c727 90 // so substract the 'added' sub-seconds and prevent underflow
kenjiArai 0:abaa4fd0c727 91 if (subsecs < subsecsadd) {
kenjiArai 0:abaa4fd0c727 92 subsecs += prescaler;
kenjiArai 0:abaa4fd0c727 93 secs++;
kenjiArai 0:abaa4fd0c727 94 }
kenjiArai 0:abaa4fd0c727 95 subsecs -= subsecsadd;
kenjiArai 0:abaa4fd0c727 96
kenjiArai 0:abaa4fd0c727 97 //Set seconds correctly
kenjiArai 0:abaa4fd0c727 98 secs += ms / 1000;
kenjiArai 0:abaa4fd0c727 99 struct tm *timeinfo = localtime(&secs);
kenjiArai 0:abaa4fd0c727 100
kenjiArai 0:abaa4fd0c727 101 //Enable rising edge EXTI interrupt of the RTC
kenjiArai 0:abaa4fd0c727 102 EXTI->IMR |= RTC_EXTI_LINE_ALARM_EVENT; // enable it
kenjiArai 0:abaa4fd0c727 103 EXTI->EMR &= ~RTC_EXTI_LINE_ALARM_EVENT; // disable event
kenjiArai 0:abaa4fd0c727 104 EXTI->RTSR |= RTC_EXTI_LINE_ALARM_EVENT; // enable rising edge
kenjiArai 0:abaa4fd0c727 105 EXTI->FTSR &= ~RTC_EXTI_LINE_ALARM_EVENT; // disable falling edge
kenjiArai 0:abaa4fd0c727 106
kenjiArai 0:abaa4fd0c727 107 //Calculate alarm register values
kenjiArai 0:abaa4fd0c727 108 uint32_t alarmreg = 0;
kenjiArai 0:abaa4fd0c727 109 alarmreg |= BYTE2BCD(timeinfo->tm_sec) << 0;
kenjiArai 0:abaa4fd0c727 110 alarmreg |= BYTE2BCD(timeinfo->tm_min) << 8;
kenjiArai 0:abaa4fd0c727 111 alarmreg |= BYTE2BCD(timeinfo->tm_hour) << 16;
kenjiArai 0:abaa4fd0c727 112 alarmreg |= BYTE2BCD(timeinfo->tm_mday) << 24;
kenjiArai 0:abaa4fd0c727 113 alarmreg &= 0x3f3f7f7f; // All MSKx & WDSEL = 0
kenjiArai 0:abaa4fd0c727 114
kenjiArai 0:abaa4fd0c727 115 //Enable RTC interrupt (use Alarm-A)
kenjiArai 0:abaa4fd0c727 116 RTC->ALRMAR = alarmreg;
kenjiArai 0:abaa4fd0c727 117 RTC->ALRMASSR = subsecs | RTC_ALRMASSR_MASKSS; //Mask no subseconds
kenjiArai 0:abaa4fd0c727 118 RTC->CR |= RTC_CR_ALRAE | RTC_CR_ALRAIE; //Enable Alarm-A
kenjiArai 0:abaa4fd0c727 119
kenjiArai 0:abaa4fd0c727 120 RTC->WPR = 0xFF; //Enable RTC write protection
kenjiArai 0:abaa4fd0c727 121 PWR->CR &= ~PWR_CR_DBP; //Disable power domain
kenjiArai 0:abaa4fd0c727 122
kenjiArai 0:abaa4fd0c727 123 __enable_irq(); //Alarm is set, so irqs can be enabled again
kenjiArai 0:abaa4fd0c727 124
kenjiArai 0:abaa4fd0c727 125 //Enable everything else
kenjiArai 0:abaa4fd0c727 126 NVIC_SetVector(RTC_IRQ, (uint32_t)WakeUp::irq_handler);
kenjiArai 0:abaa4fd0c727 127 NVIC_EnableIRQ(RTC_IRQ);
kenjiArai 0:abaa4fd0c727 128 }
kenjiArai 0:abaa4fd0c727 129
kenjiArai 0:abaa4fd0c727 130 void WakeUp::standby_then_reset(uint32_t ms)
kenjiArai 0:abaa4fd0c727 131 {
kenjiArai 0:abaa4fd0c727 132 if (ms == 0){ // just go to Reset
kenjiArai 0:abaa4fd0c727 133 system_reset();
kenjiArai 0:abaa4fd0c727 134 }
kenjiArai 0:abaa4fd0c727 135 set_ms(ms);
kenjiArai 0:abaa4fd0c727 136 PWR->CR |= PWR_CR_CWUF;
kenjiArai 0:abaa4fd0c727 137 HAL_PWR_EnterSTANDBYMode();
kenjiArai 0:abaa4fd0c727 138 }
kenjiArai 0:abaa4fd0c727 139
kenjiArai 0:abaa4fd0c727 140 void WakeUp::irq_handler(void)
kenjiArai 0:abaa4fd0c727 141 {
kenjiArai 0:abaa4fd0c727 142 //Clear RTC + EXTI interrupt flags
kenjiArai 0:abaa4fd0c727 143 PWR->CR |= PWR_CR_DBP; // Enable power domain
kenjiArai 0:abaa4fd0c727 144 RTC->ISR &= ~RTC_ISR_ALRAF;
kenjiArai 0:abaa4fd0c727 145 RTC->CR &= 0x00ff00ff; // just in case
kenjiArai 0:abaa4fd0c727 146 RTC->WPR = 0xCA; // Disable RTC write protection
kenjiArai 0:abaa4fd0c727 147 RTC->WPR = 0x53;
kenjiArai 0:abaa4fd0c727 148 RTC->CR &= ~(RTC_CR_ALRAE | RTC_CR_ALRAIE); //DisEnable Alarm-A
kenjiArai 0:abaa4fd0c727 149 RTC->WPR = 0xFF; // Enable RTC write protection
kenjiArai 0:abaa4fd0c727 150 EXTI->PR = RTC_EXTI_LINE_ALARM_EVENT;
kenjiArai 0:abaa4fd0c727 151 PWR->CR &= ~PWR_CR_DBP; // Disable power domain
kenjiArai 0:abaa4fd0c727 152 system_reset();
kenjiArai 0:abaa4fd0c727 153 }
kenjiArai 0:abaa4fd0c727 154
kenjiArai 0:abaa4fd0c727 155 #endif