SYSTIMER: SYSTIMER.c Source File

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