/* ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010 Giovanni Di Sirio. This file is part of ChibiOS/RT. ChibiOS/RT is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. ChibiOS/RT is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /** * @page article_timing 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: * @code msg_t my_thread(void *param) { while (TRUE) { do_something(); chThdSleepMilliseconds(1000); // Fixed interval } } * @endcode * This example works well assuming that the @p do_something() execution time * is well below the system tick period and that @p my_thread() is not * preempted by other threads that could insert long intervals.
* If the above conditions are not satisfied you may have @p 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: * @code msg_t my_thread(void *param) { systick_t time = chTimeNow(); // T0 while (TRUE) { time += MS2ST(1000); // Next deadline do_something(); chThdSleepUntil(time); } } * @endcode * Using this code @p 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 @p do_something() execution * time must not exceed the deadline or the thread would stay sleeping into * @p 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. * @code 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(); ... } * @endcode * Note that the callback code is executed from within the I-Locked state (see * @ref system_states) so you can only execute I-Class APIs from there (see * @ref api_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. */