WakeUpLib

Dependencies:   LPC1114_WakeInterruptIn

Fork of WakeUp by Erik -

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers WakeUp_STM_RTC.cpp Source File

WakeUp_STM_RTC.cpp

00001 #ifdef TARGET_STM
00002 
00003 #include "WakeUp.h"
00004 #include "rtc_api.h"
00005 
00006 #define BYTE2BCD(byte)      ((byte % 10) | ((byte / 10) << 4))
00007 
00008 //Most things are pretty similar between the different STM targets.
00009 //Only the IRQ number the alarm is connected to differs. Any errors
00010 //with RTC_IRQn/RTC_Alarm_IRQn in them are related to this
00011 #if defined(TARGET_M4) || defined(TARGET_M3)
00012 #define RTC_IRQ     RTC_Alarm_IRQn               
00013 #else
00014 #define RTC_IRQ     RTC_IRQn
00015 #endif
00016 
00017 // Some things to handle Disco L476VG (and similar ones)
00018 #if defined(TARGET_STM32L4)
00019 #define IMR     IMR1
00020 #define EMR     EMR1
00021 #define RTSR    RTSR1
00022 #define FTSR    FTSR2
00023 #define PR      PR1
00024 #endif
00025 
00026 //Disabling the Backup Powerdomain does not seem to work nicely anymore if you want to use other RTC functions afterwards.
00027 //For now I have disabled it in code, if you find WakeUp increases your powerconsumption, try enabling it again (code is still there, just commented)
00028 
00029 FunctionPointer WakeUp::callback;
00030 
00031 void WakeUp::set_ms(uint32_t ms)
00032 {        
00033     if (!rtc_isenabled()) {      //Make sure RTC is running
00034         rtc_init();
00035         wait_us(250);            //The f401 seems to want a delay after init
00036     }
00037     
00038     //PWR->CR |= PWR_CR_DBP;      //Enable power domain
00039     RTC->WPR = 0xCA;            //Disable RTC write protection
00040     RTC->WPR = 0x53;
00041     
00042     //Alarm must be disabled to change anything
00043     RTC->CR &= ~RTC_CR_ALRAE;
00044     while(!(RTC->ISR & RTC_ISR_ALRAWF));
00045     
00046     if (ms == 0) {              //Just disable alarm
00047         //PWR->CR &= ~PWR_CR_DBP; //Disable power domain
00048         RTC->WPR = 0xFF;        //Enable RTC write protection
00049         return;
00050     }
00051     
00052     //RTC prescaler + calculate how many sub-seconds should be added
00053     uint32_t prescaler = (RTC->PRER & 0x7FFF) + 1;
00054     uint32_t subsecsadd = ((ms % 1000) * prescaler) / 1000;
00055     
00056     if ((ms < 1000) && (subsecsadd < 2))
00057         subsecsadd = 2;                             //At least 2 subsecs delay to be sure interrupt is called
00058     
00059     __disable_irq();                                //At this point we don't want IRQs anymore
00060     
00061     //Get current time
00062     uint32_t subsecs = RTC->SSR;
00063     time_t secs = rtc_read();
00064     
00065     //Calculate alarm values
00066     //Subseconds is countdown, so substract the 'added' sub-seconds and prevent underflow
00067     if (subsecs < subsecsadd) {
00068         subsecs += prescaler;
00069         secs++;
00070     }
00071     subsecs -= subsecsadd;
00072     
00073     //Set seconds correctly
00074     secs += ms / 1000;
00075     struct tm *timeinfo = localtime(&secs);
00076     
00077     //Enable rising edge EXTI interrupt of the RTC
00078     EXTI->IMR |= RTC_EXTI_LINE_ALARM_EVENT;
00079     EXTI->EMR &= ~RTC_EXTI_LINE_ALARM_EVENT;
00080     EXTI->RTSR |= RTC_EXTI_LINE_ALARM_EVENT;
00081     EXTI->FTSR &= ~RTC_EXTI_LINE_ALARM_EVENT;
00082     
00083     //Calculate alarm register values
00084     uint32_t alarmreg = 0;
00085     alarmreg |= BYTE2BCD(timeinfo->tm_sec)  << 0;
00086     alarmreg |= BYTE2BCD(timeinfo->tm_min)  << 8;
00087     alarmreg |= BYTE2BCD(timeinfo->tm_hour) << 16;
00088     alarmreg |= BYTE2BCD(timeinfo->tm_mday) << 24;
00089     
00090     //Enable RTC interrupt
00091     RTC->ALRMAR = alarmreg;
00092     RTC->ALRMASSR = subsecs | RTC_ALRMASSR_MASKSS;      //Mask no subseconds
00093     RTC->CR |= RTC_CR_ALRAE | RTC_CR_ALRAIE;            //Enable Alarm
00094     
00095     RTC->WPR = 0xFF;        //Enable RTC write protection
00096     //PWR->CR &= ~PWR_CR_DBP; //Disable power domain
00097     
00098     __enable_irq();         //Alarm is set, so irqs can be enabled again
00099     
00100     //Enable everything else
00101     NVIC_SetVector(RTC_IRQ, (uint32_t)WakeUp::irq_handler);
00102     NVIC_EnableIRQ(RTC_IRQ);    
00103 }
00104 
00105 
00106 void WakeUp::irq_handler(void)
00107 {
00108     //Clear RTC + EXTI interrupt flags
00109     //PWR->CR |= PWR_CR_DBP;      //Enable power domain
00110     RTC->ISR &= ~RTC_ISR_ALRAF;
00111     RTC->WPR = 0xCA;            //Disable RTC write protection
00112     RTC->WPR = 0x53;
00113     RTC->CR &= ~RTC_CR_ALRAE;
00114     RTC->WPR = 0xFF;        //Enable RTC write protection
00115     EXTI->PR = RTC_EXTI_LINE_ALARM_EVENT;
00116     //PWR->CR &= ~PWR_CR_DBP;     //Disable power domain 
00117     callback.call();
00118 }
00119 
00120 void WakeUp::calibrate(void)
00121 {
00122     //RTC, we assume it is accurate enough without calibration
00123 }
00124 
00125 
00126 #endif