| .. _timers_v2: |
| |
| Timers |
| ###### |
| |
| A :dfn:`timer` is a kernel object that measures the passage of time |
| using the kernel's system clock. When a timer's specified time limit |
| is reached it can perform an application-defined action, |
| or it can simply record the expiration and wait for the application |
| to read its status. |
| |
| .. contents:: |
| :local: |
| :depth: 2 |
| |
| Concepts |
| ******** |
| |
| Any number of timers can be defined (limited only by available RAM). Each timer |
| is referenced by its memory address. |
| |
| A timer has the following key properties: |
| |
| * A :dfn:`duration` specifying the time interval before the timer |
| expires for the first time. This is a ``k_timeout_t`` value that |
| may be initialized via different units. |
| |
| * A :dfn:`period` specifying the time interval between all timer |
| expirations after the first one, also a ``k_timeout_t``. It must be |
| non-negative. A period of ``K_NO_WAIT`` (i.e. zero) or |
| ``K_FOREVER`` means that the timer is a one shot timer that stops |
| after a single expiration. (For example then, if a timer is started |
| with a duration of 200 and a period of 75, it will first expire |
| after 200ms and then every 75ms after that.) |
| |
| * An :dfn:`expiry function` that is executed each time the timer expires. |
| The function is executed by the system clock interrupt handler. |
| If no expiry function is required a ``NULL`` function can be specified. |
| |
| * A :dfn:`stop function` that is executed if the timer is stopped prematurely |
| while running. The function is executed by the thread that stops the timer. |
| If no stop function is required a ``NULL`` function can be specified. |
| |
| * A :dfn:`status` value that indicates how many times the timer has expired |
| since the status value was last read. |
| |
| A timer must be initialized before it can be used. This specifies its |
| expiry function and stop function values, sets the timer's status to zero, |
| and puts the timer into the **stopped** state. |
| |
| A timer is **started** by specifying a duration and a period. |
| The timer's status is reset to zero, then the timer enters |
| the **running** state and begins counting down towards expiry. |
| |
| Note that the timer's duration and period parameters specify |
| **minimum** delays that will elapse. Because of internal system timer |
| precision (and potentially runtime interactions like interrupt delay) |
| it is possible that more time may have passed as measured by reads |
| from the relevant system time APIs. But at least this much time is |
| guaranteed to have elapsed. |
| |
| When a running timer expires its status is incremented |
| and the timer executes its expiry function, if one exists; |
| If a thread is waiting on the timer, it is unblocked. |
| If the timer's period is zero the timer enters the stopped state; |
| otherwise the timer restarts with a new duration equal to its period. |
| |
| A running timer can be stopped in mid-countdown, if desired. |
| The timer's status is left unchanged, then the timer enters the stopped state |
| and executes its stop function, if one exists. |
| If a thread is waiting on the timer, it is unblocked. |
| Attempting to stop a non-running timer is permitted, |
| but has no effect on the timer since it is already stopped. |
| |
| A running timer can be restarted in mid-countdown, if desired. |
| The timer's status is reset to zero, then the timer begins counting down |
| using the new duration and period values specified by the caller. |
| If a thread is waiting on the timer, it continues waiting. |
| |
| A timer's status can be read directly at any time to determine how many times |
| the timer has expired since its status was last read. |
| Reading a timer's status resets its value to zero. |
| The amount of time remaining before the timer expires can also be read; |
| a value of zero indicates that the timer is stopped. |
| |
| A thread may read a timer's status indirectly by **synchronizing** |
| with the timer. This blocks the thread until the timer's status is non-zero |
| (indicating that it has expired at least once) or the timer is stopped; |
| if the timer status is already non-zero or the timer is already stopped |
| the thread continues without waiting. The synchronization operation |
| returns the timer's status and resets it to zero. |
| |
| .. note:: |
| Only a single user should examine the status of any given timer, |
| since reading the status (directly or indirectly) changes its value. |
| Similarly, only a single thread at a time should synchronize |
| with a given timer. ISRs are not permitted to synchronize with timers, |
| since ISRs are not allowed to block. |
| |
| Implementation |
| ************** |
| |
| Defining a Timer |
| ================ |
| |
| A timer is defined using a variable of type :c:struct:`k_timer`. |
| It must then be initialized by calling :c:func:`k_timer_init`. |
| |
| The following code defines and initializes a timer. |
| |
| .. code-block:: c |
| |
| struct k_timer my_timer; |
| extern void my_expiry_function(struct k_timer *timer_id); |
| |
| k_timer_init(&my_timer, my_expiry_function, NULL); |
| |
| Alternatively, a timer can be defined and initialized at compile time |
| by calling :c:macro:`K_TIMER_DEFINE`. |
| |
| The following code has the same effect as the code segment above. |
| |
| .. code-block:: c |
| |
| K_TIMER_DEFINE(my_timer, my_expiry_function, NULL); |
| |
| Using a Timer Expiry Function |
| ============================= |
| |
| The following code uses a timer to perform a non-trivial action on a periodic |
| basis. Since the required work cannot be done at interrupt level, |
| the timer's expiry function submits a work item to the |
| :ref:`system workqueue <workqueues_v2>`, whose thread performs the work. |
| |
| .. code-block:: c |
| |
| void my_work_handler(struct k_work *work) |
| { |
| /* do the processing that needs to be done periodically */ |
| ... |
| } |
| |
| K_WORK_DEFINE(my_work, my_work_handler); |
| |
| void my_timer_handler(struct k_timer *dummy) |
| { |
| k_work_submit(&my_work); |
| } |
| |
| K_TIMER_DEFINE(my_timer, my_timer_handler, NULL); |
| |
| ... |
| |
| /* start periodic timer that expires once every second */ |
| k_timer_start(&my_timer, K_SECONDS(1), K_SECONDS(1)); |
| |
| Reading Timer Status |
| ==================== |
| |
| The following code reads a timer's status directly to determine |
| if the timer has expired on not. |
| |
| .. code-block:: c |
| |
| K_TIMER_DEFINE(my_status_timer, NULL, NULL); |
| |
| ... |
| |
| /* start one shot timer that expires after 200 ms */ |
| k_timer_start(&my_status_timer, K_MSEC(200), K_NO_WAIT); |
| |
| /* do work */ |
| ... |
| |
| /* check timer status */ |
| if (k_timer_status_get(&my_status_timer) > 0) { |
| /* timer has expired */ |
| } else if (k_timer_remaining_get(&my_status_timer) == 0) { |
| /* timer was stopped (by someone else) before expiring */ |
| } else { |
| /* timer is still running */ |
| } |
| |
| Using Timer Status Synchronization |
| ================================== |
| |
| The following code performs timer status synchronization to allow a thread |
| to do useful work while ensuring that a pair of protocol operations |
| are separated by the specified time interval. |
| |
| .. code-block:: c |
| |
| K_TIMER_DEFINE(my_sync_timer, NULL, NULL); |
| |
| ... |
| |
| /* do first protocol operation */ |
| ... |
| |
| /* start one shot timer that expires after 500 ms */ |
| k_timer_start(&my_sync_timer, K_MSEC(500), K_NO_WAIT); |
| |
| /* do other work */ |
| ... |
| |
| /* ensure timer has expired (waiting for expiry, if necessary) */ |
| k_timer_status_sync(&my_sync_timer); |
| |
| /* do second protocol operation */ |
| ... |
| |
| .. note:: |
| If the thread had no other work to do it could simply sleep |
| between the two protocol operations, without using a timer. |
| |
| Suggested Uses |
| ************** |
| |
| Use a timer to initiate an asynchronous operation after a specified |
| amount of time. |
| |
| Use a timer to determine whether or not a specified amount of time has |
| elapsed. In particular, timers should be used when higher precision |
| and/or unit control is required than that afforded by the simpler |
| :c:func:`k_sleep` and :c:func:`k_usleep` calls. |
| |
| Use a timer to perform other work while carrying out operations |
| involving time limits. |
| |
| .. note:: |
| If a thread needs to measure the time required to perform an operation |
| it can read the :ref:`system clock or the hardware clock <kernel_timing>` |
| directly, rather than using a timer. |
| |
| Configuration Options |
| ********************* |
| |
| Related configuration options: |
| |
| * None |
| |
| API Reference |
| ************* |
| |
| .. doxygengroup:: timer_apis |
| :project: Zephyr |