Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Tickless OS

Default System Timer

By default, a NuttX configuration includes a periodic timer interrupt that drives all system timing. The timer is provided by architecture-specific code that calls into NuttX at a rate controlled by CONFIG_USEC_PER_TICK. The default value of CONFIG_USEC_PER_TICK is 10000 microseconds which corresponds to a timer interrupt rate of 100 Hz.

...

  • Overhead: Although the CPU usage of the system timer interrupt at 100Hz is really very low, it is still mostly wasted processing time. On most timer interrupts, there is really nothing that needs be done other than incrementing the counter.
  • Resolution: Resolution of all system timing is also determined by CONFIG_USEC_PER_TICK. So nothing can be timed with resolution finer than 10 milliseconds by default. If you want to increase this resolution, then you can reduce CONFIG_USEC_PER_TICK. However, then the system timer interrupts use more of the CPU bandwidth processing useless interrupts.
  • Power Usage: But the biggest issue is power usage. When the system is IDLE, it enters a light, low-power mode (for ARMs, this mode is entered with the wfi instruction for example). But each interrupt awakens the system from this low power mode. Therefore, higher rates of interrupts cause greater power consumption.

Tickless OS

The so-called Tickless OS provides one solution to issue. The basic concept here is that the periodic, timer interrupt is eliminated and replaced with a one-shot, interval timer. It becomes event driven instead of polled: The default system timer is a polled design. On each interrupt, the NuttX logic checks if it needs to do anything and, if so, it does it.

Using an interval timer, you can anticipate when the next interesting OS event will occur, program the interval time and wait for it to fire. When the interval time fires, then the scheduled activity is performed.

Platform Support

In order to use the Tickless OS, you must provide special support from the platform-specific code. Just as with the default system timer, the platform-specific code must provide the timer resources to support the OS behavior.

Currently these timer resources are only provided on a few platforms. You can see that implementation for the simulation in nuttx/arch/sim/src/up_tickless.c. There is another implementation for the Atmel SAMA5 at nuttx/arch/arm/src/sama5/sam_tickless.c. This Wiki will explain how you can provide the Tickless OS support for your platform.

Configuration Options

  • CONFIG_ARCH_HAVE_TICKLESS: If your platform provides support for the Tickless OS, then you should set this option in the Kconfig file for your board. Here is what the selection looks in the arch/Kconfig file for the simulated platform:

...

This value should never be less than the underlying resolution of the timer. Error may ensue.

System Interfaces

Implementation Notes

Notice that with the CONFIG_SCHED_TICKLESS option, an implementation might require two hardware timers: (1) An interval timer to satisfy the requirements for up_timer_start() and up_timer_cancel(), and a (2) a counter to handle the requirement of up_timer_gettime().

Since timers are a limited resource, the use of two timers could be an issue on some systems. The job could be done with a single timer if, for example, the single timer were kept in a free-running at all times. Some timer/counters have the capability to generate a compare interrupt when the timer matches a comparison value but also to continue counting without stopping. If your hardware supports such counters, one might used the CONFIG_SCHED_TICKLESS_ALARM option and be able to simply set the comparison count at the value of the free running timer PLUS the desired delay. Then you could have both with a single timer: An alarm and a free-running counter with the same timer!

Imported Intefaces

The interfaces that must be provided by the platform specified code are defined in include/nuttx/arch.h and summarized below.

up_timer_intialize()
Code Block
    void up_timer_initialize(void);
  • Description: Initializes all platform-specific timer facilities. This function is called early in the initialization sequence by up_intialize(). On return, the current up-time should be available from up_timer_gettime() and the interval timer is ready for use (but not actively timing).
  • Input Parameters: None
  • Returned Value: None
  • Assumptions: Called early in the initialization sequence before any special concurrency protections are required.
up_timer_gettime()
Code Block
    int up_timer_gettime(FAR struct timespec *ts);
  • Description: Return the elapsed time since power-up (or, more correctly, since up_timer_initialize() was called). This function is functionally equivalent to clock_gettime() for the clock ID CLOCK_MONOTONIC. This function provides the basis for reporting the current time and also is used to eliminate error build-up from small errors in interval time calculations.
  • Input Parameters: ts - Provides the location in which to return the up-time.
  • Returned Value: Zero (OK) is returned on success; a negated errno value is returned on any failure.
  • Assumptions: Called from the the normal tasking context. The implementation must provide whatever mutual exclusion is necessary for correct operation. This can include disabling interrupts in order to assure atomic register operations.
up_alarm_cancel()
Code Block
    int up_alarm_cancel(FAR struct timespec *ts);
  • Description: Cancel the alarm and return the time of cancellation of the alarm. These two steps need to be as nearly atomic as possible. sched_timer_expiration() will not be called unless the alarm is restarted with up_alarm_start(). If, as a race condition, the alarm has already expired when this function is called, then time returned is the current time. NOTE: This function is only required when CONFIG_SCHED_TICKLESS_ALARM is defined.
  • Input Parameters: ts -Location to return the expiration time. The current time should be returned if the timer is not active. ts may be NULL in which case the time is not returned
  • Returned Value: Zero (OK) is returned on success; a negated errno value is returned on any failure.
  • Assumptions: May be called from interrupt level handling or from the normal tasking level. interrupts may need to be disabled internally to assure non-reentrancy.
up_alarm_start()
Code Block
    int up_alarm_start(FAR const struct timespec *ts);
  • Description: Start the alarm. sched_timer_expiration() will be called at alarm expires (unless up_alarm_cancel() is called to stop the alarm. NOTE: This function is only required when CONFIG_SCHED_TICKLESS_ALARM is defined.
  • Input Parameters: ts - The time in the future at the alarm is expected to occur. When the alarm occurs the timer logic will call ched_timer_expiration() is called.
  • Returned Value: Zero (OK) is returned on success; a negated errno value is returned on any failure.
  • Assumptions: May be called from interrupt level handling or from the normal tasking level. Interrupts may need to be disabled internally to assure non-reentrancy.
up_timer_cancel()
Code Block
    int up_timer_cancel(FAR struct timespec *ts);
  • Description: Cancel the interval timer and return the time remaining on the timer. These two steps need to be as nearly atomic as possible. sched_timer_expiration() will not be called unless the timer is restarted with up_timer_start(). If, as a race condition, the timer has already expired when this function is called, then that pending interrupt must be cleared so that up_timer_start() and the remaining time of zero should be returned. NOTE: This function is only required when CONFIG_SCHED_TICKLESS_ALARM is not defined.
  • Input Parameters: ts - Location to return the remaining time. Zero should be returned if the timer is not active. ts may be NULL in which case the time remainging is not returned
  • Returned Value: Zero (OK) is returned on success; a negated errno value is returned on any failure.
  • Assumptions: May be called from interrupt level handling or from the normal tasking level. interrupts may need to be disabled internally to assure non-reentrancy.
up_timer_start()
Code Block
    int up_timer_start(FAR const struct timespec *ts);
  • Description: Start the interval timer. sched_timer_expiration() will be called at the completion of the timeout (unless up_timer_cancel() is called to stop the timing. NOTE: This function is only required when CONFIG_SCHED_TICKLESS_ALARM is not defined.
  • Input Parameters: ts - Provides the time interval until sched_timer_expiration() is called.
  • Returned Value: Zero (OK) is returned on success; a negated errno value is returned on any failure.
  • Assumptions: May be called from interrupt level handling or from the normal tasking level. Interrupts may need to be disabled internally to assure non-reentrancy.

Exported Interfaces

In addition, the following interface is provided by the RTOS for use by the platform specific code:

sched_alarm_expiration()
Code Block
    void sched_timer_expiration(FAR const timespec *tc);
  • Description: if CONFIG_SCHED_TICKLESS is defined, then this function is provided by the RTOS base code and called from platform-specific code when the alaram used to implemente the tick-less OS expires. NOTE: This function is only provided when CONFIG_SCHED_TICKLESS_ALARM is defined.
  • Input Parameters: ts - The time when the alarm expired.
  • Returned Value: None
  • Assumptions: Base code implementation assumes that this function is called from interrupt handling logic with interrupts disabled.
sched_timer_expiration()
Code Block
    void sched_timer_expiration(void);
  • Description: if CONFIG_SCHED_TICKLESS is defined, then this function is provided by the RTOS base code and called from platform-specific code when the interval timer used to implemente the tick-less OS expires. NOTE: This function is only provided when CONFIG_SCHED_TICKLESS_ALARM is not defined.
  • Input Parameters: None
  • Returned Value: None
  • Assumptions: Base code implementation assumes that this function is called from interrupt handling logic with interrupts disabled.

Issues

Let me describe an experience to illustrate some of the problems that you may run into:

...