Added Restart(by RESET) function from Standby mode only for some Nucleo boards (STM32 series)
Dependencies: LPC1114_WakeInterruptIn
Fork of WakeUp by
Example program using "Standby function" for Nucleo series is here.
/users/kenjiArai/code/Check_StandBy/
Revision 25:2bd9df8c3ac8, committed 2017-09-21
- Comitter:
- kenjiArai
- Date:
- Thu Sep 21 21:53:16 2017 +0000
- Parent:
- 24:65c04a02ad45
- Child:
- 26:df9d01556394
- Commit message:
- Added Restart(by RESET) function from Standby mode only for some Nucleo boards (STM32 series)
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Device/WakeUp_STM32_others.cpp Thu Sep 21 21:53:16 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 1 +#define DBG(...) pc.printf(__VA_ARGS__) +#else +#define DBG(...) {;} +#endif + +#if 1 +#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
--- a/Device/WakeUp_STM_RTC.cpp Tue Jul 04 07:59:06 2017 +0000 +++ b/Device/WakeUp_STM_RTC.cpp Thu Sep 21 21:53:16 2017 +0000 @@ -1,4 +1,11 @@ #ifdef TARGET_STM +// added 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) + // use WakeUp_STM32_others.cpp +#else #include "WakeUp.h" #include "rtc_api.h" @@ -9,7 +16,7 @@ //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 +#define RTC_IRQ RTC_Alarm_IRQn #else #define RTC_IRQ RTC_IRQn #endif @@ -98,7 +105,7 @@ __enable_irq(); //Alarm is set, so irqs can be enabled again //Enable everything else - NVIC_SetVector(RTC_IRQ, (uint32_t)WakeUp::irq_handler); + NVIC_SetVector(RTC_IRQ, (uint32_t)WakeUp::irq_handler); NVIC_EnableIRQ(RTC_IRQ); } @@ -122,5 +129,5 @@ //RTC, we assume it is accurate enough without calibration } - +#endif // TARGET_NUCLEO_F446RE (added by JH1PJL 2017-9-21) #endif
--- a/WakeUp.h Tue Jul 04 07:59:06 2017 +0000 +++ b/WakeUp.h Thu Sep 21 21:53:16 2017 +0000 @@ -91,9 +91,24 @@ */ static void calibrate(void); + /** + * Enter Standby mode then Reset + * (available only for confirmed Nucleo boards) + * + * @param ms required time in milliseconds + */ +#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) + // added by JH1PJL 2017-9-21 + static void standby_then_reset(uint32_t ms); + +#endif private: static Callback<void()> callback; static void irq_handler(void); static float cycles_per_ms; + static bool use_reset; // added by JH1PJL 2017-9-21 }; \ No newline at end of file