Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: LPC1114_WakeInterruptIn
Fork of WakeUp by
Diff: Device/WakeUp_STM_RTC.cpp
- Revision:
- 9:29bdf5fed21a
- Child:
- 15:b2a710aca356
diff -r 8d9a6ac0fba8 -r 29bdf5fed21a Device/WakeUp_STM_RTC.cpp
--- /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
