wake library

Dependencies:   LPC1114_WakeInterruptIn

Fork of WakeUp by Erik -

Files at this revision

API Documentation at this revision

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