Kernel Clocks

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

Purpose

Use the system clock for time-based processing that does not require high precision, such as implementing time limits or time delays.

Use the hardware clock for time-based processing that requires higher precision than the system clock can provide, such as 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.

Usage

Configuring the Kernel Clocks

Use the 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.

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

Example: Measuring Time with Normal Precision

This code uses the system clock to determine how many ticks have elapsed between two points in time.

int64_t time_stamp;
int64_t ticks_spent;

/* capture initial time stamp */
time_stamp = sys_tick_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);

Example: Measuring Time with High Precision

This code uses the hardware clock to determine how many ticks have elapsed between two points in time.

uint32_t start_time;
uint32_t stop_time;
uint32_t cycles_spent;
uint32_t nanoseconds_spent;

/* capture initial time stamp */
start_time = sys_cycle_get_32();

/* do work for some (short) period of time */
...

/* capture final time stamp */
stop_time = sys_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);

APIs

Kernel clock APIs provided by microkernel.h

sys_tick_get(), sys_tick_get_32()
Read the system clock.
sys_tick_delta(), sys_tick_delta_32()
Compute the elapsed time since an earlier system clock reading.

Kernel clock APIs common to both microkernel.h`and :file:`nanokernel.h

sys_tick_get(), sys_tick_get_32()
Read the system clock.
sys_tick_delta(), sys_tick_delta_32()
Compute the elapsed time since an earlier system clock reading.
sys_cycle_get_32()
Read hardware clock.

Kernel clock variables common to both microkernel.h and nanokernel.h

sys_clock_ticks_per_sec
The number of system clock ticks in a single second.
sys_clock_hw_cycles_per_sec
The number of hardware clock cycles in a single second.
sys_clock_us_per_tick
The number of microseconds in a single system clock tick.
sys_clock_hw_cycles_per_tick
The number of hardware clock cycles in a single system clock tick.