Flotsam / Wakeup

Dependents:   Full-Project

Fork of WakeUp by Erik -

Revision:
7:bb411115f814
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Device/WakeUp_NUCLEO_F030.cpp	Wed Jul 23 19:54:52 2014 +0000
@@ -0,0 +1,91 @@
+#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