ChibiOS/RT Logo ChibiOS/RT

Architecture - Reference Manual - Guides

Reliable timings using Threads

One common task is to have threads do something at regular, scheduled, intervals. An obvious solution is to write something like this:

msg_t my_thread(void *param) {

  while (TRUE) {
    do_something();
    chThdSleepMilliseconds(1000);   // Fixed interval
  }
}

This example works well assuming that the do_something() execution time is well below the system tick period and that my_thread() is not preempted by other threads that could insert long intervals.
If the above conditions are not satisfied you may have do_something() executed at irregular intervals, as example:

T0...T0+1000...T0+2002...T0+3002...T0+4005...etc.

Also note that the error increases over time and this kind of behavior can lead to anomalies really hard to debug.

A better solution

It is possible to rewrite the above code using absolute deadlines rather than fixed intervals:

msg_t my_thread(void *param) {

  systick_t time = chTimeNow();     // T0
  while (TRUE) {
    time += MS2ST(1000);            // Next deadline
    do_something();
    chThdSleepUntil(time);
  }
}

Using this code do_something() will always be executed at an absolute deadline time and the error will not accumulate over time regardless of the execution time and delays inserted by other threads.
Note that this solution requires that the do_something() execution time must not exceed the deadline or the thread would stay sleeping into chThdSleepUntil().

A different way

Another way to perform activities at regular intervals is the use of a virtual timer. Virtual timers are able to generate callbacks at scheduled intervals. Virtual timers are one shot timers so you need to restart them from within the callback if you need a periodic timer like in this case.

VirtualTimer vt;

void do_something(void *p) {

  chVTSetI(&vt, MS2ST(1000), do_something, p);      // Restarts the timer.
  // Periodic code here.
}

int main(int argc, char **argv) {

  chSysLock();
  chVTSetI(&vt, MS2ST(1000), do_something, NULL);   // Starts the timer.
  chSysUnlock();
  ...
}

Note that the callback code is executed from within the I-Locked state (see System States) so you can only execute I-Class APIs from there (see API Names Suffixes).
This solution has the advantage to not require a dedicated thread and thus uses much less RAM but the periodic code must have a very short execution time or it would degrade the overall system response time.


Generated on Sun Nov 28 2010 14:09:56 for ChibiOS/RT by doxygen 1.7.1