SYSTIMER
|
SYSTIMER.c
Go to the documentation of this file.
00001 00071 /*********************************************************************************************************************** 00072 * HEADER FILES 00073 **********************************************************************************************************************/ 00074 00075 /* Included to access APP data structure, functions & enumerations */ 00076 #include "systimer.h" 00077 00078 /*********************************************************************************************************************** 00079 * MACROS 00080 **********************************************************************************************************************/ 00081 00082 #define HW_TIMER_ADDITIONAL_CNT (1U) 00083 00084 /*********************************************************************************************************************** 00085 * LOCAL DATA 00086 **********************************************************************************************************************/ 00087 /* SYSTIMER_OBJECT structure acts as the timer control block */ 00088 00089 typedef struct SYSTIMER_OBJECT 00090 { 00091 struct SYSTIMER_OBJECT *next; 00092 struct SYSTIMER_OBJECT *prev; 00093 SYSTIMER_CALLBACK_t callback; 00094 SYSTIMER_MODE_t mode; 00095 SYSTIMER_STATE_t state; 00096 void *args; 00097 uint32_t id; 00098 uint32_t count; 00099 uint32_t reload; 00100 bool delete_swtmr; 00101 } SYSTIMER_OBJECT_t; 00102 00104 SYSTIMER_OBJECT_t g_timer_tbl[SYSTIMER_CFG_MAX_TMR]; 00105 00106 /* The header of the timer Control list. */ 00107 SYSTIMER_OBJECT_t *g_timer_list = NULL; 00108 00109 /* Timer ID tracker */ 00110 uint32_t g_timer_tracker = 0U; 00111 00112 /* SysTick counter */ 00113 volatile uint32_t g_systick_count = 0U; 00114 00115 /*********************************************************************************************************************** 00116 * LOCAL ROUTINES 00117 **********************************************************************************************************************/ 00118 00119 /* 00120 * This function is called to insert a timer into the timer list. 00121 */ 00122 static void SYSTIMER_lInsertTimerList(uint32_t tbl_index); 00123 00124 /* 00125 * This function is called to remove a timer from the timer list. 00126 */ 00127 static void SYSTIMER_lRemoveTimerList(uint32_t tbl_index); 00128 00129 /* 00130 * Handler function called from SysTick event handler. 00131 */ 00132 static void SYSTIMER_lTimerHandler(void); 00133 00134 /* 00135 * SysTick handler which is the main interrupt service routine to service the 00136 * system timer's configured 00137 */ 00138 void SysTick_Handler(void); 00139 00140 /********************************************************************************************************************** 00141 * API IMPLEMENTATION 00142 **********************************************************************************************************************/ 00143 /* 00144 * This function is called to insert a timer into the timer list. 00145 */ 00146 static void SYSTIMER_lInsertTimerList(uint32_t tbl_index) 00147 { 00148 SYSTIMER_OBJECT_t *object_ptr; 00149 int32_t delta_ticks; 00150 int32_t timer_count; 00151 bool found_flag = false; 00152 /* Get timer time */ 00153 timer_count = (int32_t)g_timer_tbl[tbl_index].count; 00154 /* Check if Timer list is NULL */ 00155 if (NULL == g_timer_list) 00156 { 00157 /* Set this as first Timer */ 00158 g_timer_list = &g_timer_tbl[tbl_index]; 00159 } 00160 /* If not, find the correct place, and insert the specified timer */ 00161 else 00162 { 00163 object_ptr = g_timer_list; 00164 /* Get timer tick */ 00165 delta_ticks = timer_count; 00166 /* Find correct place for inserting the timer */ 00167 while ((NULL != object_ptr) && (false == found_flag)) 00168 { 00169 /* Get timer Count Difference */ 00170 delta_ticks -= (int32_t)object_ptr->count; 00171 /* Check for delta ticks < 0 */ 00172 if (delta_ticks <= 0) 00173 { 00174 /* Check If head item */ 00175 if (NULL != object_ptr->prev) 00176 { 00177 /* If Insert to list */ 00178 object_ptr->prev->next = &g_timer_tbl[tbl_index]; 00179 g_timer_tbl[tbl_index].prev = object_ptr->prev; 00180 g_timer_tbl[tbl_index].next = object_ptr; 00181 object_ptr->prev = &g_timer_tbl[tbl_index]; 00182 } 00183 else 00184 { 00185 /* Set Timer as first item */ 00186 g_timer_tbl[tbl_index].next = g_timer_list; 00187 g_timer_list->prev = &g_timer_tbl[tbl_index]; 00188 g_timer_list = &g_timer_tbl[tbl_index]; 00189 } 00190 g_timer_tbl[tbl_index].count = g_timer_tbl[tbl_index].next->count + (uint32_t)delta_ticks; 00191 g_timer_tbl[tbl_index].next->count -= g_timer_tbl[tbl_index].count; 00192 found_flag = true; 00193 } 00194 /* Check for last item in list */ 00195 else 00196 { 00197 if ((delta_ticks > 0) && (NULL == object_ptr->next)) 00198 { 00199 /* Yes, insert into */ 00200 g_timer_tbl[tbl_index].prev = object_ptr; 00201 object_ptr->next = &g_timer_tbl[tbl_index]; 00202 g_timer_tbl[tbl_index].count = (uint32_t)delta_ticks; 00203 found_flag = true; 00204 } 00205 } 00206 /* Get the next item in timer list */ 00207 object_ptr = object_ptr->next; 00208 } 00209 } 00210 } 00211 00212 /* 00213 * This function is called to remove a timer from the timer list. 00214 */ 00215 static void SYSTIMER_lRemoveTimerList(uint32_t tbl_index) 00216 { 00217 SYSTIMER_OBJECT_t *object_ptr; 00218 object_ptr = &g_timer_tbl[tbl_index]; 00219 /* Check whether only one timer available */ 00220 if ((NULL == object_ptr->prev) && (NULL == object_ptr->next )) 00221 { 00222 /* set timer list as NULL */ 00223 g_timer_list = NULL; 00224 } 00225 /* Check if the first item in timer list */ 00226 else if (NULL == object_ptr->prev) 00227 { 00228 /* Remove timer from list, and reset timer list */ 00229 g_timer_list = object_ptr->next; 00230 g_timer_list->prev = NULL; 00231 g_timer_list->count += object_ptr->count; 00232 object_ptr->next = NULL; 00233 } 00234 /* Check if the last item in timer list */ 00235 else if (NULL == object_ptr->next) 00236 { 00237 /* Remove timer from list */ 00238 object_ptr->prev->next = NULL; 00239 object_ptr->prev = NULL; 00240 } 00241 else 00242 { 00243 /* Remove timer from list */ 00244 object_ptr->prev->next = object_ptr->next; 00245 object_ptr->next->prev = object_ptr->prev; 00246 object_ptr->next->count += object_ptr->count; 00247 object_ptr->next = NULL; 00248 object_ptr->prev = NULL; 00249 } 00250 } 00251 00252 /* 00253 * Handler function called from SysTick event handler. 00254 */ 00255 static void SYSTIMER_lTimerHandler(void) 00256 { 00257 SYSTIMER_OBJECT_t *object_ptr; 00258 /* Get first item of timer list */ 00259 object_ptr = g_timer_list; 00260 while ((NULL != object_ptr) && (0U == object_ptr->count)) 00261 { 00262 if (true == object_ptr->delete_swtmr) 00263 { 00264 /* Yes, remove this timer from timer list */ 00265 SYSTIMER_lRemoveTimerList((uint32_t)object_ptr->id); 00266 /* Set timer status as SYSTIMER_STATE_NOT_INITIALIZED */ 00267 object_ptr->state = SYSTIMER_STATE_NOT_INITIALIZED; 00268 /* Release resource which are hold by this timer */ 00269 g_timer_tracker &= ~(1U << object_ptr->id); 00270 } 00271 /* Check whether timer is a one shot timer */ 00272 else if (SYSTIMER_MODE_ONE_SHOT == object_ptr->mode) 00273 { 00274 /* Yes, remove this timer from timer list */ 00275 SYSTIMER_lRemoveTimerList((uint32_t)object_ptr->id); 00276 /* Set timer status as SYSTIMER_STATE_STOPPED */ 00277 object_ptr->state = SYSTIMER_STATE_STOPPED; 00278 /* Call timer callback function */ 00279 (object_ptr->callback)(object_ptr->args); 00280 } 00281 /* Check whether timer is periodic timer */ 00282 else if (SYSTIMER_MODE_PERIODIC == object_ptr->mode) 00283 { 00284 /* Yes, remove this timer from timer list */ 00285 SYSTIMER_lRemoveTimerList((uint32_t)object_ptr->id); 00286 /* Reset timer tick */ 00287 object_ptr->count = object_ptr->reload; 00288 /* Insert timer into timer list */ 00289 SYSTIMER_lInsertTimerList((uint32_t)object_ptr->id); 00290 /* Call timer callback function */ 00291 (object_ptr->callback)(object_ptr->args); 00292 } 00293 else 00294 { 00295 break; 00296 } 00297 /* Get first item of timer list */ 00298 object_ptr = g_timer_list; 00299 } 00300 } 00301 00302 /* 00303 * SysTick Event Handler. 00304 */ 00305 void SysTick_Handler(void) 00306 { 00307 SYSTIMER_OBJECT_t *object_ptr; 00308 object_ptr = g_timer_list; 00309 g_systick_count++; 00310 00311 if (NULL != object_ptr) 00312 { 00313 if (object_ptr->count > 1UL) 00314 { 00315 object_ptr->count--; 00316 } 00317 else 00318 { 00319 object_ptr->count = 0U; 00320 SYSTIMER_lTimerHandler(); 00321 } 00322 } 00323 } 00324 00329 /* 00330 * Function to retrieve the version of the SYSTIMER APP. 00331 */ 00332 DAVE_APP_VERSION_t SYSTIMER_GetAppVersion() 00333 { 00334 DAVE_APP_VERSION_t version; 00335 00336 version.major = (uint8_t)SYSTIMER_MAJOR_VERSION; 00337 version.minor = (uint8_t)SYSTIMER_MINOR_VERSION; 00338 version.patch = (uint8_t)SYSTIMER_PATCH_VERSION; 00339 00340 return (version); 00341 } 00342 00343 /* 00344 * Initialization function which initializes the SYSTIMER APP, configures SysTick timer and SysTick exception. 00345 */ 00346 SYSTIMER_STATUS_t SYSTIMER_Init(SYSTIMER_t *handle) 00347 { 00348 SYSTIMER_STATUS_t status = SYSTIMER_STATUS_SUCCESS; 00349 00350 XMC_ASSERT("SYSTIMER_Init: SYSTIMER APP handle pointer uninitialized", (handle != NULL)); 00351 00352 /* Check APP initialization status to ensure whether SYSTIMER_Init called or not, initialize SYSTIMER if 00353 * SYSTIMER_Init called first time. 00354 */ 00355 if (false == handle->init_status) 00356 { 00357 /* Initialize the header of the list */ 00358 g_timer_list = NULL; 00359 /* Initialize SysTick timer */ 00360 status = (SYSTIMER_STATUS_t)SysTick_Config((uint32_t)(SYSTIMER_SYSTICK_CLOCK * SYSTIMER_TICK_PERIOD)); 00361 00362 if (SYSTIMER_STATUS_FAILURE == status) 00363 { 00364 XMC_DEBUG("SYSTIMER_Init: Timer reload value out of range"); 00365 } 00366 else 00367 { 00368 #if (UC_FAMILY == XMC4) 00369 /* setting of First SW Timer period is always and subpriority value for XMC4000 devices */ 00370 NVIC_SetPriority(SysTick_IRQn, NVIC_EncodePriority( 00371 NVIC_GetPriorityGrouping(), SYSTIMER_PRIORITY, SYSTIMER_SUBPRIORITY)); 00372 #elif (UC_FAMILY == XMC1) 00373 /* setting of priority value for XMC1000 devices */ 00374 NVIC_SetPriority(SysTick_IRQn, SYSTIMER_PRIORITY); 00375 #endif 00376 g_timer_tracker = 0U; 00377 /* Update the Initialization status of the SYSTIMER APP instance */ 00378 handle->init_status = true; 00379 status = SYSTIMER_STATUS_SUCCESS; 00380 } 00381 } 00382 00383 return (status); 00384 } 00385 00386 /* 00387 * API for creating a new software Timer instance. 00388 */ 00389 uint32_t SYSTIMER_CreateTimer 00390 ( 00391 uint32_t period, 00392 SYSTIMER_MODE_t mode, 00393 SYSTIMER_CALLBACK_t callback, 00394 void *args 00395 ) 00396 { 00397 uint32_t id = 0U; 00398 uint32_t count = 0U; 00399 uint32_t period_ratio = 0U; 00400 00401 XMC_ASSERT("SYSTIMER_CreateTimer: Timer creation failure due to invalid period value", 00402 ((period >= SYSTIMER_TICK_PERIOD_US) && (period > 0U) && (period <= 0xFFFFFFFFU))); 00403 XMC_ASSERT("SYSTIMER_CreateTimer: Timer creation failure due to invalid timer mode", 00404 ((SYSTIMER_MODE_ONE_SHOT == mode) || (SYSTIMER_MODE_PERIODIC == mode))); 00405 XMC_ASSERT("SYSTIMER_CreateTimer: Can not create software without user callback", (NULL != callback)); 00406 00407 if (period < SYSTIMER_TICK_PERIOD_US) 00408 { 00409 id = 0U; 00410 } 00411 else 00412 { 00413 for (count = 0U; count < SYSTIMER_CFG_MAX_TMR; count++) 00414 { 00415 /* Check for free timer ID */ 00416 if (0U == (g_timer_tracker & (1U << count))) 00417 { 00418 /* If yes, assign ID to this timer */ 00419 g_timer_tracker |= (1U << count); 00420 /* Initialize the timer as per input values */ 00421 g_timer_tbl[count].id = count; 00422 g_timer_tbl[count].mode = mode; 00423 g_timer_tbl[count].state = SYSTIMER_STATE_STOPPED; 00424 period_ratio = (uint32_t)(period / SYSTIMER_TICK_PERIOD_US); 00425 g_timer_tbl[count].count = (period_ratio + HW_TIMER_ADDITIONAL_CNT); 00426 g_timer_tbl[count].reload = period_ratio; 00427 g_timer_tbl[count].callback = callback; 00428 g_timer_tbl[count].args = args; 00429 g_timer_tbl[count].prev = NULL; 00430 g_timer_tbl[count].next = NULL; 00431 id = count + 1U; 00432 break; 00433 } 00434 } 00435 00436 } 00437 00438 return (id); 00439 } 00440 00441 /* 00442 * API to start the software timer. 00443 */ 00444 SYSTIMER_STATUS_t SYSTIMER_StartTimer(uint32_t id) 00445 { 00446 SYSTIMER_STATUS_t status; 00447 status = SYSTIMER_STATUS_FAILURE; 00448 00449 XMC_ASSERT("SYSTIMER_StartTimer: Failure in timer restart operation due to invalid timer ID", 00450 ((id <= SYSTIMER_CFG_MAX_TMR) && (id > 0U))); 00451 XMC_ASSERT("SYSTIMER_StartTimer: Error during start of software timer", (0U != (g_timer_tracker & (1U << (id - 1U))))); 00452 00453 /* Check if timer is running */ 00454 if (SYSTIMER_STATE_STOPPED == g_timer_tbl[id - 1U].state) 00455 { 00456 g_timer_tbl[id - 1U].count = (g_timer_tbl[id - 1U].reload + HW_TIMER_ADDITIONAL_CNT); 00457 /* set timer status as SYSTIMER_STATE_RUNNING */ 00458 g_timer_tbl[id - 1U].state = SYSTIMER_STATE_RUNNING; 00459 /* Insert this timer into timer list */ 00460 SYSTIMER_lInsertTimerList((id - 1U)); 00461 status = SYSTIMER_STATUS_SUCCESS; 00462 } 00463 00464 return (status); 00465 } 00466 00467 /* 00468 * API to stop the software timer. 00469 */ 00470 SYSTIMER_STATUS_t SYSTIMER_StopTimer(uint32_t id) 00471 { 00472 SYSTIMER_STATUS_t status; 00473 status = SYSTIMER_STATUS_SUCCESS; 00474 00475 XMC_ASSERT("SYSTIMER_StopTimer: Failure in timer restart operation due to invalid timer ID", 00476 ((id <= SYSTIMER_CFG_MAX_TMR) && (id > 0U))); 00477 XMC_ASSERT("SYSTIMER_StopTimer: Error during stop of software timer", (0U != (g_timer_tracker & (1U << (id - 1U))))); 00478 00479 if (SYSTIMER_STATE_NOT_INITIALIZED == g_timer_tbl[id - 1U].state) 00480 { 00481 status = SYSTIMER_STATUS_FAILURE; 00482 } 00483 else 00484 { 00485 /* Check whether Timer is in Stop state */ 00486 if (SYSTIMER_STATE_RUNNING == g_timer_tbl[id - 1U].state) 00487 { 00488 /* remove Timer from node list */ 00489 SYSTIMER_lRemoveTimerList(id - 1U); 00490 /* Set timer status as SYSTIMER_STATE_STOPPED */ 00491 g_timer_tbl[id - 1U].state = SYSTIMER_STATE_STOPPED; 00492 } 00493 } 00494 00495 return (status); 00496 } 00497 00498 /* 00499 * API to reinitialize the time interval and to start the timer. 00500 */ 00501 SYSTIMER_STATUS_t SYSTIMER_RestartTimer(uint32_t id, uint32_t microsec) 00502 { 00503 uint32_t period_ratio = 0U; 00504 SYSTIMER_STATUS_t status; 00505 status = SYSTIMER_STATUS_SUCCESS; 00506 00507 XMC_ASSERT("SYSTIMER_RestartTimer: Failure in timer restart operation due to invalid timer ID", 00508 ((id <= SYSTIMER_CFG_MAX_TMR) && (id > 0U))); 00509 XMC_ASSERT("SYSTIMER_RestartTimer: Error during restart of software timer", (0U != (g_timer_tracker & (1U << (id - 1U))))); 00510 XMC_ASSERT("SYSTIMER_RestartTimer: Can not restart timer due to invalid period value", 00511 (microsec >= SYSTIMER_TICK_PERIOD_US) && (microsec > 0U)); 00512 00513 00514 if (SYSTIMER_STATE_NOT_INITIALIZED == g_timer_tbl[id - 1U].state) 00515 { 00516 status = SYSTIMER_STATUS_FAILURE; 00517 } 00518 else 00519 { 00520 /* check whether timer is in run state */ 00521 if( SYSTIMER_STATE_STOPPED != g_timer_tbl[id - 1U].state) 00522 { 00523 /* Stop the timer */ 00524 status = SYSTIMER_StopTimer(id); 00525 } 00526 if (SYSTIMER_STATUS_SUCCESS == status) 00527 { 00528 period_ratio = (uint32_t)(microsec / SYSTIMER_TICK_PERIOD_US); 00529 g_timer_tbl[id - 1U].reload = period_ratio; 00530 /* Start the timer */ 00531 status = SYSTIMER_StartTimer(id); 00532 } 00533 } 00534 00535 return (status); 00536 } 00537 00538 /* 00539 * Function to delete the Timer instance. 00540 */ 00541 SYSTIMER_STATUS_t SYSTIMER_DeleteTimer(uint32_t id) 00542 { 00543 SYSTIMER_STATUS_t status; 00544 status = SYSTIMER_STATUS_SUCCESS; 00545 00546 XMC_ASSERT("SYSTIMER_DeleteTimer: Failure in timer restart operation due to invalid timer ID", 00547 ((id <= SYSTIMER_CFG_MAX_TMR) && (id > 0U))); 00548 XMC_ASSERT("SYSTIMER_DeleteTimer: Error during deletion of software timer", (0U != (g_timer_tracker & (1U << (id - 1U))))); 00549 00550 /* Check whether Timer is in delete state */ 00551 if (SYSTIMER_STATE_NOT_INITIALIZED == g_timer_tbl[id - 1U].state) 00552 { 00553 status = SYSTIMER_STATUS_FAILURE; 00554 } 00555 else 00556 { 00557 if (SYSTIMER_STATE_STOPPED == g_timer_tbl[id - 1U].state) 00558 { 00559 /* Set timer status as SYSTIMER_STATE_NOT_INITIALIZED */ 00560 g_timer_tbl[id - 1U].state = SYSTIMER_STATE_NOT_INITIALIZED; 00561 /* Release resource which are hold by this timer */ 00562 g_timer_tracker &= ~(1U << (id - 1U)); 00563 } 00564 else 00565 { 00566 /* Yes, remove this timer from timer list during ISR execution */ 00567 g_timer_tbl[id - 1U].delete_swtmr = true; 00568 } 00569 } 00570 00571 return (status); 00572 } 00573 00574 /* 00575 * API to get the current SysTick time in microsecond. 00576 */ 00577 uint32_t SYSTIMER_GetTime(void) 00578 { 00579 return (g_systick_count * SYSTIMER_TICK_PERIOD_US); 00580 } 00581 00582 /* 00583 * API to get the SysTick count. 00584 */ 00585 uint32_t SYSTIMER_GetTickCount(void) 00586 { 00587 return (g_systick_count); 00588 } 00589 00590 /* 00591 * API to get the current state of software timer. 00592 */ 00593 SYSTIMER_STATE_t SYSTIMER_GetTimerState(uint32_t id) 00594 { 00595 return (g_timer_tbl[id - 1U].state); 00596 }