This is the code used on my video series "Hybrid Supercapacitor Car Battery" for my own hardware monitoring system. THe videos can be found on madelectronengineering.com

Dependencies:   BurstSPI Fonts INA219 mbed LPC1114_WakeInterruptIn

Fork of SharpMemoryLCD by Paul Staron

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