Revised by I. Cserny
Dependents: Lab04_Check_StandBy_os2 Lab04_wakeup_STM32
WakeUp_STM32.cpp
00001 /* 00002 00003 Original idea & program 00004 https://os.mbed.com/users/Sissors/code/WakeUp/ 00005 by Erik 00006 00007 modified version 00008 https://os.mbed.com/users/kenjiArai/code/WakeUp/ 00009 */ 00010 00011 /* 00012 * Modified only for STM CPU 00013 * by Kenji Arai / JH1PJL 00014 * 00015 * http://www7b.biglobe.ne.jp/~kenjia/ 00016 * http://mbed.org/users/kenjiArai/ 00017 * Created: September 21st, 2017 00018 * Revised: March 12th, 2020 00019 */ 00020 00021 #if \ 00022 defined(TARGET_NUCLEO_F334R8) 00023 # error Not support yet 00024 #elif \ 00025 defined(TARGET_NUCLEO_F401RE)\ 00026 || defined(TARGET_NUCLEO_F411RE)\ 00027 || defined(TARGET_NUCLEO_F446RE)\ 00028 || defined(TARGET_NUCLEO_L053R8)\ 00029 || defined(TARGET_NUCLEO_L073RZ)\ 00030 || defined(TARGET_NUCLEO_L152RE) 00031 00032 #include "WakeUp_STM32.h" 00033 #include "rtc_api.h" 00034 00035 #define BYTE2BCD(byte) ((byte % 10) | ((byte / 10) << 4)) 00036 00037 //Most things are pretty similar between the different STM targets. 00038 //Only the IRQ number the alarm is connected to differs. Any errors 00039 //with RTC_IRQn/RTC_Alarm_IRQn in them are related to this 00040 #if defined(TARGET_M4) || defined(TARGET_M3) 00041 #define RTC_IRQ RTC_Alarm_IRQn 00042 #else 00043 #define RTC_IRQ RTC_IRQn 00044 #endif 00045 00046 // Some things to handle Disco L476VG (and similar ones) 00047 #if defined(TARGET_STM32L4) 00048 #define IMR IMR1 00049 #define EMR EMR1 00050 #define RTSR RTSR1 00051 #define FTSR FTSR2 00052 #define PR PR1 00053 #endif 00054 00055 void WakeUp::set_ms(uint32_t ms) 00056 { 00057 if (ms == 0) { //Just disable alarm 00058 return; 00059 } 00060 00061 if (!rtc_isenabled()) { //Make sure RTC is running 00062 rtc_init(); 00063 wait_us(250); //The f401 seems to want a delay after init 00064 } 00065 00066 PWR->CR |= PWR_CR_DBP; //Enable power domain 00067 RTC->WPR = 0xCA; //Disable RTC write protection 00068 RTC->WPR = 0x53; 00069 00070 //Alarm must be disabled to change anything 00071 RTC->CR &= ~RTC_CR_ALRAE; 00072 RTC->CR &= 0x00ff00ff; 00073 while(!(RTC->ISR & RTC_ISR_ALRAWF)); 00074 00075 //RTC prescaler + calculate how many sub-seconds should be added 00076 uint32_t prescaler = (RTC->PRER & 0x7FFF) + 1; 00077 uint32_t subsecsadd = ((ms % 1000) * prescaler) / 1000; 00078 00079 if ((ms < 1000) && (subsecsadd < 2)) 00080 subsecsadd = 2;//At least 5 subsecs delay to be sure interrupt is called 00081 00082 __disable_irq(); //At this point we don't want IRQs anymore 00083 00084 //Get current time 00085 uint32_t subsecs = RTC->SSR; 00086 time_t secs = rtc_read(); 00087 00088 //Calculate alarm values 00089 //Subseconds is countdown, 00090 // so substract the 'added' sub-seconds and prevent underflow 00091 if (subsecs < subsecsadd) { 00092 subsecs += prescaler; 00093 secs++; 00094 } 00095 subsecs -= subsecsadd; 00096 00097 //Set seconds correctly 00098 secs += ms / 1000; 00099 struct tm *timeinfo = localtime(&secs); 00100 00101 //Enable rising edge EXTI interrupt of the RTC 00102 EXTI->IMR |= RTC_EXTI_LINE_ALARM_EVENT; // enable it 00103 EXTI->EMR &= ~RTC_EXTI_LINE_ALARM_EVENT; // disable event 00104 EXTI->RTSR |= RTC_EXTI_LINE_ALARM_EVENT; // enable rising edge 00105 EXTI->FTSR &= ~RTC_EXTI_LINE_ALARM_EVENT; // disable falling edge 00106 00107 //Calculate alarm register values 00108 uint32_t alarmreg = 0; 00109 alarmreg |= BYTE2BCD(timeinfo->tm_sec) << 0; 00110 alarmreg |= BYTE2BCD(timeinfo->tm_min) << 8; 00111 alarmreg |= BYTE2BCD(timeinfo->tm_hour) << 16; 00112 alarmreg |= BYTE2BCD(timeinfo->tm_mday) << 24; 00113 alarmreg &= 0x3f3f7f7f; // All MSKx & WDSEL = 0 00114 00115 //Enable RTC interrupt (use Alarm-A) 00116 RTC->ALRMAR = alarmreg; 00117 RTC->ALRMASSR = subsecs | RTC_ALRMASSR_MASKSS; //Mask no subseconds 00118 RTC->CR |= RTC_CR_ALRAE | RTC_CR_ALRAIE; //Enable Alarm-A 00119 00120 RTC->WPR = 0xFF; //Enable RTC write protection 00121 PWR->CR &= ~PWR_CR_DBP; //Disable power domain 00122 00123 __enable_irq(); //Alarm is set, so irqs can be enabled again 00124 00125 //Enable everything else 00126 NVIC_SetVector(RTC_IRQ, (uint32_t)WakeUp::irq_handler); 00127 NVIC_EnableIRQ(RTC_IRQ); 00128 } 00129 00130 void WakeUp::standby_then_reset(uint32_t ms) 00131 { 00132 if (ms == 0){ // just go to Reset 00133 system_reset(); 00134 } 00135 set_ms(ms); 00136 PWR->CR |= PWR_CR_CWUF; 00137 HAL_PWR_EnterSTANDBYMode(); 00138 } 00139 00140 void WakeUp::irq_handler(void) 00141 { 00142 //Clear RTC + EXTI interrupt flags 00143 PWR->CR |= PWR_CR_DBP; // Enable power domain 00144 RTC->ISR &= ~RTC_ISR_ALRAF; 00145 RTC->CR &= 0x00ff00ff; // just in case 00146 RTC->WPR = 0xCA; // Disable RTC write protection 00147 RTC->WPR = 0x53; 00148 RTC->CR &= ~(RTC_CR_ALRAE | RTC_CR_ALRAIE); //DisEnable Alarm-A 00149 RTC->WPR = 0xFF; // Enable RTC write protection 00150 EXTI->PR = RTC_EXTI_LINE_ALARM_EVENT; 00151 PWR->CR &= ~PWR_CR_DBP; // Disable power domain 00152 system_reset(); 00153 } 00154 00155 #endif
Generated on Wed Aug 17 2022 03:46:58 by
1.7.2