RTC
|
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 }