unified/doc: Update timing section of Kernel Primer
Revises documentation for the kernel clocks to align it
with the actual behavior of the unified kernel.
Revises documentation for the kernel timer object type
to provide users with a more compact and intuitive API
that supports (directly or indirectly) the capabilities
of the now defunct microkernel timer and nanokernel
timer object types.
Note: A separate commit will be used to implement the
revised timer API described here.
Change-Id: Ifa4306c76e1c3e2aab1c0b55031df4179ac2a6b9
Signed-off-by: Allan Stephens <allan.stephens@windriver.com>
diff --git a/doc/kernel_v2/timing/clocks.rst b/doc/kernel_v2/timing/clocks.rst
index 7b2f907..4ddf5e1 100644
--- a/doc/kernel_v2/timing/clocks.rst
+++ b/doc/kernel_v2/timing/clocks.rst
@@ -3,86 +3,112 @@
Kernel Clocks
#############
+The kernel's clocks are the foundation for all of its time-based services.
+
+.. contents::
+ :local:
+ :depth: 2
+
Concepts
********
The kernel supports two distinct clocks.
-* A 64-bit **system clock**, which is the foundation for the kernel's
- time-based services. This clock is a counter measured in **ticks**,
- and increments at a frequency determined by the application.
+* The 32-bit **hardware clock** is a high precision counter that tracks time
+ in unspecified units called **cycles**. The duration of a cycle is determined
+ by the board hardware used by the kernel, and is typically measured
+ in nanoseconds.
- The kernel allows this clock to be accessed directly by reading
- the timer. It can also be accessed indirectly by using a kernel
- timer or timeout capability.
-
-* A 32-bit **hardware clock**, which is used as the source of the ticks
- for the system clock. This clock is a counter measured in unspecified
- units (called **cycles**), and increments at a frequency determined by
- the hardware.
-
- The kernel allows this clock to be accessed directly by reading
- the timer.
+* The 64-bit **system clock** is a counter that tracks the number of
+ **ticks** that have elapsed since the kernel was initialized. The duration
+ of a tick is is configurable, and typically ranges from 1 millisecond to
+ 100 milliseconds.
The kernel also provides a number of variables that can be used
to convert the time units used by the clocks into standard time units
(e.g. seconds, milliseconds, nanoseconds, etc), and to convert between
the two types of clock time units.
-Suggested Use
-*************
+The system clock is used by most of the kernel's time-based services, including
+kernel timer objects and the timeouts supported by other kernel object types.
+For convenience, the kernel's APIs allow time durations to be specified
+in milliseconds, and automatically converts them to the corresponding
+number of ticks.
-Use the system clock for time-based processing that does not require
-high precision, such as implementing time limits or time delays.
+The hardware clock can be used to measure time with higher precision than
+that provided by kernel services based on the system clock.
-Use the hardware clock for time-based processing that requires higher
-precision than the system clock can provide, such as fine-grained
-time measurements.
+.. _clock_limitations:
+
+Clock Limitations
+=================
+
+The system clock's tick count is derived from the hardware clock's cycle
+count. The kernel determines how many clock cycles correspond to the desired
+tick frequency, then programs the hardware clock to generate an interrupt
+after that many cycles; each interrupt corresponds to a single tick.
.. note::
- The high frequency of the hardware clock, combined with its 32-bit size,
- means that counter rollover must be taken into account when taking
- high-precision measurements over an extended period of time.
+ Configuring a smaller tick duration permits finer-grained timing,
+ but also increases the amount of work the kernel has to do to process
+ tick interrupts since they occur more frequently. Setting the tick
+ duration to zero disables *both* kernel clocks, as well as their
+ associated services.
-Configuration
-*************
+Any millisecond-based time interval specified using a kernel API
+represents the **minimum** delay that will occur,
+and may actually take longer than the amount of time requested.
-Use the :option:`CONFIG_SYS_CLOCK_TICKS_PER_SEC` configuration option
-to specify how many ticks occur every second. Setting this value
-to zero disables all system clock and hardware clock capabilities.
+For example, specifying a timeout delay of 100 ms when attempting to take
+a semaphore means that the kernel will never terminate the operation
+and report failure before at least 100 ms have elapsed. However,
+it is possible that the operation may take longer than 100 ms to complete,
+and may either complete successfully during the additional time
+or fail at the end of the added time.
-.. note::
- Making the system clock frequency value larger allows the system clock
- to provide finer-grained timing, but also increases the amount of work
- the kernel has to do to process ticks (since they occur more frequently).
+The amount of added time that occurs during a kernel object operation
+depends on the following factors.
-Examples
-********
+* The added time introduced by rounding up the specified time interval
+ when converting from milliseconds to ticks. For example, if a tick duration
+ of 10 ms is being used, a specified delay of 25 ms will be rounded up
+ to 30 ms.
+
+* The added time introduced by having to wait for the next tick interrupt
+ before a delay can be properly tracked. For example, if a tick duration
+ of 10 ms is being used, a specified delay of 20 ms requires the kernel
+ to wait for 3 ticks to occur (rather than only 2), since the first tick
+ can occur at any time from the next fraction of a millisecond to just
+ slightly less than 10 ms; only after the first tick has occurred does
+ the kernel know the next 2 ticks will take 20 ms.
+
+Implementation
+**************
Measuring Time with Normal Precision
====================================
-This code uses the system clock to determine how many ticks have elapsed
+This code uses the system clock to determine how much time has elapsed
between two points in time.
.. code-block:: c
int64_t time_stamp;
- int64_t ticks_spent;
+ int64_t milliseconds_spent;
/* capture initial time stamp */
- time_stamp = sys_tick_get();
+ time_stamp = k_uptime_get();
/* do work for some (extended) period of time */
...
- /* compute how long the work took & update time stamp */
- ticks_spent = sys_tick_delta(&time_stamp);
+ /* compute how long the work took (also updates the time stamp) */
+ milliseconds_spent = k_uptime_delta(&time_stamp);
Measuring Time with High Precision
==================================
-This code uses the hardware clock to determine how many ticks have elapsed
+This code uses the hardware clock to determine how much time has elapsed
between two points in time.
.. code-block:: c
@@ -93,37 +119,51 @@
uint32_t nanoseconds_spent;
/* capture initial time stamp */
- start_time = sys_cycle_get_32();
+ start_time = k_cycle_get_32();
/* do work for some (short) period of time */
...
/* capture final time stamp */
- stop_time = sys_cycle_get_32();
+ stop_time = k_cycle_get_32();
/* compute how long the work took (assumes no counter rollover) */
cycles_spent = stop_time - start_time;
nanoseconds_spent = SYS_CLOCK_HW_CYCLES_TO_NS(cycles_spent);
+Suggested Uses
+**************
+
+Use services based on the system clock for time-based processing
+that does not require high precision,
+such as :ref:`timer objects <timers_v2>` or :ref:`thread_sleeping`.
+
+Use services based on the hardware clock for time-based processing
+that requires higher precision than the system clock can provide,
+such as :ref:`busy_waiting` or fine-grained time measurements.
+
+.. note::
+ The high frequency of the hardware clock, combined with its 32-bit size,
+ means that counter rollover must be taken into account when taking
+ high-precision measurements over an extended period of time.
+
+Configuration
+*************
+
+Related configuration options:
+
+* :option:`CONFIG_SYS_CLOCK_TICKS_PER_SEC`
+
APIs
****
The following kernel clock APIs are provided by :file:`kernel.h`:
-:cpp:func:`sys_tick_get()`, :cpp:func:`sys_tick_get_32()`
- Read the system clock.
-
-:cpp:func:`sys_tick_delta()`, :cpp:func:`sys_tick_delta_32()`
- Compute the elapsed time since an earlier system clock reading.
-
-:cpp:func:`sys_tick_get()`, :cpp:func:`sys_tick_get_32()`
- Read the system clock.
-
-:cpp:func:`sys_tick_delta()`, :cpp:func:`sys_tick_delta_32()`
- Compute the elapsed time since an earlier system clock reading.
-
-:cpp:func:`sys_cycle_get_32()`
- Read hardware clock.
+* :cpp:func:`k_uptime_get()`
+* :cpp:func:`k_uptime_get_32()`
+* :cpp:func:`k_uptime_delta()`
+* :cpp:func:`k_uptime_delta_32()`
+* :cpp:func:`k_cycle_get_32()`
The following kernel clock variables are provided by :file:`kernel.h`:
diff --git a/doc/kernel_v2/timing/microkernel_timers.rst b/doc/kernel_v2/timing/microkernel_timers.rst
deleted file mode 100644
index 1a3ccdb..0000000
--- a/doc/kernel_v2/timing/microkernel_timers.rst
+++ /dev/null
@@ -1,211 +0,0 @@
-.. _microkernel_timers_v2:
-
-Timer Services
-##############
-
-Concepts
-********
-
-A :dfn:`microkernel timer` allows a task to determine whether or not a
-specified time limit has been reached while the task is busy performing
-other work. The timer uses the kernel's system clock, measured in
-ticks, to monitor the passage of time.
-
-Any number of microkernel timers can be defined in a microkernel system.
-Each timer has a unique identifier, which allows it to be distinguished
-from other timers.
-
-A task that wants to use a timer must first allocate an unused timer
-from the set of microkernel timers. A task can allocate more than one timer
-when it needs to monitor multiple time intervals simultaneously.
-
-A timer is started by specifying:
-
-* A :dfn:`duration` is the number of ticks the timer counts before it
- expires for the first time.
-* A :dfn:`period` is the number of ticks the timer counts before it expires
- each time thereafter.
-* The :dfn:`microkernel semaphore identifier` is what the timer gives each
- time the semaphore expires.
-
-The semaphore's state can be examined by the task any time the task needs to
-determine whether or not the given time limit has been reached.
-
-When the timer's period is set to zero, the timer stops automatically
-after reaching the duration and giving the semaphore. When the period is set to
-any number of ticks other than zero, the timer restarts automatically with
-a new duration that is equal to its period. When this new duration has elapsed,
-the timer gives the semaphore again and restarts. For example, a timer can be
-set to expire after 5 ticks, and to then re-expire every 20 ticks thereafter,
-resulting in the semaphore being given 3 times after 45 ticks have elapsed.
-
-.. note::
- Care must be taken when specifying the duration of a microkernel timer.
- The first tick measured by the timer after it is started will be
- less than a full-tick interval. For example, when the system clock period
- is 10 milliseconds, starting a timer that expires after 1 tick will result
- in the semaphore being given anywhere from a fraction of a millisecond
- later to just slightly less than 10 milliseconds later. To ensure that a
- timer doesn't expire for at least ``N`` ticks, it is necessary to specify
- a duration of ``N+1`` ticks. This adjustment is not required when specifying
- the period of a timer, which always corresponds to full-tick intervals.
-
-A running microkernel timer can be cancelled or restarted by a task prior to
-its expiration. Cancelling a timer that has already expired does not affect
-the state of the associated semaphore. Likewise, restarting a timer that has
-already expired is equivalent to stopping the timer and starting it afresh.
-
-When a task no longer needs a timer it should free the timer. This makes
-the timer available for reallocation.
-
-Purpose
-*******
-
-Use a microkernel timer to determine whether or not a specified number of
-system clock ticks have elapsed while the task is busy performing other work.
-
-.. note::
- If a task has no other work to perform while waiting for time to pass
- it can simply call :cpp:func:`task_sleep()`.
-
-.. note::
- The microkernel provides additional APIs that allow a task to monitor
- both the system clock and the higher-precision hardware clock, without
- using a microkernel timer.
-
-Usage
-*****
-
-Configuring Microkernel Timers
-==============================
-
-Set the :option:`CONFIG_NUM_TIMER_PACKETS` configuration option to
-specify the number of timer-related command packets available in the
-application. This value should be **equal to** or **greater than** the
-sum of the following quantities:
-
-* The number of microkernel timers.
-* The number of tasks.
-
-.. note::
- Unlike most other microkernel object types, microkernel timers are defined
- as a group using a configuration option, rather than as individual public
- objects in an MDEF or private objects in a source file.
-
-Example: Allocating a Microkernel Timer
-=======================================
-
-This code allocates an unused timer.
-
-.. code-block:: c
-
- ktimer_t timer_id;
-
- timer_id = task_timer_alloc();
-
-Example: Starting a One Shot Microkernel Timer
-==============================================
-This code uses a timer to limit the amount of time a task spends on gathering
-data. It works by monitoring the status of a microkernel semaphore that is set
-when the timer expires. Since the timer is started with a period of zero, it
-stops automatically once it expires.
-
-.. code-block:: c
-
- ktimer_t timer_id;
- ksem_t my_sem;
-
- ...
-
- /* set timer to expire in 10 ticks */
- task_timer_start(timer_id, 10, 0, my_sem);
-
- /* gather data until timer expires */
- do {
- ...
- } while (task_sem_take(my_sem, TICKS_NONE) != RC_OK);
-
- /* process the new data */
- ...
-
-Example: Starting a Periodic Microkernel Timer
-==============================================
-This code is similar to the previous example, except that the timer
-automatically restarts every time it expires. This approach eliminates
-the overhead of having the task explicitly issue a request to
-reactivate the timer.
-
-.. code-block:: c
-
- ktimer_t timer_id;
- ksem_t my_sem;
-
- ...
-
- /* set timer to expire every 10 ticks */
- task_timer_start(timer_id, 10, 10, my_sem);
-
- while (1) {
- /* gather data until timer expires */
- do {
- ...
- } while (task_sem_take(my_sem, TICKS_NONE) != RC_OK);
-
- /* process the new data, then loop around to get more */
- ...
- }
-
-Example: Cancelling a Microkernel Timer
-=======================================
-This code illustrates how an active timer can be stopped prematurely.
-
-.. code-block:: c
-
- ktimer_t timer_id;
- ksem_t my_sem;
-
- ...
-
- /* set timer to expire in 10 ticks */
- task_timer_start(timer_id, 10, 0, my_sem);
-
- /* do work while waiting for input to arrive */
- ...
-
- /* now have input, so stop the timer if it is still running */
- task_timer_stop(timer_id);
-
- /* check to see if the timer expired before it was stopped */
- if (task_sem_take(my_sem, TICKS_NONE) == RC_OK) {
- printf("Warning: Input took too long to arrive!");
- }
-
-Example: Freeing a Microkernel Timer
-====================================
-This code allows a task to relinquish a previously-allocated timer
-so it can be used by other tasks.
-
-.. code-block:: c
-
- task_timer_free(timer_id);
-
-
-APIs
-****
-
-The following microkernel timer APIs are provided by :file:`microkernel.h`:
-
-:cpp:func:`task_timer_alloc()`
- Allocates an unused timer.
-
-:cpp:func:`task_timer_start()`
- Starts a timer.
-
-:cpp:func:`task_timer_restart()`
- Restarts a timer.
-
-:cpp:func:`task_timer_stop()`
- Cancels a timer.
-
-:cpp:func:`task_timer_free()`
- Marks timer as unused.
diff --git a/doc/kernel_v2/timing/nanokernel_timers.rst b/doc/kernel_v2/timing/nanokernel_timers.rst
deleted file mode 100644
index 9e2df70..0000000
--- a/doc/kernel_v2/timing/nanokernel_timers.rst
+++ /dev/null
@@ -1,179 +0,0 @@
-.. _nanokernel_timers_v2:
-
-Timer Services
-##############
-
-Concepts
-********
-
-The nanokernel's :dfn:`timer` object type uses the kernel's system clock to
-monitor the passage of time, as measured in ticks. It is mainly intended for use
-by fibers.
-
-A *nanokernel timer* allows a fiber or task to determine whether or not a
-specified time limit has been reached while the thread itself is busy performing
-other work. A thread can use more than one timer when it needs to monitor multiple
-time intervals simultaneously.
-
-A nanokernel timer points to a *user data structure* that is supplied by the
-thread that uses it; this pointer is returned when the timer expires. The user
-data structure must be at least 4 bytes long and aligned on a 4-byte boundary,
-as the kernel reserves the first 32 bits of this area for its own use. Any
-remaining bytes of this area can be used to hold data that is helpful to the
-thread that uses the timer.
-
-Any number of nanokernel timers can be defined. Each timer is a distinct
-variable of type :c:type:`struct nano_timer`, and is referenced using a pointer
-to that variable. A timer must be initialized with its user data structure
-before it can be used.
-
-A nanokernel timer is started by specifying a *duration*, which is the number
-of ticks the timer counts before it expires.
-
-.. note::
- Care must be taken when specifying the duration of a nanokernel timer,
- since the first tick measured by the timer after it is started will be
- less than a full tick interval. For example, when the system clock period
- is 10 milliseconds, starting a timer than expires after 1 tick will result
- in the timer expiring anywhere from a fraction of a millisecond
- later to just slightly less than 10 milliseconds later. To ensure that
- a timer doesn't expire for at least ``N`` ticks it is necessary to specify
- a duration of ``N+1`` ticks.
-
-Once started, a nanokernel timer can be tested in either a non-blocking or
-blocking manner to allow a thread to determine if the timer has expired.
-If the timer has expired, the kernel returns the pointer to the user data
-structure. If the timer has not expired, the kernel either returns
-:c:macro:`NULL` (for a non-blocking test), or it waits for the timer to expire
-(for a blocking test).
-
-.. note::
- The nanokernel does not allow more than one thread to wait on a nanokernel
- timer at any given time. If a second thread starts waiting, only the first
- waiting thread wakes up when the timer expires. The second thread continues
- waiting.
-
- A task that waits on a nanokernel timer does a ``busy wait``. This is
- not an issue for a nanokernel application's background task; however, in
- a microkernel application, a task that waits on a nanokernel timer remains
- the *current task* and prevents other tasks of equal or lower priority
- from doing useful work.
-
-A nanokernel timer can be cancelled after it has been started. Cancelling
-a timer while it is still running causes the timer to expire immediately,
-thereby unblocking any thread waiting on the timer. Cancelling a timer
-that has already expired has no effect on the timer.
-
-A nanokernel timer can be reused once it has expired, but must **not** be
-restarted while it is still running. If desired, a timer can be re-initialized
-with a different user data structure before it is started again.
-
-
-Purpose
-*******
-
-Use a nanokernel timer to determine whether or not a specified number
-of system clock ticks have elapsed while a fiber or task is busy performing
-other work.
-
-.. note::
- If a fiber or task has no other work to perform while waiting
- for time to pass, it can simply call :cpp:func:`fiber_sleep()`
- or :cpp:func:`task_sleep()`, respectively.
-
-.. note::
- The kernel provides additional APIs that allow a fiber or task to monitor
- the system clock, as well as the higher precision hardware clock,
- without using a nanokernel timer.
-
-
-Usage
-*****
-
-Example: Initializing a Nanokernel Timer
-========================================
-
-This code initializes a nanokernel timer.
-
-.. code-block:: c
-
- struct nano_timer my_timer;
- uint32_t data_area[3] = { 0, 1111, 2222 };
-
- nano_timer_init(&my_timer, data_area);
-
-
-Example: Starting a Nanokernel Timer
-====================================
-This code uses the above nanokernel timer to limit the amount of time a fiber
-spends gathering data before processing it.
-
-.. code-block:: c
-
- /* set timer to expire in 10 ticks */
- nano_fiber_timer_start(&my_timer, 10);
-
- /* gather data until timer expires */
- do {
- ...
- } while (nano_fiber_timer_test(&my_timer, TICKS_NONE) == NULL);
-
- /* process the data */
- ...
-
-
-Example: Cancelling a Nanokernel Timer
-======================================
-This code illustrates how an active nanokernel timer can be stopped prematurely.
-
-.. code-block:: c
-
- struct nano_timer my_timer;
- uint32_t dummy;
-
- ...
-
- /* set timer to expire in 10 ticks */
- nano_timer_init(&my_timer, &dummy);
- nano_fiber_timer_start(&my_timer, 10);
-
- /* do work while waiting for an input signal to arrive */
- ...
-
- /* now have input signal, so stop the timer if it is still running */
- nano_fiber_timer_stop(&my_timer);
-
- /* check to see if the timer expired before it was stopped */
- if (nano_fiber_timer_test(&my_timer, TICKS_NONE) != NULL) {
- printf("Warning: Input signal took too long to arrive!");
- }
-
-
-APIs
-****
-
-APIs for a nanokernel timer provided by :file:`nanokernel.h`
-============================================================
-
-:cpp:func:`nano_timer_init()`
-
- Initialize a timer.
-
-:cpp:func:`nano_task_timer_start()`, :cpp:func:`nano_fiber_timer_start()`,
-:cpp:func:`nano_isr_timer_start()`, :cpp:func:`nano_timer_start()`
-
- Start a timer.
-
-:cpp:func:`nano_task_timer_test()`, :cpp:func:`nano_fiber_timer_test()`,
-:cpp:func:`nano_isr_timer_test()`, :cpp:func:`nano_timer_test()`
-
- Wait or test for timer expiration.
-
-:cpp:func:`nano_task_timer_stop()`, :cpp:func:`nano_fiber_timer_stop()`,
-:cpp:func:`nano_isr_timer_stop()`, :cpp:func:`nano_timer_stop()`
-
- Force timer expiration, if not already expired.
-
-:cpp:func:`nano_timer_ticks_remain()`
-
- Return timer ticks before timer expiration.
diff --git a/doc/kernel_v2/timing/timers.rst b/doc/kernel_v2/timing/timers.rst
new file mode 100644
index 0000000..7cc0562
--- /dev/null
+++ b/doc/kernel_v2/timing/timers.rst
@@ -0,0 +1,249 @@
+.. _timers_v2:
+
+Timers
+######
+
+A :dfn:`timer` is a kernel object that measures the passage of time
+using the kernel's system clock. When a timer's specified time limit
+is reached it can perform an application-defined action,
+or it can simply record the expiration and wait for the application
+to read its status.
+
+.. contents::
+ :local:
+ :depth: 2
+
+Concepts
+********
+
+Any number of timers can be defined. Each timer is referenced by its
+memory address.
+
+A timer has the following key properties:
+
+* A :dfn:`duration` specifying the time interval before the timer expires
+ for the first time, measured in milliseconds. It must be greater than zero.
+
+* A :dfn:`period` specifying the time interval between all timer expirations
+ after the first one, measured in milliseconds. It must be non-negative.
+ A period of zero means that the timer is a one shot timer that stops
+ after a single expiration.
+
+* An :dfn:`expiry function` that is executed each time the timer expires.
+ The function is executed by the system clock interrupt handler.
+ If no expiry function is required a :c:macro:`NULL` function can be specified.
+
+* A :dfn:`stop function` that is executed if the timer is stopped prematurely
+ while running. The function is executed by the thread that stops the timer.
+ If no stop function is required a :c:macro:`NULL` function can be specified.
+
+* A :dfn:`status` value that indicates how many times the timer has expired
+ since the status value was last read.
+
+A timer must be initialized before it can be used. This specifies its
+expiry function and stop function values, sets the timer's status to zero,
+and puts the timer into the **stopped** state.
+
+A timer is **started** by specifying a duration and a period.
+The timer's status is reset to zero, then the timer enters
+the **running** state and begins counting down towards expiry.
+
+When a running timer expires its status is incremented
+and the timer executes its expiry function, if one exists;
+If a thread is waiting on the timer, it is unblocked.
+If the timer's period is zero the timer enters the stopped state;
+otherwise the timer restarts with a new duration equal to its period.
+
+A running timer can be stopped in mid-countdown, if desired.
+The timer's status is left unchanged, then the timer enters the stopped state
+and executes its stop function, if one exists.
+If a thread is waiting on the timer, it is unblocked.
+Attempting to stop a non-running timer is permitted,
+but has no effect on the timer since it is already stopped.
+
+A running timer can be restarted in mid-countdown, if desired.
+The timer's status is reset to zero, then the timer begins counting down
+using the new duration and period values specified by the caller.
+If a thread is waiting on the timer, it continues waiting.
+
+A timer's status can be read directly at any time to determine how many times
+the timer has expired since its status was last read.
+Reading a timer's status resets its value to zero.
+The amount of time remaining before the timer expires can also be read;
+a value of zero indicates that the timer is stopped.
+
+A thread may read a timer's status indirectly by **synchronizing**
+with the timer. This blocks the thread until the timer's status is non-zero
+(indicating that it has expired at least once) or the timer is stopped;
+if the timer status is already non-zero or the timer is already stopped
+the thread continues without waiting. The synchronization operation
+returns the timer's status and resets it to zero.
+
+.. note::
+ Only a single user should examine the status of any given timer,
+ since reading the status (directly or indirectly) changes its value.
+ Similarly, only a single thread at a time should synchronize
+ with a given timer. ISRs are not permitted to synchronize with timers,
+ since ISRs are not allowed to block.
+
+Timer Limitations
+=================
+
+Since timers are based on the system clock, the delay values specified
+when using a timer are **minimum** values.
+(See :ref:`clock_limitations`.)
+
+Implementation
+**************
+
+Defining a Timer
+================
+
+A timer is defined using a variable of type :c:type:`struct k_timer`.
+It must then be initialized by calling :cpp:func:`k_timer_init()`.
+
+The following code defines and initializes a timer.
+
+.. code-block:: c
+
+ struct k_timer my_timer;
+ extern void my_expiry_function(struct k_timer *timer_id);
+
+ k_timer_init(&my_timer, my_expiry_function, NULL);
+
+Alternatively, a timer can be defined and initialized at compile time
+by calling :c:macro:`K_TIMER_DEFINE()`.
+
+The following code has the same effect as the code segment above.
+
+.. code-block:: c
+
+ K_TIMER_DEFINE(my_timer, my_expiry_function, NULL);
+
+Using a Timer Expiry Function
+=============================
+
+The following code uses a timer to perform a non-trivial action on a periodic
+basis. Since the required work cannot be done at interrupt level,
+the timer's expiry function uses a :ref:`kernel event object <events_v2>`
+to do the work in the context of the system workqueue.
+
+.. code-block:: c
+
+ int my_event_handler(struct k_event *dummy)
+ {
+ /* do the processing that needs to be done periodically */
+ ...
+ return 0;
+ }
+
+ K_EVENT_DEFINE(my_event, my_event_handler);
+
+ void my_timer_handler(struct k_timer *dummy)
+ {
+ k_event_send(&my_event);
+ }
+
+ K_TIMER_DEFINE(my_timer, my_timer_handler, NULL);
+
+ ...
+
+ /* start periodic timer that expires once every second */
+ k_timer_start(&my_timer, 1000, 1000);
+
+Reading Timer Status
+====================
+
+The following code reads a timer's status directly to determine
+if the timer has expired on not.
+
+.. code-block:: c
+
+ K_TIMER_DEFINE(my_status_timer, NULL, NULL);
+
+ ...
+
+ /* start one shot timer that expires after 200 ms */
+ k_timer_start(&my_status_timer, 200, 0);
+
+ /* do work */
+ ...
+
+ /* check timer status */
+ if (k_timer_status_get(&my_status_timer) > 0) {
+ /* timer has expired */
+ } else if (k_timer_remaining_get(&my_status_timer) == 0) {
+ /* timer was stopped (by someone else) before expiring */
+ } else {
+ /* timer is still running */
+ }
+
+Using Timer Status Synchronization
+==================================
+
+The following code performs timer status synchronization to allow a thread
+to do useful work while ensuring that a pair of protocol operations
+are separated by the specified time interval.
+
+.. code-block:: c
+
+ K_TIMER_DEFINE(my_sync_timer, NULL, NULL);
+
+ ...
+
+ /* do first protocol operation */
+ ...
+
+ /* start one shot timer that expires after 500 ms */
+ k_timer_start(&my_sync_timer, 500, 0);
+
+ /* do other work */
+ ...
+
+ /* ensure timer has expired (waiting for expiry, if necessary) */
+ k_timer_status_sync(&my_sync_timer);
+
+ /* do second protocol operation */
+ ...
+
+.. note::
+ If the thread had no other work to do it could simply sleep
+ between the two protocol operations, without using a timer.
+
+Suggested Uses
+**************
+
+Use a timer to initiate an asynchronous operation after a specified
+amount of time.
+
+Use a timer to determine whether or not a specified amount of time
+has elapsed.
+
+Use a timer to perform other work while carrying out operations
+involving time limits.
+
+.. note::
+ If a thread has no other work to perform while waiting for time to pass
+ it should call :cpp:func:`k_sleep()`.
+ If a thread needs to measure the time required to perform an operation
+ it can read the :ref:`system clock or the hardware clock <clocks_v2>`
+ directly, rather than using a timer.
+
+Configuration Options
+*********************
+
+Related configuration options:
+
+* None.
+
+APIs
+****
+
+The following timer APIs are provided by :file:`kernel.h`:
+
+* :cpp:func:`k_timer_init()`
+* :cpp:func:`k_timer_start()`
+* :cpp:func:`k_timer_stop()`
+* :cpp:func:`k_timer_status_get()`
+* :cpp:func:`k_timer_status_sync()`
+* :cpp:func:`k_timer_remaining_get()`
diff --git a/doc/kernel_v2/timing/timing.rst b/doc/kernel_v2/timing/timing.rst
index fc5701d..3651f28 100644
--- a/doc/kernel_v2/timing/timing.rst
+++ b/doc/kernel_v2/timing/timing.rst
@@ -1,14 +1,13 @@
.. _timing_v2:
-Timing [TBD]
-############
+Timing
+######
-This section describes the timing-related services available
-in the kernel.
+This section describes the kernel's time-based services, such as
+specifying time delays or for measuring the passage of time.
.. toctree::
:maxdepth: 2
clocks.rst
- nanokernel_timers.rst
- microkernel_timers.rst
+ timers.rst