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
Diff: Device/WakeUp_STM32_others.cpp
- Revision:
- 2:0c49a8f32f6e
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Device/WakeUp_STM32_others.cpp Tue Dec 26 21:30:09 2017 +0000 @@ -0,0 +1,188 @@ +// Created new file only for STM32/Nucleo boards which I have own it +// by JH1PJL 2017-9-21 + +#if defined(TARGET_NUCLEO_F446RE) || defined(TARGET_NUCLEO_F411RE)\ + || defined(TARGET_NUCLEO_F401RE)\ + || defined(TARGET_NUCLEO_L152RE) || defined(TARGET_NUCLEO_L073RZ)\ + || defined(TARGET_NUCLEO_L053R8) + +#include "WakeUp.h" +#include "rtc_api.h" + +//#define DEBUG + +extern Serial pc; + +#if 0 +#define DBG(...) pc.printf(__VA_ARGS__) +#else +#define DBG(...) {;} +#endif + +#if 0 +#define DBGP(...) pc.printf(__VA_ARGS__) +#else +#define DBGP(...) {;} +#endif + +#define BYTE2BCD(byte) ((byte % 10) | ((byte / 10) << 4)) + +//Most things are pretty similar between the different STM targets. +//Only the IRQ number the alarm is connected to differs. Any errors +//with RTC_IRQn/RTC_Alarm_IRQn in them are related to this +#if defined(TARGET_M4) || defined(TARGET_M3) +#define RTC_IRQ RTC_Alarm_IRQn +#else +#define RTC_IRQ RTC_IRQn +#endif + +// Some things to handle Disco L476VG (and similar ones) +#if defined(TARGET_STM32L4) +#define IMR IMR1 +#define EMR EMR1 +#define RTSR RTSR1 +#define FTSR FTSR2 +#define PR PR1 +#endif + +Callback<void()> WakeUp::callback; +bool WakeUp::use_reset = false; + + +void WakeUp::set_ms(uint32_t ms) +{ + if (ms == 0) { //Just disable alarm + return; + } + + if (!rtc_isenabled()) { //Make sure RTC is running + rtc_init(); + wait_us(250); //The f401 seems to want a delay after init + } + + PWR->CR |= PWR_CR_DBP; //Enable power domain + RTC->WPR = 0xCA; //Disable RTC write protection + RTC->WPR = 0x53; + + //Alarm must be disabled to change anything + RTC->CR &= ~RTC_CR_ALRAE; + RTC->CR &= 0x00ff00ff; + while(!(RTC->ISR & RTC_ISR_ALRAWF)); + + DBG("Step(%u)\r\n", __LINE__); + + //RTC prescaler + calculate how many sub-seconds should be added + uint32_t prescaler = (RTC->PRER & 0x7FFF) + 1; + uint32_t subsecsadd = ((ms % 1000) * prescaler) / 1000; + + if ((ms < 1000) && (subsecsadd < 2)) + subsecsadd = 2;//At least 5 subsecs delay to be sure interrupt is called + + __disable_irq(); //At this point we don't want IRQs anymore + + //Get current time + uint32_t subsecs = RTC->SSR; + time_t secs = rtc_read(); + DBG("Step(%u),secs:%d,subsecs:%d\r\n", __LINE__, secs, subsecs); + + //Calculate alarm values + //Subseconds is countdown, + // so substract the 'added' sub-seconds and prevent underflow + if (subsecs < subsecsadd) { + subsecs += prescaler; + secs++; + } + subsecs -= subsecsadd; + + //Set seconds correctly + secs += ms / 1000; + struct tm *timeinfo = localtime(&secs); + DBG("Step(%u),secs:%d\r\n", __LINE__, secs); + + //Enable rising edge EXTI interrupt of the RTC + EXTI->IMR |= RTC_EXTI_LINE_ALARM_EVENT; // enable it + EXTI->EMR &= ~RTC_EXTI_LINE_ALARM_EVENT; // disable event + EXTI->RTSR |= RTC_EXTI_LINE_ALARM_EVENT; // enable rising edge + EXTI->FTSR &= ~RTC_EXTI_LINE_ALARM_EVENT; // disable falling edge + + //Calculate alarm register values + uint32_t alarmreg = 0; + alarmreg |= BYTE2BCD(timeinfo->tm_sec) << 0; + alarmreg |= BYTE2BCD(timeinfo->tm_min) << 8; + alarmreg |= BYTE2BCD(timeinfo->tm_hour) << 16; + alarmreg |= BYTE2BCD(timeinfo->tm_mday) << 24; + alarmreg &= 0x3f3f7f7f; // All MSKx & WDSEL = 0 + + //Enable RTC interrupt (use Alarm-A) + DBG("Step(%u),alarmreg:0x%08x\r\n", __LINE__, alarmreg); + DBG("Step(%u),RTC->ISR:0x%08x\r\n", __LINE__, RTC->ISR); + RTC->ALRMAR = alarmreg; + RTC->ALRMASSR = subsecs | RTC_ALRMASSR_MASKSS; //Mask no subseconds + DBG("Step(%u),alarmreg(reg):0x%08x\r\n", __LINE__, RTC->ALRMAR); + RTC->CR |= RTC_CR_ALRAE | RTC_CR_ALRAIE; //Enable Alarm-A + DBG("Step(%u),RTC->CR:0x%08x\r\n", __LINE__, RTC->CR); + + RTC->WPR = 0xFF; //Enable RTC write protection + PWR->CR &= ~PWR_CR_DBP; //Disable power domain + + __enable_irq(); //Alarm is set, so irqs can be enabled again + + //Enable everything else + NVIC_SetVector(RTC_IRQ, (uint32_t)WakeUp::irq_handler); + NVIC_EnableIRQ(RTC_IRQ); + use_reset = false; + //---- Only for Debug purpose + DBGP("PWR->CR 0x%08x:0x%08x\r\n",&PWR->CR, PWR->CR); + DBGP("PWR->CSR 0x%08x:0x%08x\r\n",&PWR->CSR, PWR->CSR); + DBGP("SCB->SCR 0x%08x:0x%08x\r\n",&SCB->SCR, SCB->SCR); + DBGP("SCB->AIRCR 0x%08x:0x%08x\r\n",&SCB->AIRCR, SCB->AIRCR); + DBGP("EXTI->IMR 0x%08x:0x%08x\r\n",&EXTI->IMR, EXTI->IMR); + DBGP("EXTI->EMR 0x%08x:0x%08x\r\n",&EXTI->EMR, EXTI->EMR); + DBGP("EXTI->RTSR 0x%08x:0x%08x\r\n",&EXTI->RTSR, EXTI->RTSR); + DBGP("EXTI->FTSR 0x%08x:0x%08x\r\n",&EXTI->FTSR, EXTI->FTSR); + DBGP("RTC->TR 0x%08x:0x%08x\r\n",&RTC->TR,RTC->TR); + DBGP("RTC->DR 0x%08x:0x%08x\r\n",&RTC->DR,RTC->DR); + DBGP("RTC->CR 0x%08x:0x%08x\r\n",&RTC->CR,RTC->CR); + DBGP("RTC->ISR 0x%08x:0x%08x\r\n",&RTC->ISR,RTC->ISR); + DBGP("RTC->ALRMAR 0x%08x:0x%08x\r\n",&RTC->ALRMAR,RTC->ALRMAR); +} + +void WakeUp::standby_then_reset(uint32_t ms) +{ + DBG("Step(%u),ms:%d\r\n", __LINE__, ms); + if (ms == 0){ // just go to Reset + __NVIC_SystemReset(); + } + set_ms(ms); + use_reset = true; + PWR->CR |= PWR_CR_CWUF; + HAL_PWR_EnterSTANDBYMode(); +} + +void WakeUp::irq_handler(void) +{ + //Clear RTC + EXTI interrupt flags + PWR->CR |= PWR_CR_DBP; // Enable power domain + RTC->ISR &= ~RTC_ISR_ALRAF; + RTC->CR &= 0x00ff00ff; // just in case + RTC->WPR = 0xCA; // Disable RTC write protection + RTC->WPR = 0x53; + RTC->CR &= ~(RTC_CR_ALRAE | RTC_CR_ALRAIE); //DisEnable Alarm-A + RTC->WPR = 0xFF; // Enable RTC write protection + EXTI->PR = RTC_EXTI_LINE_ALARM_EVENT; + PWR->CR &= ~PWR_CR_DBP; // Disable power domain + if (use_reset == true){ + NVIC_SystemReset(); + } else { + if (callback){ + callback.call(); + } + } +} + +void WakeUp::calibrate(void) +{ + //RTC, we assume it is accurate enough without calibration +} + +#endif \ No newline at end of file