Timer Driver

The Timer driver provides means for delayed and periodical function invocation.

Timer Basics and Best Practice

A timer task is a piece of code (function) executed at a specific time or periodically by the timer after the task has been added to the timers task queue. The execution delay or period is set in ticks, where one tick is defined as a configurable number of clock cycles in the hardware timer. Changing the number of clock cycles in a tick automatically changes execution delays and periods for all tasks in the timers task queue.

A task has two operation modes, single-shot or repeating mode. In single-shot mode the task is removed from the task queue and then executed once. In repeating mode the task reschedules itself automatically after it has executed based on the period set in the task configuration. In single-shot mode a task is removed from the task queue before its callback is invoked. It allows an application to reuse the memory of expired tasks in the callback.

Each instance of the Timer driver supports an infinite number of timer tasks, only limited by the amount of RAM available.

Summary of the API's Functional Features

The API provides functions to:
  • Initialization and deinitialization

  • Starting and stopping

  • Timer tasks - periodical invocation of functions

  • Changing and obtaining of the period of a timer

Summary of Configuration Options

A hardware timer is needed for this timer driver, and can be configured in START. Take SAM D21 for example, one of TC, TCC, RTC can be selected as hardware timer instance, and can configure timer tick in START.

Driver Implementation Description

Concurrency

The Timer driver is an interrupt driven driver.This means that the interrupt that triggers a task may occur during the process of adding or removing a task via the driver's API. In such case the interrupt processing is postponed until the task adding or removing is complete.

The task queue is not protected from the access by interrupts not used by the driver. Due to this it is not recommended to add or remove a task from such interrupts: in case if a higher priority interrupt supersedes the driver's interrupt, adding or removing a task may cause an unpredictable behavior of the driver.

Limitations

  • The driver is designed to work outside of an operating system environment. The task queue is therefore processed in interrupt context which may delay execution of other interrupts

  • If there are a lot of frequently called interrupts with a priority higher than the driver's one, it may cause delay for triggering of a task

Example of Usage

The following shows a simple example of using the Timer. The Timer driver must have been initialized by timer_init. This initialization will configure the operation of the hardware timer instance, such as ticks for this timer.

The example enables two repeat timer tasks at different time intervals.

          /**
           * Example of using TIMER_0.
           */
          static void TIMER_0_task1_cb(const struct timer_task *const timer_task)
          {
          }
          static void TIMER_0_task2_cb(const struct timer_task *const timer_task)
          {
          }
          void TIMER_0_example(void)
          {
              TIMER_0_task1.interval = 100;
              TIMER_0_task1.cb       = TIMER_0_task1_cb;
              TIMER_0_task1.mode     = TIMER_TASK_REPEAT;
              TIMER_0_task2.interval = 200;
              TIMER_0_task2.cb       = TIMER_0_task2_cb;
              TIMER_0_task2.mode     = TIMER_TASK_REPEAT;
              timer_add_task(&TIMER_0, &TIMER_0_task1);
              timer_add_task(&TIMER_0, &TIMER_0_task2);
              timer_start(&TIMER_0);
          }
        

Dependencies

  • Each instance of the driver requires separate hardware timer capable of generating periodic interrupt