Skip to end of metadata
Go to start of metadata

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 23 Next »

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

Dynamic Tick requires a programmable hardware timer which can be configured to count a specified number of ticks. A down-counting timer can be used, but we will assume an up-counter for the remainder of this document. The OS needs some way to read and write to the timer, so it defines a new API to do this: OS_DynTickSet() and OS_DynTickGet(). However, this API is somewhat unique in that it is not implemented by the kernel, but instead left to the BSP. This gives the BSP developer some flexibility in the choice of time source, provided that certain restrictions are followed.

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, for reasons which will be discussed later in this section:

  • 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).

There is one other addition to the API, OSTimeDynTick(), which must be used in place of OSTimeTick(). The main difference between the two is that the new function allows the ISR to process multiple ticks at once.

Dynamic Tick Model

The function shown above, OSTimeDynTick(), is only a small part of the dynamic tick API. There are many more details to cover, so we've decided to lay out the rest through a number of different cases. One of the details is fundamental to the remainder of the examples, so we state it here: the Dynamic Tick API 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.
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

One function in the dynamic tick API has been left out of the discussion until it was relevant: OS_DynTickGet(). OS_DynTickGet() allows the kernel to read the ticks counted towards the current request. For example, if a 50 tick timeout request is issued, OS_DynTickGet() would return 0 at the start of the request and 50 at the end of the request. It should never return a value greater than 50.

The simplest use for OS_DynTickGet() is to read the System Time. In periodic tick mode, the current system time was represented by a global variable, OSTickCtr. As its name suggests, it is a count of the number of ticks that the OS has processed since it started running. Dynamic Tick Mode throws a wrench into this because we now have ticks that have elapsed (i.e. been counted by the timer) but have not been processed by the ISR. To remedy this situation, OSTimeGet() reads the number of ticks in this in-between state by calling OS_DynTickGet(). The value it reads is added to OSTickCtr to give the correct system time.However, OS_DynTickGet() is not only used for reading the System Time; it's primary purpose is to maintain it. Internally, the system's tick counter is updated whenever we process the tick ISR.  If we look at the scenario outlined in Case 2 once again, we'll realize that the 10 ticks which elapsed before Task2 requested a delay were never added to our tick counter because overriding the first delay request meant that OSTickUpdate() was never called by the ISR to process those ticks. You can confirm this by counting the ticks reported by the ISR, which only add up to 40 when we should see 50. To ensure that the system time is properly maintained, the kernel uses OS_DynTickGet() to make up the difference whenever a request override scenario occurs.

There is one more case to consider, which is the culmination of our discussion surrounding OS_DynTickGet(). How does dynamic tick mode handle the situation when no tasks are waiting for a timeout (i.e. the tick list is empty)? It turns out that OS_DynTickSet() cleanly handles this edge case by setting aside argument 0, which had no use previously, for generating an indefinite timeout. However, this tells us nothing about how an indefinite timeout is actually handled.

One possibility would be to simply disable the timer until we get a new request. The problem there is that we would lose time-keeping altogether, so our tick counter would no longer reflect the actual number of ticks that have elapsed. What we actually need is for our timer to count to infinity, until we're ready to issue a new timeout request. Obviously, this solution cannot be realized on actual hardware, but once again we can provide a best-effort attempt to do so.This last case is interesting because it imposes a limit on the power efficiency of dynamic tick mode. If we have a perfectly idle system with the dynamic tick running, we will still be forced to wake up periodically. However, the wake up is much less frequent now than in the periodic tick case. Instead of waking up every tick, we only wake up each time the timer reaches its maximum tick count.

  • No labels