RT Virtual Timers

Virtual Timers are an unique ChibiOS/RT feature. It is a software system able to provide an “unlimited” number of one-shot timers with the same resolution of the system tick. Virtual timers are also used internally in order to implement the timeout feature present in many API functions.
The services of the threading module are:

  • System Time.
  • Time Conversion Utilities.
  • Time Intervals Utilities.
  • One Shot Timers.
  • Tickless Mode.

Global Settings

Virtual timers are affected by the following global settings:

CH_CFG_ST_RESOLUTION System time type systime_t resolution in bits, it can be 16 or 32. The system time is a global counter incremented by a dedicated HW timer.
CH_CFG_ST_FREQUENCY System time frequency. Defines the working frequency of the dedicated system timer.
CH_CFG_ST_TIMEDELTA If zero then the kernel uses the classic tick mode, in alternative the new tickless mode is activated. Values greater or equal to two defines the minimum number of ticks for intervals, the value one is forbidden.

System Time

API

chVTGetSystemTime() Returns the system time.
chVTGetSystemTimeX() Returns the system time (X-Class variant). This function can be called from any context but its atomicity is not guaranteed on architectures whose word size is less than systime_t size.
chVTTimeElapsedSinceX() Returns the time passed since the specified time in system ticks. It is equivalent to: chVTGetSystemTimeX() - time.
chVTIsTimeWithinX() Returns true if the specified time is within the specified interval.
chVTIsSystemTimeWithin() Returns true if the system time is within the specified interval.
chVTIsSystemTimeWithinX() Returns true if the system time is within the specified interval (X-Class variant).

Examples

Reading System Time

  /* Getting the number of ticks since the "epoch": the instant of
     the system initialization.*/
  systime_t now = chVTGetSystemTime();

Time Bounded Loop

A loop executes performs an internal activity until a condition is met or a specified time period expires.

  /* The following loop executes for 200 milliseconds or until an internal
     condition is met, whichever comes first.*/
  systime_t start = chVTGetSystemTime();
  systime_t end = start + MS2ST(200);
  while (chVTIsSystemTimeWithin(start, end) {
 
    ...;
 
    if (condition)
      break;
 
    ...;
  }

Time Conversion Utilities

API

S2ST() Seconds to system ticks. The result is rounded upward to the next tick boundary.
MS2ST() Milliseconds to system ticks. The result is rounded upward to the next tick boundary.
US2ST() Microseconds to system ticks. The result is rounded upward to the next tick boundary.
ST2S() System ticks to seconds. The result is rounded up to the next second boundary.
ST2MS() System ticks to milliseconds. The result is rounded up to the next millisecond boundary.
ST2US() System ticks to microseconds. The result is rounded up to the next microsecond boundary.

Examples

System Time in Seconds

  /* Getting the number of seconds since the "epoch": the instant of
     the system initialization.*/
  uint32_t now = ST2S(chVTGetSystemTime());

Timeout in Milliseconds

Many functions can have a timeout specification in system ticks, it is also possible to specify timeouts using normal time units.

/* Waiting for a network event with a timeout of 200 milliseconds.*/
  chSysLock();
  msg_t msg = chThdEnqueueTimeoutS(&rx_frames_queue,
                                   MS2ST(200));
  if (msg == MSG_TIMEOUT) {
    /* Timeout management.*/
    ...;
  }
  chSysUnlock();

One Shot Timers

Virtual timers are one-shot timers that can be started, stopped prematurely or trigger a callback after their programmed time is expired. The timers state machine is:

Virtual Timer States

Callbacks

Timers callbacks are always invoked from ISR context, this means that the API that can be utilized from a timer callback is subject to the same restrictions applicable to ISRs. By re-arming a virtual timer from the callback it is possible to implement periodic or aperiodic timers as well.

API

chVTObjectInit() Initializes a virtual timer object virtual_timer_t.
chVTSet() Starts or restarts a virtual timer.
chVTSetI() Starts or restarts a virtual timer (I-Class variant).
chVTReset() Stops, if active, a virtual timer.
chVTResetI() Stops, if active, a virtual timer (I-Class variant).
chVTIsArmedI() Returns true if the timer is armed.
chVTDoSetI() Starts a virtual timer, the timer must not be already armed. Slightly faster than chVTSetI().
chVTDoResetI() Stops a virtual timer, the timer must be already armed. Slightly faster than chVTResetI().

Examples

Monostable LED Blinker

A function blinks a LED one time for a fixed period, if called repeatedly the LED stays on.

static virtual_timer_t led_vt;
 
/*
 * LED timer callback.
 */
static void led_cb(void *arg) {
 
  LED_off();
}
 
/*
 * Monostable blinker function.
 */
void blink(void) {
 
  LED_on();
  chVTSet(&led_vt, MS2ST(500), led_cb, NULL);
}
 
/*
 * Application main function.
 */
void main(void) {
 
  /*
   * System initializations.
   * - Kernel initialization, the main() function becomes a thread and the
   *   RTOS is active. Interrupts are enabled on chSysInit() exit.
   */
  chSysInit();
 
  /* LED timer initialization.*/
  chVTObjectInit(&led_vt);
 
  /* Blinking the LED when the key is pressed.*/
  while (true) {
    if (key_pressed())
      blink();
 
    chThdSleepMilliseconds(50);
  }  
}

Continuous LED Blinker

A virtual timer is used a dedicated LED blinker. The blinker can be started and stopped with a single command.

static virtual_timer_t led_vt;
 
/*
 * LED timer callback.
 */
static void led_cb(void *arg) {
 
  LED_toggle();
  chSysLockFromISR();
  chVTSetI(&led_vt, MS2ST(500), led_cb, NULL);
  chSysUnlockFromISR();
}
 
/*
 * Application main function.
 */
void main(void) {
 
  /*
   * System initializations.
   * - Kernel initialization, the main() function becomes a thread and the
   *   RTOS is active. Interrupts are enabled on chSysInit() exit.
   */
  chSysInit();
 
  /* LED timer initialization.*/
  chVTObjectInit(&led_vt);
 
  /* Starting blinker.*/
  chVTSet(&led_vt, MS2ST(500), led_cb, NULL);
 
  ...;
 
  /* Stopping blinker.*/
  chVTReset(&led_vt);
  LED_off();
}

Tickless Mode

Common RTOS kernels are triggered by a periodic interrupt, called system tick, driving the internal timings-relate mechanisms. In ChibiOS/RT the system tick is handled efficiently however it can still limits the system in several ways:

  • CPU usage is increased by the frequent IRQ servicing, the problem gets worse at higher frequencies.
  • The system tick limits the resolution of the virtual timers and of the system time because a too high frequency would negatively affect the system performance.
  • The system jitter is worsened by the continuous interruptions.
  • Frequent interrupts can prevent the system from entering deeper sleep modes. This affects negatively the system power usage.

ChibiOS/RT implements a unique tickless mode in its virtual timers subsystem. When the tickless mode is activated the system timer is no more generating periodic interrupts but is programmed to generate an interrupt only when the system has some scheduled activity to execute, usually a virtual timer expiration.
This approach has several positive aspects:

  • Lower power consumption thanks to the use of deeper sleep modes not continuously interrupted by a system tick.
  • Better overall jitter in ISR servicing.
  • Higher resolution for system time and virtual timers because the timer frequency is no more constrained.

There are some things to consider:

  • A new ChibiOS/RT port is more complex if the tickless mode has to be implemented.
  • A special timer must be present in HW and dedicated to the tickless mode. It must be an up-counter with a comparator register. A 16 bits counter is sufficient however a 32 bits counter is recommended.
  • The behavior of the system time within critical zones is slightly different, in tick mode the system time is not incremented, in tickless mode the time is always incremented because the timer counter register is used and it is not affected by the critical zone.
  • Slightly larger kernel image.

The system can use both modes without impacts for applications so the mode can be changed without problems, in order to make comparisons for example.