This is the code used on my video series "Hybrid Supercapacitor Car Battery" for my own hardware monitoring system. THe videos can be found on madelectronengineering.com
Dependencies: BurstSPI Fonts INA219 mbed LPC1114_WakeInterruptIn
Fork of SharpMemoryLCD by
WakeUp_STM32_others.cpp
00001 // Created new file only for STM32/Nucleo boards which I have own it 00002 // by JH1PJL 2017-9-21 00003 00004 #if defined(TARGET_NUCLEO_F446RE) || defined(TARGET_NUCLEO_F411RE)\ 00005 || defined(TARGET_NUCLEO_F401RE)\ 00006 || defined(TARGET_NUCLEO_L152RE) || defined(TARGET_NUCLEO_L073RZ)\ 00007 || defined(TARGET_NUCLEO_L053R8) 00008 00009 #include "WakeUp.h" 00010 #include "rtc_api.h" 00011 00012 //#define DEBUG 00013 00014 extern Serial pc; 00015 00016 #if 0 00017 #define DBG(...) pc.printf(__VA_ARGS__) 00018 #else 00019 #define DBG(...) {;} 00020 #endif 00021 00022 #if 0 00023 #define DBGP(...) pc.printf(__VA_ARGS__) 00024 #else 00025 #define DBGP(...) {;} 00026 #endif 00027 00028 #define BYTE2BCD(byte) ((byte % 10) | ((byte / 10) << 4)) 00029 00030 //Most things are pretty similar between the different STM targets. 00031 //Only the IRQ number the alarm is connected to differs. Any errors 00032 //with RTC_IRQn/RTC_Alarm_IRQn in them are related to this 00033 #if defined(TARGET_M4) || defined(TARGET_M3) 00034 #define RTC_IRQ RTC_Alarm_IRQn 00035 #else 00036 #define RTC_IRQ RTC_IRQn 00037 #endif 00038 00039 // Some things to handle Disco L476VG (and similar ones) 00040 #if defined(TARGET_STM32L4) 00041 #define IMR IMR1 00042 #define EMR EMR1 00043 #define RTSR RTSR1 00044 #define FTSR FTSR2 00045 #define PR PR1 00046 #endif 00047 00048 Callback<void()> WakeUp::callback; 00049 bool WakeUp::use_reset = false; 00050 00051 00052 void WakeUp::set_ms(uint32_t ms) 00053 { 00054 if (ms == 0) { //Just disable alarm 00055 return; 00056 } 00057 00058 if (!rtc_isenabled()) { //Make sure RTC is running 00059 rtc_init(); 00060 wait_us(250); //The f401 seems to want a delay after init 00061 } 00062 00063 PWR->CR |= PWR_CR_DBP; //Enable power domain 00064 RTC->WPR = 0xCA; //Disable RTC write protection 00065 RTC->WPR = 0x53; 00066 00067 //Alarm must be disabled to change anything 00068 RTC->CR &= ~RTC_CR_ALRAE; 00069 RTC->CR &= 0x00ff00ff; 00070 while(!(RTC->ISR & RTC_ISR_ALRAWF)); 00071 00072 DBG("Step(%u)\r\n", __LINE__); 00073 00074 //RTC prescaler + calculate how many sub-seconds should be added 00075 uint32_t prescaler = (RTC->PRER & 0x7FFF) + 1; 00076 uint32_t subsecsadd = ((ms % 1000) * prescaler) / 1000; 00077 00078 if ((ms < 1000) && (subsecsadd < 2)) 00079 subsecsadd = 2;//At least 5 subsecs delay to be sure interrupt is called 00080 00081 __disable_irq(); //At this point we don't want IRQs anymore 00082 00083 //Get current time 00084 uint32_t subsecs = RTC->SSR; 00085 time_t secs = rtc_read(); 00086 DBG("Step(%u),secs:%d,subsecs:%d\r\n", __LINE__, secs, subsecs); 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 DBG("Step(%u),secs:%d\r\n", __LINE__, secs); 00101 00102 //Enable rising edge EXTI interrupt of the RTC 00103 EXTI->IMR |= RTC_EXTI_LINE_ALARM_EVENT; // enable it 00104 EXTI->EMR &= ~RTC_EXTI_LINE_ALARM_EVENT; // disable event 00105 EXTI->RTSR |= RTC_EXTI_LINE_ALARM_EVENT; // enable rising edge 00106 EXTI->FTSR &= ~RTC_EXTI_LINE_ALARM_EVENT; // disable falling edge 00107 00108 //Calculate alarm register values 00109 uint32_t alarmreg = 0; 00110 alarmreg |= BYTE2BCD(timeinfo->tm_sec) << 0; 00111 alarmreg |= BYTE2BCD(timeinfo->tm_min) << 8; 00112 alarmreg |= BYTE2BCD(timeinfo->tm_hour) << 16; 00113 alarmreg |= BYTE2BCD(timeinfo->tm_mday) << 24; 00114 alarmreg &= 0x3f3f7f7f; // All MSKx & WDSEL = 0 00115 00116 //Enable RTC interrupt (use Alarm-A) 00117 DBG("Step(%u),alarmreg:0x%08x\r\n", __LINE__, alarmreg); 00118 DBG("Step(%u),RTC->ISR:0x%08x\r\n", __LINE__, RTC->ISR); 00119 RTC->ALRMAR = alarmreg; 00120 RTC->ALRMASSR = subsecs | RTC_ALRMASSR_MASKSS; //Mask no subseconds 00121 DBG("Step(%u),alarmreg(reg):0x%08x\r\n", __LINE__, RTC->ALRMAR); 00122 RTC->CR |= RTC_CR_ALRAE | RTC_CR_ALRAIE; //Enable Alarm-A 00123 DBG("Step(%u),RTC->CR:0x%08x\r\n", __LINE__, RTC->CR); 00124 00125 RTC->WPR = 0xFF; //Enable RTC write protection 00126 PWR->CR &= ~PWR_CR_DBP; //Disable power domain 00127 00128 __enable_irq(); //Alarm is set, so irqs can be enabled again 00129 00130 //Enable everything else 00131 NVIC_SetVector(RTC_IRQ, (uint32_t)WakeUp::irq_handler); 00132 NVIC_EnableIRQ(RTC_IRQ); 00133 use_reset = false; 00134 //---- Only for Debug purpose 00135 DBGP("PWR->CR 0x%08x:0x%08x\r\n",&PWR->CR, PWR->CR); 00136 DBGP("PWR->CSR 0x%08x:0x%08x\r\n",&PWR->CSR, PWR->CSR); 00137 DBGP("SCB->SCR 0x%08x:0x%08x\r\n",&SCB->SCR, SCB->SCR); 00138 DBGP("SCB->AIRCR 0x%08x:0x%08x\r\n",&SCB->AIRCR, SCB->AIRCR); 00139 DBGP("EXTI->IMR 0x%08x:0x%08x\r\n",&EXTI->IMR, EXTI->IMR); 00140 DBGP("EXTI->EMR 0x%08x:0x%08x\r\n",&EXTI->EMR, EXTI->EMR); 00141 DBGP("EXTI->RTSR 0x%08x:0x%08x\r\n",&EXTI->RTSR, EXTI->RTSR); 00142 DBGP("EXTI->FTSR 0x%08x:0x%08x\r\n",&EXTI->FTSR, EXTI->FTSR); 00143 DBGP("RTC->TR 0x%08x:0x%08x\r\n",&RTC->TR,RTC->TR); 00144 DBGP("RTC->DR 0x%08x:0x%08x\r\n",&RTC->DR,RTC->DR); 00145 DBGP("RTC->CR 0x%08x:0x%08x\r\n",&RTC->CR,RTC->CR); 00146 DBGP("RTC->ISR 0x%08x:0x%08x\r\n",&RTC->ISR,RTC->ISR); 00147 DBGP("RTC->ALRMAR 0x%08x:0x%08x\r\n",&RTC->ALRMAR,RTC->ALRMAR); 00148 } 00149 00150 void WakeUp::standby_then_reset(uint32_t ms) 00151 { 00152 DBG("Step(%u),ms:%d\r\n", __LINE__, ms); 00153 if (ms == 0){ // just go to Reset 00154 __NVIC_SystemReset(); 00155 } 00156 set_ms(ms); 00157 use_reset = true; 00158 PWR->CR |= PWR_CR_CWUF; 00159 HAL_PWR_EnterSTANDBYMode(); 00160 } 00161 00162 void WakeUp::irq_handler(void) 00163 { 00164 //Clear RTC + EXTI interrupt flags 00165 PWR->CR |= PWR_CR_DBP; // Enable power domain 00166 RTC->ISR &= ~RTC_ISR_ALRAF; 00167 RTC->CR &= 0x00ff00ff; // just in case 00168 RTC->WPR = 0xCA; // Disable RTC write protection 00169 RTC->WPR = 0x53; 00170 RTC->CR &= ~(RTC_CR_ALRAE | RTC_CR_ALRAIE); //DisEnable Alarm-A 00171 RTC->WPR = 0xFF; // Enable RTC write protection 00172 EXTI->PR = RTC_EXTI_LINE_ALARM_EVENT; 00173 PWR->CR &= ~PWR_CR_DBP; // Disable power domain 00174 if (use_reset == true){ 00175 NVIC_SystemReset(); 00176 } else { 00177 if (callback){ 00178 callback.call(); 00179 } 00180 } 00181 } 00182 00183 void WakeUp::calibrate(void) 00184 { 00185 //RTC, we assume it is accurate enough without calibration 00186 } 00187 00188 #endif
Generated on Wed Jul 13 2022 09:15:42 by 1.7.2