add the implementation of LP1768 wakeup based on the old WakeUp library

Dependencies:   LPC1114_WakeInterruptIn

Fork of WakeUp by steven niu

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 #define EXTI_RTC_LINE       (1 << 17)
00008 
00009 //Most things are pretty similar between the different STM targets.
00010 //Only the IRQ number the alarm is connected to differs. Any errors
00011 //with RTC_IRQn/RTC_Alarm_IRQn in them are related to this
00012 #if defined(TARGET_M4)
00013 #define RTC_IRQ     RTC_Alarm_IRQn               
00014 #else
00015 #define RTC_IRQ     RTC_IRQn
00016 #endif
00017 
00018 FunctionPointer WakeUp::callback;
00019 
00020 void WakeUp::set_ms(uint32_t ms)
00021 {        
00022     if (!rtc_isenabled()) {      //Make sure RTC is running
00023         rtc_init();
00024         wait_us(250);            //The f401 seems to want a delay after init
00025     }
00026     
00027     PWR->CR |= PWR_CR_DBP;      //Enable power domain
00028     RTC->WPR = 0xCA;            //Disable RTC write protection
00029     RTC->WPR = 0x53;
00030     
00031     //Alarm must be disabled to change anything
00032     RTC->CR &= ~RTC_CR_ALRAE;
00033     while(!(RTC->ISR & RTC_ISR_ALRAWF));
00034     
00035     if (ms == 0) {              //Just disable alarm
00036         PWR->CR &= ~PWR_CR_DBP; //Disable power domain
00037         RTC->WPR = 0xFF;        //Enable RTC write protection
00038         return;
00039     }
00040     
00041     //RTC prescaler + calculate how many sub-seconds should be added
00042     uint32_t prescaler = (RTC->PRER & 0x7FFF) + 1;
00043     uint32_t subsecsadd = ((ms % 1000) * prescaler) / 1000;
00044     
00045     if ((ms < 1000) && (subsecsadd < 2))
00046         subsecsadd = 2;                             //At least 2 subsecs delay to be sure interrupt is called
00047     
00048     __disable_irq();                                //At this point we don't want IRQs anymore
00049     
00050     //Get current time
00051     uint32_t subsecs = RTC->SSR;
00052     time_t secs = rtc_read();
00053     
00054     //Calculate alarm values
00055     //Subseconds is countdown, so substract the 'added' sub-seconds and prevent underflow
00056     if (subsecs < subsecsadd) {
00057         subsecs += prescaler;
00058         secs++;
00059     }
00060     subsecs -= subsecsadd;
00061     
00062     //Set seconds correctly
00063     secs += ms / 1000;
00064     struct tm *timeinfo = localtime(&secs);
00065     
00066     //Enable rising edge EXTI interrupt of the RTC
00067     EXTI->IMR |= EXTI_RTC_LINE;
00068     EXTI->EMR &= ~EXTI_RTC_LINE;
00069     EXTI->RTSR |= EXTI_RTC_LINE;
00070     EXTI->FTSR &= ~EXTI_RTC_LINE;
00071     
00072     //Calculate alarm register values
00073     uint32_t alarmreg = 0;
00074     alarmreg |= BYTE2BCD(timeinfo->tm_sec)  << 0;
00075     alarmreg |= BYTE2BCD(timeinfo->tm_min)  << 8;
00076     alarmreg |= BYTE2BCD(timeinfo->tm_hour) << 16;
00077     alarmreg |= BYTE2BCD(timeinfo->tm_mday) << 24;
00078     
00079     //Enable RTC interrupt
00080     RTC->ALRMAR = alarmreg;
00081     RTC->ALRMASSR = subsecs | RTC_ALRMASSR_MASKSS;      //Mask no subseconds
00082     RTC->CR |= RTC_CR_ALRAE | RTC_CR_ALRAIE;            //Enable Alarm
00083     
00084     RTC->WPR = 0xFF;        //Enable RTC write protection
00085     PWR->CR &= ~PWR_CR_DBP; //Disable power domain
00086     
00087     __enable_irq();         //Alarm is set, so irqs can be enabled again
00088     
00089     //Enable everything else
00090     NVIC_SetVector(RTC_IRQ, (uint32_t)WakeUp::irq_handler);
00091     NVIC_EnableIRQ(RTC_IRQ);    
00092 }
00093 
00094 
00095 void WakeUp::irq_handler(void)
00096 {
00097     //Clear RTC + EXTI interrupt flags
00098     PWR->CR |= PWR_CR_DBP;      //Enable power domain
00099     RTC->ISR &= ~RTC_ISR_ALRAF;
00100     EXTI->PR = EXTI_RTC_LINE;
00101     PWR->CR &= ~PWR_CR_DBP;     //Disable power domain 
00102     callback.call();
00103 }
00104 
00105 void WakeUp::calibrate(void)
00106 {
00107     //RTC, we assume it is accurate enough without calibration
00108 }
00109 
00110 
00111 #endif