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:
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. |
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). |
/* Getting the number of ticks since the "epoch": the instant of the system initialization.*/ systime_t now = chVTGetSystemTime();
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; ...; }
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. |
/* Getting the number of seconds since the "epoch": the instant of the system initialization.*/ uint32_t now = ST2S(chVTGetSystemTime());
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();
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:
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.
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() . |
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); } }
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(); }
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:
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:
There are some things to consider:
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.
ChibiOS - Copyright © 2006..2017 Giovanni Di Sirio.