Dynamic Tick Mode is a power-saving feature that was first introduced in μC/OS-III V3.05.00 and later revised in µC/OS-III V3.07.00. It is a compromise between the approaches outlined in the sections on Tickless Mode and Periodic Tick Mode in that it gives low power applications the option to utilize timing services, without the drawback of waking the system up periodically.
Benefits
- The full set of time services is available for use.
- Power consumption is reduced by allowing the system to stay asleep through idle periods.
Implications
- Support for this mode is more involved than for Periodic Tick Mode.
- Round-robin scheduling cannot be used. A build error will be generated if it is enabled.
System Behavior
Compared to Periodic Tick Mode, the system behavior changes drastically while using dynamic tick. It more closely resembles an application using tickless mode with a hardware timer, as was shown in that section. The major difference between the two cases is that dynamic tick operates alongside the kernel's timing API. For code making use of those APIs, there should be no difference between a properly-implemented Dynamic Tick BSP and the simpler Periodic Tick BSP.
Dynamic Tick
Requirements
Dynamic Tick requires a programmable hardware timer. A down-counting timer can be used, but we will assume an up-counter for the remainder of this document.
The timer must have the following characteristics:
- A programmable ceiling value which:
- Generates an interrupt on match
- Sets a status bit on match
- A counter that can be read while the timer is running
- A frequency that is an integer multiple of the OS Tick rate
For an optimal implementation of Dynamic Tick, the following constraints should be added:
- A timer frequency which matches the OS Tick frequency.
- A register width with matches the width of the OS_TICK type (32-bit by default).
Dynamic Tick Model
The details of dynamic tick mode will be laid out through a number of different cases. An important detail to keep in mind is that the Dynamic Tick Service is always invoked either with interrupts disabled or from interrupt context. This prevents race conditions on the kernel's data structures and the hardware timer.
Case 1 - Requesting a Timeout
Dynamic tick is a best-effort service which fulfills timeout requests from the kernel. The service can only handle one request at any given time, so the kernel must ensure that the current request is valid for the nearest task delay or pend timeout.
Case 2 - Overriding a Previous Request
There are situations where the previous request must be overridden before it completes. For example, assume Task1 delays for 50 ticks, then Task2 runs for 10 ticks and delays for 20 ticks. This situation is illustrated below.Up until this point, we've been ignoring one of the services provided by the dynamic tick API:
OS_DynTickGet()
. The reason it was ignored is that this function's importance becomes more evident once we delve into implementation details. The purpose of OS_DynTickGet()
is to tell the kernel how many of the ticks from our current request have been counted so far.
One final note on this case: there are situations where an override is required because we've removed a task from the tick list prematurely. This usually happens when a task pending with timeout receives the object before time is up, but it may also be due to a PendAbort or call to OSTimeDlyResume(). In any case, the situation is handled in a similar fashion. If, after the task is removed, the current timeout is too short the kernel will override it with a longer timeout request.
Case 3 - Indefinite Timeouts
When no tasks are waiting for a timeout (i.e. the tick list is empty), we don't know when the next timeout event should be generated. We need some way to postpone timeout events until a task has requested a definite timeout. The kernel handles this case by sending an indefinite timeout request to the Dynamic Tick Service; this is accomplished by passing 0 to OS_DynTickSet()
. Since it is impossible for a real timer to count indefinitely, there will be an limit to the length of the "indefinite" timeout. The BSP handles this by programming the timer to count as many ticks as it is able. In this case, the kernel will continue to issue indefinite timeout requests until a task is added to the tick list.
The ISR only needs to worry about reporting the number of ticks elapsed. However,
Dynamic Tick Control Flow
Dynamic tick is most easily understood as a best-effort service which fulfills timeout requests from the kernel. The service can only handle one request at any given time, so the kernel must ensure that the current request is valid for the nearest task delay or pend timeout. For simplicity, let us assume that we have two tasks in our system which are delayed; T1 should wake up in N ticks and T2 should wake up in N+1 ticks.
Description
Dynamic Tick Mode is a power-saving feature that was first introduced in μC/OS-III V3.05.00 and later revised in µC/OS-III V3.07.00. It is a compromise between the approaches outlined in the sections on Tickless Mode and Periodic Tick Mode in that it gives low power applications the option to utilize timing services, without the drawback of waking the system up periodically.
Benefits
- The full set of time services is available for use.
- Power consumption is reduced by allowing the system to stay asleep through idle periods.
Implications
- Support for this mode is more involved than for Periodic Tick Mode.
- Round-robin scheduling cannot be used. A build error will be generated if it is enabled.
System Behavior
Compared to Periodic Tick Mode, the system behavior changes drastically while using dynamic tick. It more closely resembles an application using tickless mode with a hardware timer, as was shown in that section. The major difference between the two cases is that dynamic tick operates alongside the kernel's timing API. For code making use of those APIs, there should be no difference between a properly-implemented Dynamic Tick BSP and the simpler Periodic Tick BSP.
Dynamic Tick
Requirements
Dynamic Tick requires a programmable hardware timer. A down-counting timer can be used, but we will assume an up-counter for the remainder of this document.
The timer must have the following characteristics:
- A programmable ceiling value which:
- Generates an interrupt on match
- Sets a status bit on match
- A counter that can be read while the timer is running
- A frequency that is an integer multiple of the OS Tick rate
For an optimal implementation of Dynamic Tick, the following constraints should be added:
- A timer frequency which matches the OS Tick frequency.
- A register width with matches the width of the OS_TICK type (32-bit by default).
Dynamic Tick Model
The details of dynamic tick mode will be laid out through a number of different cases. An important detail to keep in mind is that the Dynamic Tick Service is always invoked either with interrupts disabled or from interrupt context. This prevents race conditions on the kernel's data structures and the hardware timer.
Case 1 - Requesting a Timeout
Dynamic tick is a best-effort service which fulfills timeout requests from the kernel. The service can only handle one request at any given time, so the kernel must ensure that the current request is valid for the nearest task delay or pend timeout.
Case 2 - Overriding the Current Request
There are situations where the current request must be overridden before it completes. For example, assume Task1 delays for 50 ticks, then Task2 runs for 10 ticks and delays for 20 ticks. This situation is illustrated below.Up until this point, we've ignored one of the services provided by the dynamic tick API:
OS_DynTickGet()
. The reason is that this function's importance only becomes evident once we start exploring the implementation details. The purpose of it is to
One final note on this case: there are situations where an override is required because we've removed a task from the tick list prematurely. This usually happens when a task pending with timeout receives the object before time is up, but it may also be due to a PendAbort or call to OSTimeDlyResume(). In any case, the situation is handled in a similar fashion. If, after the task is removed, the current timeout is too short the kernel will override it with a longer timeout request.
Case 3 - Indefinite Timeouts
When no tasks are waiting for a timeout (i.e. the tick list is empty), we don't know when the next timeout event should be generated. We need some way to postpone timeout events until a task has requested a definite timeout. The kernel handles this case by sending an indefinite timeout request to the Dynamic Tick Service; this is accomplished by passing 0 to OS_DynTickSet()
. Since it is impossible for a real timer to count indefinitely, there will be an limit to the length of the "indefinite" timeout. The BSP handles this by programming the timer to count as many ticks as it is able. In this case, the kernel will continue to issue indefinite timeout requests until a task is added to the tick list.
The ISR only needs to worry about reporting the number of ticks elapsed. However,
Dynamic Tick Control Flow
Dynamic tick is most easily understood as a best-effort service which fulfills timeout requests from the kernel. The service can only handle one request at any given time, so the kernel must ensure that the current request is valid for the nearest task delay or pend timeout. For simplicity, let us assume that we have two tasks in our system which are delayed; T1 should wake up in N ticks and T2 should wake up in N+1 ticks.