wake library
Dependencies: LPC1114_WakeInterruptIn
Fork of WakeUp by
Revision 9:29bdf5fed21a, committed 2014-07-24
- Comitter:
- Sissors
- Date:
- Thu Jul 24 15:04:04 2014 +0000
- Parent:
- 8:8d9a6ac0fba8
- Child:
- 10:c41bc9154a7c
- Commit message:
- General STM support for all devices with same RTC and Alarm A
Changed in this revision
Device/WakeUp_NUCLEO_F030.cpp | Show diff for this revision Revisions of this file |
Device/WakeUp_STM_RTC.cpp | Show annotated file Show diff for this revision Revisions of this file |
--- a/Device/WakeUp_NUCLEO_F030.cpp Thu Jul 24 12:59:16 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,91 +0,0 @@ -#ifdef TARGET_NUCLEO_F030R8 - -#include "WakeUp.h" -#include "rtc_api.h" -#include "stm32f0xx_rtc.h" - -FunctionPointer WakeUp::callback; - -void WakeUp::set_ms(uint32_t ms) -{ - if (!rtc_isenabled()) //Make sure RTC is running - rtc_init(); - - //Alarm must be disabled to change anything - PWR_BackupAccessCmd(ENABLE); - RTC_AlarmCmd(RTC_Alarm_A, DISABLE); - - if (ms == 0) { //Just disable alarm - PWR_BackupAccessCmd(DISABLE); - return; - } - - //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 2 subsecs delay to be sure interrupt is called - - //Get current time - uint32_t subsecs = RTC->SSR; - time_t secs = rtc_read(); - - //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); - - RTC_AlarmTypeDef alarmStruct; - alarmStruct.RTC_AlarmTime.RTC_Hours = timeinfo->tm_hour; - alarmStruct.RTC_AlarmTime.RTC_Minutes = timeinfo->tm_min; - alarmStruct.RTC_AlarmTime.RTC_Seconds = timeinfo->tm_sec; - alarmStruct.RTC_AlarmTime.RTC_H12 = RTC_HourFormat_24; - alarmStruct.RTC_AlarmMask = RTC_AlarmMask_None; - alarmStruct.RTC_AlarmDateWeekDaySel = RTC_AlarmDateWeekDaySel_Date; - alarmStruct.RTC_AlarmDateWeekDay = timeinfo->tm_mday; - - //Enable EXTI interrupt of the RTC - EXTI_InitTypeDef extiStruct; - extiStruct.EXTI_Line = EXTI_Line17; - extiStruct.EXTI_Mode = EXTI_Mode_Interrupt; - extiStruct.EXTI_Trigger = EXTI_Trigger_Rising; - extiStruct.EXTI_LineCmd = ENABLE; - - //Enable RTC interrupt - RTC_AlarmSubSecondConfig(RTC_Alarm_A, subsecs, RTC_AlarmSubSecondMask_None); - RTC_SetAlarm(RTC_Format_BIN, RTC_Alarm_A, &alarmStruct); - RTC_AlarmCmd(RTC_Alarm_A, ENABLE); - RTC_ITConfig(RTC_IT_ALRA, ENABLE); - PWR_BackupAccessCmd(DISABLE); - - //Enable everything else - EXTI_Init(&extiStruct); - NVIC_SetVector(RTC_IRQn, (uint32_t)WakeUp::irq_handler); - NVIC_EnableIRQ(RTC_IRQn); -} - - -void WakeUp::irq_handler(void) -{ - //Clear RTC + EXTI interrupt flags - PWR_BackupAccessCmd(ENABLE); - RTC_ClearFlag(RTC_FLAG_ALRAF); - EXTI_ClearFlag(EXTI_Line17); - PWR_BackupAccessCmd(DISABLE); - callback.call(); -} - -void WakeUp::calibrate(void) -{ - //RTC, we assume it is accurate enough without calibration -} - -#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Device/WakeUp_STM_RTC.cpp Thu Jul 24 15:04:04 2014 +0000 @@ -0,0 +1,111 @@ +#ifdef TARGET_STM + +#include "WakeUp.h" +#include "rtc_api.h" + +#define BYTE2BCD(byte) ((byte % 10) | ((byte / 10) << 4)) +#define EXTI_RTC_LINE (1 << 17) + +//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) +#define RTC_IRQ RTC_Alarm_IRQn +#else +#define RTC_IRQ RTC_IRQn +#endif + +FunctionPointer WakeUp::callback; + +void WakeUp::set_ms(uint32_t ms) +{ + 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; + while(!(RTC->ISR & RTC_ISR_ALRAWF)); + + if (ms == 0) { //Just disable alarm + PWR->CR &= ~PWR_CR_DBP; //Disable power domain + RTC->WPR = 0xFF; //Enable RTC write protection + return; + } + + //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 2 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(); + + //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); + + //Enable rising edge EXTI interrupt of the RTC + EXTI->IMR |= EXTI_RTC_LINE; + EXTI->EMR &= ~EXTI_RTC_LINE; + EXTI->RTSR |= EXTI_RTC_LINE; + EXTI->FTSR &= ~EXTI_RTC_LINE; + + //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; + + //Enable RTC interrupt + RTC->ALRMAR = alarmreg; + RTC->ALRMASSR = subsecs | RTC_ALRMASSR_MASKSS; //Mask no subseconds + RTC->CR |= RTC_CR_ALRAE | RTC_CR_ALRAIE; //Enable Alarm + + 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); +} + + +void WakeUp::irq_handler(void) +{ + //Clear RTC + EXTI interrupt flags + PWR->CR |= PWR_CR_DBP; //Enable power domain + RTC->ISR &= ~RTC_ISR_ALRAF; + EXTI->PR = EXTI_RTC_LINE; + PWR->CR &= ~PWR_CR_DBP; //Disable power domain + callback.call(); +} + +void WakeUp::calibrate(void) +{ + //RTC, we assume it is accurate enough without calibration +} + + +#endif