2020-07-21 00:18:26 +02:00
|
|
|
=====================
|
|
|
|
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_timer``. ``g_system_timer`` 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_timer``
|
|
|
|
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:
|
2020-10-18 18:48:44 +02:00
|
|
|
|
2020-07-21 00:18:26 +02:00
|
|
|
.. code-block:: c
|
2020-10-18 18:48:44 +02:00
|
|
|
|
2020-07-21 00:18:26 +02:00
|
|
|
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:
|
2020-10-18 18:48:44 +02:00
|
|
|
|
2020-07-21 00:18:26 +02:00
|
|
|
.. code-block:: c
|
2020-10-18 18:48:44 +02:00
|
|
|
|
2020-07-21 00:18:26 +02:00
|
|
|
if (match == 328)
|
|
|
|
{
|
|
|
|
accumulator += 32; // 100*(328 - 327.68)
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
accumulator -= 68; // (100*(327 - 327.68)
|
2020-10-18 18:48:44 +02:00
|
|
|
}
|
2020-07-21 00:18:26 +02:00
|
|
|
|
|
|
|
#. And on that same timer interrupt a new match value would be
|
|
|
|
programmed:
|
2020-10-18 18:48:44 +02:00
|
|
|
|
2020-07-21 00:18:26 +02:00
|
|
|
.. code-block:: c
|
2020-10-18 18:48:44 +02:00
|
|
|
|
2020-07-21 00:18:26 +02:00
|
|
|
if (accumulator < 0)
|
|
|
|
{
|
|
|
|
match = 328;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
match = 327;
|
|
|
|
}
|
2020-10-18 18:48:44 +02:00
|
|
|
|
2020-07-21 00:18:26 +02:00
|
|
|
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:
|
|
|
|
|
2020-10-18 18:48:44 +02:00
|
|
|
``CONFIG_RTC``
|
2020-07-21 00:18:26 +02:00
|
|
|
Enables general support for a hardware RTC. Specific
|
|
|
|
architectures may require other specific settings.
|
2020-10-18 18:48:44 +02:00
|
|
|
``CONFIG_RTC_EXTERNAL``
|
2020-07-21 00:18:26 +02:00
|
|
|
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.
|
2020-10-18 18:48:44 +02:00
|
|
|
``CONFIG_RTC_DATETIME``
|
2020-07-21 00:18:26 +02:00
|
|
|
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.
|
2020-10-18 18:48:44 +02:00
|
|
|
``CONFIG_RTC_HIRES``
|
2020-07-21 00:18:26 +02:00
|
|
|
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.
|
2020-10-18 18:48:44 +02:00
|
|
|
``CONFIG_RTC_FREQUENCY``
|
2020-07-21 00:18:26 +02:00
|
|
|
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.
|
2020-10-18 18:48:44 +02:00
|
|
|
``CONFIG_RTC_ALARM``
|
2020-07-21 00:18:26 +02:00
|
|
|
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_tick``).
|
|
|
|
- ``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_timer``.
|
|
|
|
|
|
|
|
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_timer``
|
|
|
|
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. One 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 that be time
|
|
|
|
with resolution finer than 10 milliseconds be default. To
|
|
|
|
increase this resolution, ``CONFIG_USEC_PER_TICK`` an 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 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 board. Here is what
|
|
|
|
the selection looks in the ``arch/Kconfig`` file for the
|
|
|
|
simulated platform:
|
|
|
|
|
|
|
|
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 it will 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 less.
|
|
|
|
|
|
|
|
- ``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 configure the timer for 100Hz or
|
|
|
|
``CONFIG_USEC_PER_TICK=10000``. If ``CONFIG_SCHED_TICKLESS`` is
|
|
|
|
selected, then there are no system timer interrupt. 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 a (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 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!
|
|
|
|
|
|
|
|
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
|
2020-10-18 18:48:44 +02:00
|
|
|
be ``stm32``.
|
2020-07-21 00:18:26 +02:00
|
|
|
|
2020-10-18 18:48:44 +02:00
|
|
|
:return: Zero (OK) on success; a negated errno value on failure.
|
2020-07-21 00:18:26 +02:00
|
|
|
|
|
|
|
**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..
|
|
|
|
|
2020-10-18 18:48:44 +02:00
|
|
|
:return: Zero (OK) on success; a negated errno value on failure.
|
2020-07-21 00:18:26 +02:00
|
|
|
|
|
|
|
**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
|
2020-10-18 18:48:44 +02:00
|
|
|
order to assure atomic register operations.
|
2020-07-21 00:18:26 +02:00
|
|
|
|
|
|
|
.. 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
|
|
|
|
|
2020-10-18 18:48:44 +02:00
|
|
|
:return: Zero (OK) on success; a negated errno value on failure.
|
2020-07-21 00:18:26 +02:00
|
|
|
|
|
|
|
**Assumptions**: May be called from interrupt level handling or
|
|
|
|
from the normal tasking level. interrupts may need to be disabled
|
2020-10-18 18:48:44 +02:00
|
|
|
internally to assure non-reentrancy.
|
2020-07-21 00:18:26 +02:00
|
|
|
|
|
|
|
.. 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()``.
|
|
|
|
|
2020-10-18 18:48:44 +02:00
|
|
|
:return: Zero (OK) on success; a negated errno value on failure.
|
2020-07-21 00:18:26 +02:00
|
|
|
|
|
|
|
**Assumptions**: May be called from interrupt level handling or
|
|
|
|
from the normal tasking level. Interrupts may need to be
|
2020-10-18 18:48:44 +02:00
|
|
|
disabled internally to assure non-reentrancy.
|
2020-07-21 00:18:26 +02:00
|
|
|
|
|
|
|
.. 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.
|
|
|
|
|
2020-10-18 18:48:44 +02:00
|
|
|
:return: Zero (OK) on success; a negated errno value on failure.
|
2020-07-21 00:18:26 +02:00
|
|
|
|
|
|
|
**Assumptions**: May be called from interrupt level handling or
|
2020-10-18 18:48:44 +02:00
|
|
|
from the normal tasking level. interrupts may need to be
|
|
|
|
disabled internally to assure non-reentrancy.
|
2020-07-21 00:18:26 +02:00
|
|
|
|
|
|
|
.. 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.
|
|
|
|
|
2020-10-18 18:48:44 +02:00
|
|
|
:return: Zero (OK) on success; a negated errno value on failure.
|
2020-07-21 00:18:26 +02:00
|
|
|
|
|
|
|
**Assumptions**: May be called from interrupt level handling
|
|
|
|
or from the normal tasking level. Interrupts may need to be
|
2020-10-18 18:48:44 +02:00
|
|
|
disabled internally to assure non-reentrancy.
|
2020-07-21 00:18:26 +02:00
|
|
|
|
|
|
|
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
|
|
|
|
|
2020-08-14 22:25:53 +02:00
|
|
|
.. c:function:: int wd_start(FAR struct wdog_s *wdog, int delay, \
|
|
|
|
wdentry_t wdentry, wdparm_t arg)
|
2020-07-21 00:18:26 +02:00
|
|
|
|
|
|
|
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
|
2020-08-14 22:25:53 +02:00
|
|
|
:param arg: The parameter to pass to wdentry.
|
2020-07-21 00:18:26 +02:00
|
|
|
|
2020-08-14 22:25:53 +02:00
|
|
|
**NOTE**: The parameter must be of type ``wdparm_t``.
|
2020-07-21 00:18:26 +02:00
|
|
|
|
|
|
|
: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
|
|
|
|
|
2020-08-14 22:25:53 +02:00
|
|
|
.. c:function:: int wd_cancel(FAR struct wdog_s *wdog)
|
2020-07-21 00:18:26 +02:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
2020-08-14 22:25:53 +02:00
|
|
|
.. c:function:: int wd_gettime(FAR struct wdog_s *wdog)
|
2020-07-21 00:18:26 +02:00
|
|
|
|
|
|
|
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.
|
|
|
|
|
2020-10-18 18:48:44 +02:00
|
|
|
.. c:type:: void (*wdentry_t)(wdparm_t arg)
|
2020-07-21 00:18:26 +02:00
|
|
|
|
|
|
|
**Watchdog Timer Callback**: when a watchdog expires,
|
|
|
|
the callback function with this type is
|
2020-08-14 22:25:53 +02:00
|
|
|
called.
|
2020-10-18 18:48:44 +02:00
|
|
|
|
2020-08-14 22:25:53 +02:00
|
|
|
The argument is passed as scalar ``wdparm_t`` values. For
|
2020-07-21 00:18:26 +02:00
|
|
|
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).
|
2020-10-18 18:48:44 +02:00
|
|
|
|
2020-07-21 00:18:26 +02:00
|
|
|
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
|