SYSTIMER: SYSTIMER.c Source File

Modbus RTU XMC47

SYSTIMER.c
Go to the documentation of this file.
1 
78 /***********************************************************************************************************************
79  * HEADER FILES
80  **********************************************************************************************************************/
81 
82 /* Included to access APP data structure, functions & enumerations */
83 #include "systimer.h"
84 
85 /***********************************************************************************************************************
86  * MACROS
87  **********************************************************************************************************************/
88 
89 #define HW_TIMER_ADDITIONAL_CNT (1U)
90 
91 /***********************************************************************************************************************
92  * LOCAL DATA
93  **********************************************************************************************************************/
94 /* SYSTIMER_OBJECT structure acts as the timer control block */
95 
96 typedef struct SYSTIMER_OBJECT
97 {
98  struct SYSTIMER_OBJECT *next;
99  struct SYSTIMER_OBJECT *prev;
100  SYSTIMER_CALLBACK_t callback;
101  void *args;
102  uint32_t id;
103  uint32_t count;
104  uint32_t reload;
105  SYSTIMER_MODE_t mode;
106  SYSTIMER_STATE_t state;
107 } SYSTIMER_OBJECT_t;
108 
110 SYSTIMER_OBJECT_t g_timer_tbl[SYSTIMER_CFG_MAX_TMR];
111 
112 /* The header of the timer Control list. */
113 SYSTIMER_OBJECT_t *g_timer_list = NULL;
114 
115 /* Timer ID tracker */
116 uint32_t g_timer_tracker = 0U;
117 
118 /* SysTick counter */
119 volatile uint32_t g_systick_count = 0U;
120 
121 /***********************************************************************************************************************
122  * LOCAL ROUTINES
123  **********************************************************************************************************************/
124 
125 /*
126  * This function is called to insert a timer into the timer list.
127  */
128 static void SYSTIMER_lInsertTimerList(uint32_t tbl_index);
129 
130 /*
131  * This function is called to remove a timer from the timer list.
132  */
133 static void SYSTIMER_lRemoveTimerList(uint32_t tbl_index);
134 
135 /*
136  * Handler function called from SysTick event handler.
137  */
138 static void SYSTIMER_lTimerHandler(void);
139 
140 /*
141  * SysTick handler which is the main interrupt service routine to service the
142  * system timer's configured
143  */
144 void SysTick_Handler(void);
145 
146 /**********************************************************************************************************************
147 * API IMPLEMENTATION
148 **********************************************************************************************************************/
149 __attribute__((always_inline)) __STATIC_INLINE uint32_t critical_section_enter(void)
150 {
151  uint32_t status;
152  status = __get_PRIMASK();
153  __disable_irq ();
154  return status;
155 }
156 
157 __attribute__((always_inline)) __STATIC_INLINE void critical_section_exit(uint32_t status)
158 {
159  __set_PRIMASK(status);
160 }
161 
162 void SYSTIMER_Start(void)
163 {
164  SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;
165 }
166 
167 void SYSTIMER_Stop(void)
168 {
169  SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;
170 }
171 
172 /*
173  * This function is called to insert a timer into the timer list.
174  */
175 static void SYSTIMER_lInsertTimerList(uint32_t tbl_index)
176 {
177  SYSTIMER_OBJECT_t *object_ptr;
178  int32_t delta_ticks;
179  int32_t timer_count;
180  bool found_flag = false;
181 
182  /* Get timer time */
183  timer_count = (int32_t)g_timer_tbl[tbl_index].count;
184  /* Check if Timer list is NULL */
185  if (NULL == g_timer_list)
186  {
187  /* Set this as first Timer */
188  g_timer_list = &g_timer_tbl[tbl_index];
189  }
190  /* If not, find the correct place, and insert the specified timer */
191  else
192  {
193  object_ptr = g_timer_list;
194  /* Get timer tick */
195  delta_ticks = timer_count;
196  /* Find correct place for inserting the timer */
197  while ((NULL != object_ptr) && (false == found_flag))
198  {
199  /* Get timer Count Difference */
200  delta_ticks -= (int32_t)object_ptr->count;
201  /* Check for delta ticks < 0 */
202  if (delta_ticks <= 0)
203  {
204  /* Check If head item */
205  if (NULL != object_ptr->prev)
206  {
207  /* If Insert to list */
208  object_ptr->prev->next = &g_timer_tbl[tbl_index];
209  g_timer_tbl[tbl_index].prev = object_ptr->prev;
210  g_timer_tbl[tbl_index].next = object_ptr;
211  object_ptr->prev = &g_timer_tbl[tbl_index];
212  }
213  else
214  {
215  /* Set Timer as first item */
216  g_timer_tbl[tbl_index].next = g_timer_list;
217  g_timer_list->prev = &g_timer_tbl[tbl_index];
218  g_timer_list = &g_timer_tbl[tbl_index];
219  }
220  g_timer_tbl[tbl_index].count = g_timer_tbl[tbl_index].next->count + (uint32_t)delta_ticks;
221  g_timer_tbl[tbl_index].next->count -= g_timer_tbl[tbl_index].count;
222  found_flag = true;
223  }
224  /* Check for last item in list */
225  else
226  {
227  if ((delta_ticks > 0) && (NULL == object_ptr->next))
228  {
229  /* Yes, insert into */
230  g_timer_tbl[tbl_index].prev = object_ptr;
231  object_ptr->next = &g_timer_tbl[tbl_index];
232  g_timer_tbl[tbl_index].count = (uint32_t)delta_ticks;
233  found_flag = true;
234  }
235  }
236  /* Get the next item in timer list */
237  object_ptr = object_ptr->next;
238  }
239  }
240 }
241 
242 /*
243  * This function is called to remove a timer from the timer list.
244  */
245 static void SYSTIMER_lRemoveTimerList(uint32_t tbl_index)
246 {
247  SYSTIMER_OBJECT_t *object_ptr;
248 
249  object_ptr = &g_timer_tbl[tbl_index];
250  /* Check whether only one timer available */
251  if ((NULL == object_ptr->prev) && (NULL == object_ptr->next ))
252  {
253  /* set timer list as NULL */
254  g_timer_list = NULL;
255  }
256  /* Check if the first item in timer list */
257  else if (NULL == object_ptr->prev)
258  {
259  /* Remove timer from list, and reset timer list */
260  g_timer_list = object_ptr->next;
261  g_timer_list->prev = NULL;
262  g_timer_list->count += object_ptr->count;
263  object_ptr->next = NULL;
264  }
265  /* Check if the last item in timer list */
266  else if (NULL == object_ptr->next)
267  {
268  /* Remove timer from list */
269  object_ptr->prev->next = NULL;
270  object_ptr->prev = NULL;
271  }
272  else
273  {
274  /* Remove timer from list */
275  object_ptr->prev->next = object_ptr->next;
276  object_ptr->next->prev = object_ptr->prev;
277  object_ptr->next->count += object_ptr->count;
278  object_ptr->next = NULL;
279  object_ptr->prev = NULL;
280  }
281 
282 }
283 
284 /*
285  * Handler function called from SysTick event handler.
286  */
287 static void SYSTIMER_lTimerHandler(void)
288 {
289  SYSTIMER_OBJECT_t *object_ptr;
290 
291  /* Get first item of timer list */
292  object_ptr = g_timer_list;
293  while ((NULL != object_ptr) && (0U == object_ptr->count))
294  {
295  if (SYSTIMER_STATE_RUNNING == object_ptr->state)
296  {
297  /* Check whether timer is a one shot timer */
298  if (SYSTIMER_MODE_ONE_SHOT == object_ptr->mode)
299  {
300  /* Yes, remove this timer from timer list */
301  SYSTIMER_lRemoveTimerList((uint32_t)object_ptr->id);
302  /* Set timer status as SYSTIMER_STATE_STOPPED */
303  object_ptr->state = SYSTIMER_STATE_STOPPED;
304  /* Call timer callback function */
305  (object_ptr->callback)(object_ptr->args);
306  }
307  /* Check whether timer is periodic timer */
308  else if (SYSTIMER_MODE_PERIODIC == object_ptr->mode)
309  {
310  /* Yes, remove this timer from timer list */
311  SYSTIMER_lRemoveTimerList((uint32_t)object_ptr->id);
312  /* Reset timer tick */
313  object_ptr->count = object_ptr->reload;
314  /* Insert timer into timer list */
315  SYSTIMER_lInsertTimerList((uint32_t)object_ptr->id);
316  /* Call timer callback function */
317  (object_ptr->callback)(object_ptr->args);
318  }
319  }
320  /* Get first item of timer list */
321  object_ptr = g_timer_list;
322  }
323 
324 }
325 
326 /*
327  * SysTick Event Handler.
328  */
329 void SysTick_Handler(void)
330 {
331  SYSTIMER_OBJECT_t *object_ptr;
332  object_ptr = g_timer_list;
333  g_systick_count++;
334 
335  if (NULL != object_ptr)
336  {
337  if (object_ptr->count > 1UL)
338  {
339  object_ptr->count--;
340  }
341  else
342  {
343  object_ptr->count = 0U;
344  SYSTIMER_lTimerHandler();
345  }
346  }
347 }
348 
353 /*
354  * Function to retrieve the version of the SYSTIMER APP.
355  */
356 DAVE_APP_VERSION_t SYSTIMER_GetAppVersion()
357 {
358  DAVE_APP_VERSION_t version;
359 
360  version.major = (uint8_t)SYSTIMER_MAJOR_VERSION;
361  version.minor = (uint8_t)SYSTIMER_MINOR_VERSION;
362  version.patch = (uint8_t)SYSTIMER_PATCH_VERSION;
363 
364  return (version);
365 }
366 
367 /*
368  * Initialization function which initializes the SYSTIMER APP, configures SysTick timer and SysTick exception.
369  */
371 {
373 
374  XMC_ASSERT("SYSTIMER_Init: SYSTIMER APP handle pointer uninitialized", (handle != NULL));
375 
376  /* Check APP initialization status to ensure whether SYSTIMER_Init called or not, initialize SYSTIMER if
377  * SYSTIMER_Init called first time.
378  */
379  if (false == handle->init_status)
380  {
381  /* Initialize the header of the list */
382  g_timer_list = NULL;
383  /* Initialize SysTick timer */
384  status = (SYSTIMER_STATUS_t)SysTick_Config((uint32_t)(SYSTIMER_SYSTICK_CLOCK * SYSTIMER_TICK_PERIOD));
385 
386  if (SYSTIMER_STATUS_FAILURE == status)
387  {
388  XMC_DEBUG("SYSTIMER_Init: Timer reload value out of range");
389  }
390  else
391  {
392 #if (UC_FAMILY == XMC4)
393  /* setting of First SW Timer period is always and subpriority value for XMC4000 devices */
394  NVIC_SetPriority(SysTick_IRQn, NVIC_EncodePriority(
395  NVIC_GetPriorityGrouping(), SYSTIMER_PRIORITY, SYSTIMER_SUBPRIORITY));
396 #elif (UC_FAMILY == XMC1)
397  /* setting of priority value for XMC1000 devices */
398  NVIC_SetPriority(SysTick_IRQn, SYSTIMER_PRIORITY);
399 #endif
400  g_timer_tracker = 0U;
401  /* Update the Initialization status of the SYSTIMER APP instance */
402  handle->init_status = true;
403  status = SYSTIMER_STATUS_SUCCESS;
404  }
405  }
406 
407  return (status);
408 }
409 
410 /*
411  * API for creating a new software Timer instance.
412  */
413 uint32_t SYSTIMER_CreateTimer
414 (
415  uint32_t period,
416  SYSTIMER_MODE_t mode,
417  SYSTIMER_CALLBACK_t callback,
418  void *args
419 )
420 {
421  uint32_t id = 0U;
422  uint32_t count = 0U;
423  uint32_t period_ratio = 0U;
424 
425  XMC_ASSERT("SYSTIMER_CreateTimer: Timer creation failure due to invalid period value",
426  ((period >= SYSTIMER_TICK_PERIOD_US) && (period > 0U) && (period <= 0xFFFFFFFFU)));
427  XMC_ASSERT("SYSTIMER_CreateTimer: Timer creation failure due to invalid timer mode",
428  ((SYSTIMER_MODE_ONE_SHOT == mode) || (SYSTIMER_MODE_PERIODIC == mode)));
429  XMC_ASSERT("SYSTIMER_CreateTimer: Can not create software without user callback", (NULL != callback));
430 
431  if (period < SYSTIMER_TICK_PERIOD_US)
432  {
433  id = 0U;
434  }
435  else
436  {
437  for (count = 0U; count < SYSTIMER_CFG_MAX_TMR; count++)
438  {
439  /* Check for free timer ID */
440  if (0U == (g_timer_tracker & (1U << count)))
441  {
442  /* If yes, assign ID to this timer */
443  g_timer_tracker |= (1U << count);
444  /* Initialize the timer as per input values */
445  g_timer_tbl[count].id = count;
446  g_timer_tbl[count].mode = mode;
447  g_timer_tbl[count].state = SYSTIMER_STATE_STOPPED;
448  period_ratio = (uint32_t)(period / SYSTIMER_TICK_PERIOD_US);
449  g_timer_tbl[count].count = (period_ratio + HW_TIMER_ADDITIONAL_CNT);
450  g_timer_tbl[count].reload = period_ratio;
451  g_timer_tbl[count].callback = callback;
452  g_timer_tbl[count].args = args;
453  g_timer_tbl[count].prev = NULL;
454  g_timer_tbl[count].next = NULL;
455  id = count + 1U;
456  break;
457  }
458  }
459 
460  }
461 
462  return (id);
463 }
464 
466 (
467  uint32_t period,
468  SYSTIMER_MODE_t mode,
469  SYSTIMER_CALLBACK_t callback,
470  void *args
471 )
472 {
473  uint32_t id;
474 
475  uint32_t ics;
476  ics = critical_section_enter();
477 
478  id = SYSTIMER_CreateTimer(period, mode, callback, args);
479 
480  critical_section_exit(ics);
481 
482  return (id);
483 }
484 
485 /*
486  * API to start the software timer.
487  */
489 {
490  SYSTIMER_STATUS_t status;
491 
492  status = SYSTIMER_STATUS_FAILURE;
493 
494  XMC_ASSERT("SYSTIMER_StartTimer: Failure in timer restart operation due to invalid timer ID",
495  ((id <= SYSTIMER_CFG_MAX_TMR) && (id > 0U)));
496  XMC_ASSERT("SYSTIMER_StartTimer: Error during start of software timer", (0U != (g_timer_tracker & (1U << (id - 1U)))));
497 
498  /* Check if timer is running */
499  if (SYSTIMER_STATE_STOPPED == g_timer_tbl[id - 1U].state)
500  {
501  g_timer_tbl[id - 1U].state = SYSTIMER_STATE_RUNNING;
502  g_timer_tbl[id - 1U].count = (g_timer_tbl[id - 1U].reload + HW_TIMER_ADDITIONAL_CNT);
503 
504  /* Insert this timer into timer list */
505  SYSTIMER_lInsertTimerList((id - 1U));
506 
507  status = SYSTIMER_STATUS_SUCCESS;
508  }
509 
510  return (status);
511 }
512 
514 {
515  SYSTIMER_STATUS_t status;
516 
517  uint32_t ics;
518  ics = critical_section_enter();
519 
520  status = SYSTIMER_StartTimer(id);
521 
522  critical_section_exit(ics);
523 
524  return (status);
525 }
526 
527 /*
528  * API to stop the software timer.
529  */
531 {
532  SYSTIMER_STATUS_t status;
533 
534  status = SYSTIMER_STATUS_SUCCESS;
535 
536  XMC_ASSERT("SYSTIMER_StopTimer: Failure in timer restart operation due to invalid timer ID",
537  ((id <= SYSTIMER_CFG_MAX_TMR) && (id > 0U)));
538  XMC_ASSERT("SYSTIMER_StopTimer: Error during stop of software timer", (0U != (g_timer_tracker & (1U << (id - 1U)))));
539 
540  if (SYSTIMER_STATE_NOT_INITIALIZED == g_timer_tbl[id - 1U].state)
541  {
542  status = SYSTIMER_STATUS_FAILURE;
543  }
544  else
545  {
546  /* Check whether Timer is in Stop state */
547  if (SYSTIMER_STATE_RUNNING == g_timer_tbl[id - 1U].state)
548  {
549  g_timer_tbl[id - 1U].state = SYSTIMER_STATE_STOPPED;
550  /* remove Timer from node list */
551  SYSTIMER_lRemoveTimerList(id - 1U);
552  }
553  }
554 
555  return (status);
556 }
557 
559 {
560  SYSTIMER_STATUS_t status;
561 
562  uint32_t ics;
563  ics = critical_section_enter();
564 
565  status = SYSTIMER_StopTimer(id);
566 
567  critical_section_exit(ics);
568 
569  return (status);
570 }
571 
572 /*
573  * API to reinitialize the time interval and to start the timer.
574  */
575 SYSTIMER_STATUS_t SYSTIMER_RestartTimer(uint32_t id, uint32_t microsec)
576 {
577  uint32_t period_ratio = 0U;
578  SYSTIMER_STATUS_t status;
579 
580  status = SYSTIMER_STATUS_SUCCESS;
581 
582  XMC_ASSERT("SYSTIMER_RestartTimer: Failure in timer restart operation due to invalid timer ID",
583  ((id <= SYSTIMER_CFG_MAX_TMR) && (id > 0U)));
584  XMC_ASSERT("SYSTIMER_RestartTimer: Error during restart of software timer", (0U != (g_timer_tracker & (1U << (id - 1U)))));
585  XMC_ASSERT("SYSTIMER_RestartTimer: Can not restart timer due to invalid period value",
586  (microsec >= SYSTIMER_TICK_PERIOD_US) && (microsec > 0U));
587 
588 
589  if (SYSTIMER_STATE_NOT_INITIALIZED == g_timer_tbl[id - 1U].state)
590  {
591  status = SYSTIMER_STATUS_FAILURE;
592  }
593  else
594  {
595  /* check whether timer is in run state */
596  if( SYSTIMER_STATE_STOPPED != g_timer_tbl[id - 1U].state)
597  {
598  /* Stop the timer */
599  status = SYSTIMER_StopTimer(id);
600  }
601  if (SYSTIMER_STATUS_SUCCESS == status)
602  {
603  period_ratio = (uint32_t)(microsec / SYSTIMER_TICK_PERIOD_US);
604  g_timer_tbl[id - 1U].reload = period_ratio;
605  /* Start the timer */
606  status = SYSTIMER_StartTimer(id);
607  }
608  }
609 
610  return (status);
611 }
612 
613 SYSTIMER_STATUS_t SYSTIMER_RestartTimerFromISR(uint32_t id, uint32_t microsec)
614 {
615  SYSTIMER_STATUS_t status;
616 
617  uint32_t ics;
618  ics = critical_section_enter();
619 
620  status = SYSTIMER_RestartTimerFromISR(id, microsec)
621 
622  critical_section_exit(ics);
623 
624  return (status);
625 }
626 
627 /*
628  * Function to delete the Timer instance.
629  */
631 {
632  SYSTIMER_STATUS_t status;
633 
634  status = SYSTIMER_STATUS_SUCCESS;
635 
636  XMC_ASSERT("SYSTIMER_DeleteTimer: Failure in timer restart operation due to invalid timer ID",
637  ((id <= SYSTIMER_CFG_MAX_TMR) && (id > 0U)));
638  XMC_ASSERT("SYSTIMER_DeleteTimer: Error during deletion of software timer", (0U != (g_timer_tracker & (1U << (id - 1U)))));
639 
640  /* Check whether Timer is in delete state */
641  if (SYSTIMER_STATE_NOT_INITIALIZED == g_timer_tbl[id - 1U].state)
642  {
643  status = SYSTIMER_STATUS_FAILURE;
644  }
645  else
646  {
647  status = SYSTIMER_StopTimer(id);
648 
649  /* Set timer status as SYSTIMER_STATE_NOT_INITIALIZED */
651  /* Release resource which are hold by this timer */
652  g_timer_tracker &= ~(1U << (id - 1U));
653 
654  }
655 
656  return (status);
657 }
658 
660 {
661  SYSTIMER_STATUS_t status;
662 
663  uint32_t ics;
664  ics = critical_section_enter();
665 
666  status = SYSTIMER_DeleteTimer(id);
667 
668  critical_section_exit(ics);
669 
670  return (status);
671 }
672 
673 /*
674  * API to get the current SysTick time in microsecond.
675  */
676 uint32_t SYSTIMER_GetTime(void)
677 {
678  return (g_systick_count * SYSTIMER_TICK_PERIOD_US);
679 }
680 
681 /*
682  * API to get the SysTick count.
683  */
684 uint32_t SYSTIMER_GetTickCount(void)
685 {
686  return (g_systick_count);
687 }
688 
689 /*
690  * API to get the current state of software timer.
691  */
693 {
694  return (g_timer_tbl[id - 1U].state);
695 }