RTC: RTC.c Source File

Real Time Clock

RTC.c
Go to the documentation of this file.
00001 
00066 /***********************************************************************************************************************
00067  * HEADER FILES
00068  **********************************************************************************************************************/
00069 #include "rtc.h"
00070 
00071 /***********************************************************************************************************************
00072  * MACROS
00073  **********************************************************************************************************************/
00074 /* Constant used for the number of days in an year */
00075 #define RTC_DAYS_IN_AN_YEAR     (365U)
00076 /* Constant used for the seconds in a day */
00077 #define RTC_SECONDS_IN_A_DAY    (24U * 60U * 60U)
00078 /* Constant used for the seconds in an hour */
00079 #define RTC_SECONDS_IN_AN_HOUR  (60U * 60U)
00080 /* Constant used for the seconds in a minute */
00081 #define RTC_SECONDS_IN_A_MINUTE (60U)
00082 /* Constant used for the epoch year */
00083 #define RTC_EPOCH_YEAR          (1970U)
00084 
00085 /***********************************************************************************************************************
00086  * LOCAL DATA
00087  **********************************************************************************************************************/
00088 /* Constant array used to store the number of days in each month */
00089 const uint32_t RTC_DAYS_IN_MONTH[13] =
00090 {
00091   /* Index from 1, hence skip 0*/
00092   0U,
00093   /*Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec*/
00094   31U, 28U, 31U, 30U, 31U, 30U, 31U, 31U, 30U, 31U, 30U, 31U
00095 };
00096 
00097 /***********************************************************************************************************************
00098  * LOCAL ROUTINES
00099  **********************************************************************************************************************/
00100 uint8_t RTC_lleapyear(uint16_t year);
00101 bool RTC_lConfigureInterrupts(const RTC_t *const handler);
00102 XMC_RTC_STATUS_t RTC_lRegister_Callbacks(const RTC_t *const handler);
00103 
00104 /**********************************************************************************************************************
00105  * API IMPLEMENTATION
00106 ***********************************************************************************************************************/
00107 /*
00108  * API to retrieve the version of the RTC APP
00109  */
00110 DAVE_APP_VERSION_t RTC_GetAppVersion(void)
00111 {
00112   DAVE_APP_VERSION_t version;
00113 
00114   version.major = RTC_MAJOR_VERSION;
00115   version.minor = RTC_MINOR_VERSION;
00116   version.patch = RTC_PATCH_VERSION;
00117 
00118   return (version);
00119 }
00120 
00121 /*
00122   Initialization function for the APP. Configures the registers
00123   based on options selected in UI.
00124 */
00125 RTC_STATUS_t RTC_Init(RTC_t *const handler)
00126 {
00127   XMC_RTC_STATUS_t status;
00128   RTC_STATUS_t rtc_initstatus;
00129   bool interrupt_configured;
00130 
00131   XMC_ASSERT("RTC_Init: NULL Handler", handler != NULL);
00132 
00133   status = XMC_RTC_STATUS_OK;
00134   rtc_initstatus = RTC_STATUS_FAILURE;
00135 
00136 #if (RTC_INTERRUPT_ENABLED == 1)
00137 #if (UC_FAMILY == XMC4)
00138   rtc_initstatus = (RTC_STATUS_t)GLOBAL_SCU_XMC4_Init(GLOBAL_SCU_HANDLE);
00139 #else
00140   rtc_initstatus = (RTC_STATUS_t)GLOBAL_SCU_XMC1_Init(GLOBAL_SCU_HANDLE);
00141 #endif
00142   if (rtc_initstatus == RTC_STATUS_SUCCESS)
00143   {
00144 #endif
00145       if (handler->initialized == false)
00146       {
00147         /* Initialize the clock source and pre-scalar */
00148         status = XMC_RTC_Init(handler->time_alarm_config);
00149 
00150         if (status == XMC_RTC_STATUS_OK)
00151         {
00152           /* Configure periodic, alarm and hibernate periodic interrupts */
00153           interrupt_configured = RTC_lConfigureInterrupts(handler);
00154 
00155           if (interrupt_configured == true)
00156           {
00157             status = RTC_lRegister_Callbacks(handler);
00158           }
00159 
00160           if (status == XMC_RTC_STATUS_OK)
00161           {
00162                 /* Check RTC start during init is set or not in UI */
00163             if (handler->config->start == RTC_START_ENABLE)
00164             {
00165               RTC_Start();
00166             }
00167             handler->initialized = true;
00168             rtc_initstatus = RTC_STATUS_SUCCESS;
00169           }
00170         }
00171         else
00172         {
00173           rtc_initstatus = RTC_STATUS_FAILURE;
00174         }
00175       }
00176       else
00177       {
00178         rtc_initstatus = RTC_STATUS_SUCCESS;
00179       }
00180 #if (RTC_INTERRUPT_ENABLED == 1)
00181    } /* end of if(rtc_initstatus == GLOBAL_SCU_XMC4_STATUS_OK) */
00182 #endif
00183 
00184   return (rtc_initstatus);
00185 }
00186 /*
00187  *  This function configures periodic and alarm interrupts
00188  */
00189 bool RTC_lConfigureInterrupts(const RTC_t *const handler)
00190 {
00191   uint32_t regval;
00192   bool interrupt_configured = false;
00193 
00194   /* Enable periodic seconds, minutes, hours days, months and years interrupts */
00195   regval = (((uint32_t)handler->config->periodic_sec_intr << RTC_MSKSR_MPSE_Pos)
00196            | ((uint32_t)handler->config->periodic_min_intr << RTC_MSKSR_MPMI_Pos)
00197            | ((uint32_t)handler->config->periodic_hour_intr << RTC_MSKSR_MPHO_Pos)
00198            | ((uint32_t)handler->config->periodic_day_intr << RTC_MSKSR_MPDA_Pos)
00199            | ((uint32_t)handler->config->periodic_month_intr << RTC_MSKSR_MPMO_Pos)
00200            | ((uint32_t)handler->config->periodic_year_intr << RTC_MSKSR_MPYE_Pos));
00201 
00202   /* Enable RTC periodic interrupt in SCU when any of the periodic interrupts
00203    * are enabled */
00204   if (regval != 0U)
00205   {
00206     XMC_RTC_EnableEvent(regval);
00207 #if ((UC_FAMILY == XMC4) && (RTC_TIMER_EVENT_TRIG_TO_NMI == 1))
00208                 XMC_SCU_INTERRUPT_EnableEvent((XMC_SCU_INTERRUPT_EVENT_t)XMC_SCU_NMIREQ_RTC_PI);
00209                 XMC_SCU_INTERRUPT_EnableNmiRequest((uint32_t)XMC_SCU_NMIREQ_RTC_PI);
00210 #endif
00211 #if ((UC_FAMILY == XMC4) && (RTC_TIMER_EVENT_TRIG_TO_SCU == 1))
00212                 GLOBAL_SCU_XMC4_EnableEvent((GLOBAL_SCU_XMC4_EVENT_t)GLOBAL_SCU_XMC4_EVENT_RTC_PERIODIC);
00213 #endif
00214     interrupt_configured = true;
00215   }
00216 
00217 
00218         if (handler->config->alarm_intr == RTC_INT_ALARM_ENABLE)
00219         {
00220                 XMC_RTC_EnableEvent((uint32_t)XMC_RTC_EVENT_ALARM);
00221 #if ((UC_FAMILY == XMC4) && (RTC_ALARM_EVENT_TRIG_TO_NMI == 1))
00222                 XMC_SCU_INTERRUPT_EnableEvent((XMC_SCU_INTERRUPT_EVENT_t)XMC_SCU_NMIREQ_RTC_AI);
00223                 XMC_SCU_INTERRUPT_EnableNmiRequest((uint32_t)XMC_SCU_NMIREQ_RTC_AI);
00224 #endif
00225 #if ((UC_FAMILY == XMC4) && (RTC_ALARM_EVENT_TRIG_TO_SCU == 1))
00226                 GLOBAL_SCU_XMC4_EnableEvent((GLOBAL_SCU_XMC4_EVENT_t)GLOBAL_SCU_XMC4_EVENT_RTC_ALARM);
00227 #endif
00228 
00229                 interrupt_configured = true;
00230         }
00231 
00232 
00233   return (interrupt_configured);
00234 }
00235 
00236 /*
00237  *  Interface to register the RTC call backs
00238  */
00239 XMC_RTC_STATUS_t RTC_lRegister_Callbacks(const RTC_t *const handler)
00240 {
00241   XMC_RTC_STATUS_t pi_status;
00242   XMC_RTC_STATUS_t ai_status;
00243 
00244   pi_status = XMC_RTC_STATUS_OK;
00245   ai_status = XMC_RTC_STATUS_OK;
00246 
00247 #if (RTC_INTERRUPT_ENABLED == 1)
00248   #if (UC_FAMILY == XMC4)
00249     pi_status = (XMC_RTC_STATUS_t)GLOBAL_SCU_XMC4_RegisterCallback(
00250                 (GLOBAL_SCU_XMC4_EVENT_t)GLOBAL_SCU_XMC4_EVENT_RTC_PERIODIC, handler->config->pi_listener);
00251     if (handler->config->alarm_intr == RTC_INT_ALARM_ENABLE)
00252     {
00253       ai_status = (XMC_RTC_STATUS_t)GLOBAL_SCU_XMC4_RegisterCallback(
00254                 (GLOBAL_SCU_XMC4_EVENT_t)GLOBAL_SCU_XMC4_EVENT_RTC_ALARM,handler->config->ai_listener);
00255     }
00256   #else
00257     pi_status = (XMC_RTC_STATUS_t)GLOBAL_SCU_XMC1_RegisterCallback((GLOBAL_SCU_XMC1_EVENT_t)GLOBAL_SCU_XMC1_EVENT_RTC_PERIODIC,
00258                                                                    handler->config->pi_listener);
00259 
00260     if (handler->config->alarm_intr == RTC_INT_ALARM_ENABLE)
00261     {
00262       ai_status = (XMC_RTC_STATUS_t)GLOBAL_SCU_XMC1_RegisterCallback((GLOBAL_SCU_XMC1_EVENT_t)GLOBAL_SCU_XMC1_EVENT_RTC_ALARM,
00263                                                                      handler->config->ai_listener);
00264     }
00265   #endif
00266 #endif
00267 
00268   return (XMC_RTC_STATUS_t)((uint32_t)pi_status & (uint32_t)ai_status);
00269 }
00270 
00271 /*
00272  *  This function is used to set RTC time.
00273  */
00274 RTC_STATUS_t RTC_SetTime(XMC_RTC_TIME_t *current_time)
00275 {
00276   RTC_STATUS_t status = RTC_STATUS_SUCCESS;
00277   XMC_RTC_TIME_t time_val;
00278 
00279   XMC_ASSERT("RTC_SetTime: NULL pointer", current_time != NULL);
00280 
00281   /* copy to local structure to keep data safe */
00282   time_val.year = current_time->year;
00283   time_val.month = current_time->month;
00284   time_val.days = current_time->days;
00285   time_val.hours = current_time->hours;
00286   time_val.minutes = current_time->minutes;
00287   time_val.seconds = current_time->seconds;
00288 
00289   if ((time_val.days != 0U) && (time_val.month != 0U))
00290   {
00291     time_val.days = time_val.days - 1U;
00292     time_val.month = time_val.month - 1U;
00293 
00294     XMC_RTC_SetTime(&time_val);
00295   }
00296   else
00297   {
00298     status = RTC_STATUS_FAILURE;
00299   }
00300 
00301   return (status);
00302 }
00303 
00304 /*
00305  *  This function is used to get RTC time.
00306  */
00307 void RTC_GetTime(XMC_RTC_TIME_t *current_time)
00308 {
00309   XMC_ASSERT("RTC_GetTime: NULL pointer", current_time != NULL);
00310 
00311   XMC_RTC_GetTime(current_time);
00312 
00313   current_time->days = current_time->days + 1U;
00314   current_time->month = current_time->month + 1U;
00315 }
00316 
00317 /*
00318  *  This function is used to set Alarm time.
00319  */
00320 RTC_STATUS_t RTC_SetAlarmTime(XMC_RTC_ALARM_t *alarm)
00321 {
00322   RTC_STATUS_t status = RTC_STATUS_SUCCESS;
00323   XMC_RTC_ALARM_t alarm_val;
00324 
00325   XMC_ASSERT("RTC_SetAlarmTime: NULL pointer", alarm != NULL);
00326 
00327   /* copy to local structure to keep data safe */
00328   alarm_val.year = alarm->year;
00329   alarm_val.month = alarm->month;
00330   alarm_val.days = alarm->days;
00331   alarm_val.hours = alarm->hours;
00332   alarm_val.minutes = alarm->minutes;
00333   alarm_val.seconds = alarm->seconds;
00334 
00335   if ((alarm_val.days != 0U) && (alarm_val.month != 0U))
00336   {
00337     alarm_val.days = alarm_val.days - 1U;
00338     alarm_val.month = alarm_val.month - 1U;
00339 
00340     XMC_RTC_SetAlarm(&alarm_val);
00341   }
00342   else
00343   {
00344     status = RTC_STATUS_FAILURE;
00345   }
00346 
00347   return (status);
00348 }
00349 
00350 /*
00351  *  This function is used to get Alarm time from XMC.
00352  *  And returns in standard time format.
00353  */
00354 void RTC_GetAlarmTime(XMC_RTC_ALARM_t *alarm)
00355 {
00356   XMC_ASSERT("RTC_GetAlarmTime: NULL pointer", alarm != NULL);
00357 
00358   XMC_RTC_GetAlarm(alarm);
00359 
00360   alarm->days = alarm->days + 1U;
00361   alarm->month = alarm->month + 1U;
00362 }
00363 
00364 /*
00365  *  This function is used to get event status.
00366  */
00367 uint32_t RTC_GetFlagStatus(void)
00368 {
00369   uint32_t event_status;
00370 
00371   event_status = XMC_RTC_GetEventStatus();
00372 
00373   return (event_status);
00374 }
00375 
00376 /*
00377  *  This function is to get the time in seconds calculated from Epoch time
00378  *  (01/01/1970).
00379  */
00380 RTC_STATUS_t RTC_Time(time_t* time_value)
00381 {
00382   uint32_t elapsedyear;
00383   uint32_t elapsedmonth;
00384   uint32_t elapseddays;
00385   uint32_t elapsedseconds;
00386 
00387   RTC_STATUS_t status;
00388   XMC_RTC_TIME_t curr_time;
00389   
00390   XMC_ASSERT("RTC_Time: NULL pointer", time_value != NULL);
00391 
00392   /*Check if RTC module is enabled and no NULL pointer*/
00393   if (true == XMC_RTC_IsRunning())
00394   {
00395     /* Read values from TIM0 and TIM1 registers */
00396     XMC_RTC_GetTime(&curr_time);
00397 
00398     /*Count number of Days for Elapsed Years since Epoch*/
00399     elapseddays = ((uint32_t)curr_time.year - RTC_EPOCH_YEAR) * RTC_DAYS_IN_AN_YEAR;
00400 
00401     /* Add the number of days to be adjusted for leap years,
00402        start from previous year and check backward */
00403     for (elapsedyear = ((uint32_t)curr_time.year - 1U); elapsedyear>= (uint32_t)1970; elapsedyear--)
00404     {
00405       if (RTC_lleapyear((uint16_t)elapsedyear))
00406       {
00407         elapseddays++;
00408       }
00409     }
00410     /*If current year is leap year add 1 only if March or later*/
00411     if (RTC_lleapyear(curr_time.year))
00412     {
00413       if(curr_time.month > 2U)
00414       {
00415         elapseddays++;
00416       }
00417     }
00418 
00419     /*Add number of Days from Elapsed months from current year*/
00420     for (elapsedmonth = (curr_time.month); elapsedmonth != 0U; elapsedmonth--)
00421     {
00422       elapseddays += RTC_DAYS_IN_MONTH[elapsedmonth];
00423     }
00424 
00425     /*Add Elapsed days from current month*/
00426     elapseddays += curr_time.days;
00427 
00428     /*Accumulate the total seconds for ElapsedDays*/
00429     elapsedseconds = (elapseddays * RTC_SECONDS_IN_A_DAY);
00430 
00431     /*Add seconds for current hour, minute and seconds*/
00432     elapsedseconds += ((uint32_t)curr_time.hours * RTC_SECONDS_IN_AN_HOUR);
00433     elapsedseconds += ((uint32_t)curr_time.minutes * RTC_SECONDS_IN_A_MINUTE);
00434     elapsedseconds += (uint32_t)curr_time.seconds;
00435 
00436     *time_value = (time_t)elapsedseconds;
00437      status = RTC_STATUS_SUCCESS;
00438   }
00439   else
00440   {
00441     status = RTC_STATUS_FAILURE;
00442   }
00443   return (status);
00444 }
00445         
00446 /* This function returns 1 if it is leap year otherwise 0.*/
00447 uint8_t RTC_lleapyear(uint16_t year)
00448 {
00449   uint8_t valid = 0U;
00450 
00451   if ((((year) % 400U) == 0U) || ((((year) % 100U) != 0U) &&
00452        (((year) %4U) == 0U)))
00453   {
00454     valid = 1U;
00455   }
00456   return (valid);
00457 }