=====================
System Time and Clock
=====================

Basic System Timer
==================

**System Timer** In most implementations, system time is provided
by a timer interrupt. That timer interrupt runs at rate determined
by ``CONFIG_USEC_PER_TICK`` (default 10000 microseconds or 100Hz.
If ``CONFIG_SCHED_TICKLESS`` is selected, the default is 100
microseconds). The timer generates an interrupt each
``CONFIG_USEC_PER_TICK`` microseconds and increments a counter
called ``g_system_ticks``. ``g_system_ticks`` then provides a
time-base for calculating *up-time* and elapsed time intervals in
units of ``CONFIG_USEC_PER_TICK``. The range of ``g_system_ticks``
is, by default, 32-bits. However, if the MCU supports type
``long long`` and ``CONFIG_SYSTEM_TIME16`` is selected, a 64-bit
system timer will be supported instead.

**System Timer Accuracy** On many system, the exact timer interval
specified by ``CONFIG_USEC_PER_TICK`` cannot be achieved due to
limitations in frequencies or in dividers. As a result, the time
interval specified by ``CONFIG_USEC_PER_TICK`` may only be
approximate and there may be small errors in the apparent
*up-time* time. These small errors, however, will accumulate over
time and after a long period of time may have an unacceptably
large error in the apparent *up-time* of the MCU.

If the timer tick period generated by the hardware is not exactly
``CONFIG_USEC_PER_TICK`` *and* if there you require accurate
up-time for the MCU, then there are measures that you can take:

-  Perhaps you can adjust ``CONFIG_USEC_PER_TICK`` to a different
   value so that an exactly ``CONFIG_USEC_PER_TICK`` can be
   realized.
-  Or you can use a technique known as *Delta-Sigma Modulation*.
   (Suggested by Uros Platise). Consider the example below.

**Delta-Sigma Modulation Example**. Consider this case: The system
timer is a count-up timer driven at 32.768KHz. There are dividers
that can be used, but a divider of one yields the highest
accuracy. This counter counts up until the count equals a match
value, then a timer interrupt is generated. The desire frequency
is 100Hz (``CONFIG_USEC_PER_TICK`` is 10000).

This exact frequency of 100Hz cannot be obtained in this case. In
order to obtain that exact frequency a match value of 327.68 would
have to be provided. The closest integer value is 328 but the
ideal match value is between 327 and 328. The closest value, 328,
would yield an actual timer frequency of 99.9Hz! That will may
cause significant timing errors in certain usages.

Use of Delta-Sigma Modulation can eliminate this error in the long
run. Consider this example implementation:

  #. Initially an accumulator is zero an the match value is
     programmed to 328:

     .. code-block:: c

      accumulator = 0;
      match = 328;

  #. On each timer interrupt, accumulator is updated with difference
     that, in this reflects, 100\* the error in interval that just
     passed. So on the first timer interrupt, the accumulator would
     be updated like:

     .. code-block:: c

        if (match == 328)
          {
            accumulator += 32; // 100*(328 - 327.68)
          }
        else
          {
            accumulator -= 68; // (100*(327 - 327.68)
          }

  #. And on that same timer interrupt a new match value would be
     programmed:

     .. code-block:: c

      if (accumulator < 0)
        {
          match = 328;
        }
      else
        {
          match = 327;
        }

In this way, the timer interval is controlled from
interrupt-to-interrupt to produce an average frequency of exactly
100Hz.

Hardware
========

To enable hardware module use the following configuration options:

``CONFIG_RTC``
   Enables general support for a hardware RTC. Specific
   architectures may require other specific settings.
``CONFIG_RTC_EXTERNAL``
   Most MCUs include RTC hardware built into the chip. Other RTCs,
   *external* MCUs, may be provided as separate chips typically
   interfacing with the MCU via a serial interface such as SPI or
   I2C. These external RTCs differ from the built-in RTCs in that
   they cannot be initialized until the operating system is fully
   booted and can support the required serial communications.
   ``CONFIG_RTC_EXTERNAL`` will configure the operating system so
   that it defers initialization of its time facilities.
``CONFIG_RTC_DATETIME``
   There are two general types of RTC: (1) A simple battery backed
   counter that keeps the time when power is down, and (2) A full
   date / time RTC the provides the date and time information,
   often in BCD format. If ``CONFIG_RTC_DATETIME`` is selected, it
   specifies this second kind of RTC. In this case, the RTC is
   used to "seed"" the normal NuttX timer and the NuttX system
   timer provides for higher resolution time.
``CONFIG_RTC_HIRES``
   If ``CONFIG_RTC_DATETIME`` not selected, then the simple,
   battery backed counter is used. There are two different
   implementations of such simple counters based on the time
   resolution of the counter: The typical RTC keeps time to
   resolution of 1 second, usually supporting a 32-bit ``time_t``
   value. In this case, the RTC is used to "seed" the normal NuttX
   timer and the NuttX timer provides for higher resolution time.
   If ``CONFIG_RTC_HIRES`` is enabled in the NuttX configuration,
   then the RTC provides higher resolution time and completely
   replaces the system timer for purpose of date and time.
``CONFIG_RTC_FREQUENCY``
   If ``CONFIG_RTC_HIRES`` is defined, then the frequency of the
   high resolution RTC must be provided. If ``CONFIG_RTC_HIRES``
   is not defined, ``CONFIG_RTC_FREQUENCY`` is assumed to be one.
``CONFIG_RTC_ALARM``
   Enable if the RTC hardware supports setting of an alarm. A
   callback function will be executed when the alarm goes off

which requires the following base functions to read and set time:

-  ``up_rtc_initialize()``. Initialize the built-in, MCU hardware
   RTC per the selected configuration. This function is called
   once very early in the OS initialization sequence. NOTE that
   initialization of external RTC hardware that depends on the
   availability of OS resources (such as SPI or I2C) must be
   deferred until the system has fully booted. Other, RTC-specific
   initialization functions are used in that case.
-  ``up_rtc_time()``. Get the current time in seconds. This is
   similar to the standard ``time()`` function. This interface is
   only required if the low-resolution RTC/counter hardware
   implementation selected. It is only used by the RTOS during
   initialization to set up the system time when ``CONFIG_RTC`` is
   set but neither ``CONFIG_RTC_HIRES`` nor
   ``CONFIG_RTC_DATETIME`` are set.
-  ``up_rtc_gettime()``. Get the current time from the high
   resolution RTC clock/counter. This interface is only supported
   by the high-resolution RTC/counter hardware implementation. It
   is used to replace the system timer (``g_system_ticks``).
-  ``up_rtc_settime()``. Set the RTC to the provided time. All RTC
   implementations must be able to set their time based on a
   standard timespec.

System Tick and Time
====================

The system tick is represented by ``g_system_ticks``.

Running at rate of system base timer, used for time-slicing, and
so forth.

If hardware RTC is present (``CONFIG_RTC``) and and
high-resolution timing is enabled (``CONFIG_RTC_HIRES``), then
after successful initialization variables are overridden by calls
to ``up_rtc_gettime()`` which is running continuously even in
power-down modes.

In the case of ``CONFIG_RTC_HIRES`` is set the ``g_system_ticks``
keeps counting at rate of a system timer, which however, is
disabled in power-down mode. By comparing this time and RTC
(actual time) one may determine the actual system active time. To
retrieve that variable use:

Tickless OS
===========

**Default System Timer**. By default, a NuttX configuration uses 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.

On each timer interrupt, NuttX does these things:

-  Increments a counter. This counter is the system time and has a
   resolution of ``CONFIG_USEC_PER_TICK`` microseconds.
-  Checks if it is time to perform time-slice operations on tasks
   that have select round-robin scheduling.
-  Checks for expiration of timed events.

What is wrong with this default system timer? Nothing really. It
is reliable and uses only a small fraction of the CPU band width.
But we can do better. Some limitations of default system timer
are, in increasing order of importance:

-  **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 to 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. To
   increase this resolution, ``CONFIG_USEC_PER_TICK`` can be
   reduced. 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`` or ``wfe`` instructions
   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 this 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, one 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.

Tickless Platform Support
-------------------------

In order to use the Tickless OS, one 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. An example implementation is for
the simulation is at ``nuttx/arch/sim/src/up_tickless.c``. There
is another example for the Atmel SAMA5 at
``nuttx/arch/arm/src/sama5/sam_tickless.c``. These paragraphs will
explain how to provide the Tickless OS support to any platform.

Tickless Configuration Options
------------------------------

-  ``CONFIG_ARCH_HAVE_TICKLESS``: If the platform provides
   support for the *Tickless OS*, then this setting should be
   selected in the ``Kconfig`` file for the architecture. Here is
   what the selection looks in the ``arch/Kconfig`` file for the
   simulated platform:

   .. code-block:: console
 
     config ARCH_SIM
        bool "Simulation"
        select ARCH_HAVE_TICKLESS
        ---help---
                Linux/Cygwin user-mode simulation.

   When the simulation platform is selected,
   ``ARCH_HAVE_TICKLESS`` is automatically selected, informing the
   configuration system that *Tickless OS* options can be
   selected.

-  ``CONFIG_SCHED_TICKLESS``: If ``CONFIG_ARCH_HAVE_TICKLESS`` is
   selected, then you will be able to use this option to enable the
   *Tickless OS* features in NuttX.

-  ``CONFIG_SCHED_TICKLESS_ALARM``: The tickless option can be
   supported either via a simple interval timer (plus elapsed
   time) or via an alarm. The interval timer allows programming
   events to occur after an interval. With the alarm, you can set
   a time in the future and get an event when that alarm goes off.
   This option selects the use of an alarm.

   The advantage of an alarm is that it avoids some small timing
   errors; the advantage of the use of the interval timer is that
   the hardware requirement may be simpler.

-  ``CONFIG_USEC_PER_TICK``: This option is not unique to
   *Tickless OS* operation, but changes its relevance when the
   *Tickless OS* is selected. In the default configuration, where
   system time is provided by a periodic timer interrupt, the
   default system timer is configured for 100Hz, that is,
   ``CONFIG_USEC_PER_TICK=10000``. If ``CONFIG_SCHED_TICKLESS`` is
   selected, then there are no system timer interrupts. In this
   case, ``CONFIG_USEC_PER_TICK`` does not control any timer
   rates. Rather, it only determines the resolution of time
   reported by ``clock_systime_ticks()`` and the resolution of
   times that can be set for certain delays including watchdog
   timers and delayed work.

   In this case there is still a trade-off: It is better to have
   the ``CONFIG_USEC_PER_TICK`` as low as possible for higher
   timing resolution. However, the time is currently held in
   ``unsigned int``. On some systems, this may be 16-bits in width
   but on most contemporary systems it will be 32-bits. In either
   case, smaller values of ``CONFIG_USEC_PER_TICK`` will reduce
   the range of values that delays that can be represented. So the
   trade-off is between range and resolution (you could also
   modify the code to use a 64-bit value if you really want both).

   The default, 100 microseconds, will provide for a range of
   delays up to 120 hours.

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

Tickless Imported Interfaces
----------------------------

The interfaces that must be provided by the platform specified
code are defined in ``include/nuttx/arch.h``, listed below, and
summarized in the following paragraphs:

  - ``<arch>_timer_initialize()`` Initializes
    the timer facilities. Called early in the initialization
    sequence (by ``up_initialize()``).
  - ``up_timer_gettime()``: Returns the
    current time from the platform specific time source.

The tickless option can be supported either via a simple interval
timer (plus elapsed time) or via an alarm. The interval timer
allows programming events to occur after an interval. With the
alarm, you can set a time in\* the future and get an event when
that alarm goes off.

If ``CONFIG_SCHED_TICKLESS_ALARM`` is defined, then the platform
code must provide the following:

-  ``up_alarm_cancel()``: Cancels the alarm.
-  ``up_alarm_start()``: Enables (or
   re-enables) the alarm.

If ``CONFIG_SCHED_TICKLESS_ALARM`` is *not*\ defined, then the
platform code must provide the following verify similar functions:

-  ``up_timer_cancel()``: Cancels the
   interval timer.
-  ``up_timer_start()``: Starts (or re-starts)
   the interval timer.

Note that a platform-specific implementation would probably require two
hardware timers: (1) A interval timer to satisfy the requirements of
``up_timer_start()`` and ``up_timer_cancel()``, and (2) a counter to
handle the requirement of ``up_timer_gettime()``. Ideally, both timers
would run at the rate determined by ``CONFIG_USEC_PER_TICK`` (and
certainly never slower than that rate).

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 mode 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 use
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!

In addition to these imported interfaces, the RTOS will export the
following interfaces for use by the platform-specific interval
timer implementation:

- ``nxsched_alarm_expiration()``: called by the platform-specific logic when the alarm expires.
- ``nxsched_timer_expiration()``: called by the platform-specific logic when the interval time expires.

.. c:function:: void archname_timer_initialize(void)

  Initializes all platform-specific timer facilities. This function is
  called early in the initialization sequence by up_initialize().
  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).
  The naming will depend on the architecture so for STM32 ``archname`` will
  be ``stm32``.

  :return: Zero (OK) on success; a negated errno value on failure.

  **Assumptions**: Called early in the initialization sequence before
  any special concurrency protections are required.

.. c:function:: int up_timer_gettime(FAR struct timespec *ts)

  Return the elapsed time since power-up (or, more correctly, since
  *<arch>*\ ``_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.

  :param ts: Provides the location in which to return the up-time..

  :return: Zero (OK) on success; a negated errno value on failure.

  **Assumptions**: Called from 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.

.. c:function:: int up_alarm_cancel(FAR struct timespec *ts)

  Cancel the alarm and return the time of cancellation of the alarm.
  These two steps need to be as nearly atomic as possible.
  ``nxsched_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.

  :param 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

  :return: Zero (OK) on success; a negated errno value on 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.

.. c:function:: int up_alarm_start(FAR const struct timespec *ts)

  Start the alarm. ``nxsched_timer_expiration()`` will be called
  when the alarm occurs (unless ``up_alarm_cancel`` is called to
  stop it).

  :param ts: The time in the future at the alarm is expected to
    occur. When the alarm occurs the timer logic will call
    ``nxsched_timer_expiration()``.

  :return: Zero (OK) on success; a negated errno value on 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.

.. c:function:: int up_timer_cancel(FAR struct timespec *ts)

Cancel the interval timer and return the time remaining on the
timer. These two steps need to be as nearly atomic as possible.
``nxsched_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
``nxsched_timer_expiration()`` is not called spuriously and the
remaining time of zero should be returned.

:param ts: Location to return the remaining time. Zero should be
  returned if the timer is not active.

:return: Zero (OK) on success; a negated errno value on 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.

.. c:function:: int up_timer_start(FAR const struct timespec *ts)

Start the interval timer. ``nxsched_timer_expiration()`` will be
called at the completion of the timeout (unless
``up_timer_cancel()`` is called to stop the timing).

:param ts: Provides the time interval until
  ``nxsched_timer_expiration()`` is called.

:return: Zero (OK) on success; a negated errno value on 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.

Watchdog Timer Interfaces
=========================

NuttX provides a general watchdog timer facility. This facility
allows the NuttX user to specify a watchdog timer function that
will run after a specified delay. The watchdog timer function will
run in the context of the timer interrupt handler. Because of
this, a limited number of NuttX interfaces are available to he
watchdog timer function. However, the watchdog timer function may
use ``mq_send()``, ``sigqueue()``, or ``kill()`` to communicate
with NuttX tasks.

- :c:func:`wd_start`
- :c:func:`wd_cancel`
- :c:func:`wd_gettime`
- Watchdog Timer Callback

.. c:function:: int wd_start(FAR struct wdog_s *wdog, int delay, \
                 wdentry_t wdentry, wdparm_t arg)

  This function adds a watchdog to the timer queue.
  The specified watchdog function will be called from the interrupt
  level after the specified number of ticks has elapsed. Watchdog
  timers may be started from the interrupt level.

  Watchdog times execute in the context of the timer interrupt
  handler.

  Watchdog timers execute only once.

  To replace either the timeout delay or the function to be
  executed, call wd_start again with the same wdog; only the most
  recent wd_start() on a given watchdog ID has any effect.

  :param wdog: Watchdog ID
  :param delay: Delay count in clock ticks
  :param wdentry: Function to call on timeout
  :param arg: The parameter to pass to wdentry.

  **NOTE**: The parameter must be of type ``wdparm_t``.

  :return: Zero (``OK``) is returned on success; a negated ``errno`` value
    is return to indicate the nature of any failure.

  **Assumptions/Limitations:** The watchdog routine runs in the
  context of the timer interrupt handler and is subject to all ISR
  restrictions.

  **POSIX Compatibility:** This is a NON-POSIX interface. VxWorks
  provides the following comparable interface:

  .. code-block:: c

    STATUS wdStart (WDOG_ID wdog, int delay, FUNCPTR wdentry, int parameter);

  Differences from the VxWorks interface include:

  -  The present implementation supports multiple parameters passed
     to wdentry; VxWorks supports only a single parameter. The
     maximum number of parameters is determined by

.. c:function:: int wd_cancel(FAR struct wdog_s *wdog)

  This function cancels a currently running
  watchdog timer. Watchdog timers may be canceled from the interrupt
  level.

  :param wdog: ID of the watchdog to cancel.

  :return: ``OK`` or ``ERROR``

  **POSIX Compatibility:** This is a NON-POSIX interface. VxWorks
  provides the following comparable interface:

  .. code-block:: c

    STATUS wdCancel (WDOG_ID wdog);

.. c:function:: int wd_gettime(FAR struct wdog_s *wdog)

  Returns the time remaining before
  the specified watchdog expires.

  :param wdog: Identifies the watchdog that the request is for.

  :return: The time in system ticks remaining until the
    watchdog time expires. Zero means either that wdog is not valid or
    that the wdog has already expired.

.. c:type:: void (*wdentry_t)(wdparm_t arg)

  **Watchdog Timer Callback**: when a watchdog expires,
  the callback function with this type is
  called.

  The argument is passed as scalar ``wdparm_t`` values. For
  systems where the ``sizeof(pointer) < sizeof(uint32_t)``, the
  following union defines the alignment of the pointer within the
  ``uint32_t``. For example, the SDCC MCS51 general pointer is
  24-bits, but ``uint32_t`` is 32-bits (of course).

  We always have ``sizeof(pointer) <= sizeof(uintptr_t)`` by
  definition.

  .. code-block:: c

    union wdparm_u
    {
      FAR void     *pvarg; /* The size one generic point */
      uint32_t      dwarg; /* Big enough for a 32-bit value in any case */
      uintptr_t     uiarg; /* sizeof(uintptr_t) >= sizeof(pointer) */
    };

    #if UINTPTR_MAX >= UINT32_MAX
    typedef uintptr_t wdparm_t;
    #else
    typedef uint32_t  wdparm_t;
    #endif