Clocks

Name

cyg_clock_create, cyg_clock_delete, cyg_clock_to_counter, cyg_clock_set_resolution, cyg_clock_get_resolution, cyg_real_time_clock, cyg_current_time -- Provide system clocks

Synopsis

#include <cyg/kernel/kapi.h>
        

void cyg_clock_create(cyg_resolution_t resolution, cyg_handle_t* handle, cyg_clock* clock);

void cyg_clock_delete(cyg_handle_t clock);

void cyg_clock_to_counter(cyg_handle_t clock, cyg_handle_t* counter);

void cyg_clock_set_resolution(cyg_handle_t clock, cyg_resolution_t resolution);

cyg_resolution_t cyg_clock_get_resolution(cyg_handle_t clock);

cyg_handle_t cyg_real_time_clock(void);

cyg_tick_count_t cyg_current_time(void);

Description

In the eCos kernel clock objects are a special form of counter objects. They are attached to a specific type of hardware, clocks that generate ticks at very specific time intervals, whereas counters can be used with any event source.

In a default configuration the kernel provides a single clock instance, the real-time clock. This gets used for timeslicing and for operations that involve a timeout, for example cyg_semaphore_timed_wait. If this functionality is not required it can be removed from the system using the configuration option CYGVAR_KERNEL_COUNTERS_CLOCK. Otherwise the real-time clock can be accessed by a call to cyg_real_time_clock, allowing applications to attach alarms, and the current counter value can be obtained using cyg_current_time.

Applications can create and destroy additional clocks if desired, using cyg_clock_create and cyg_clock_delete. The first argument to cyg_clock_create specifies the resolution this clock will run at. The second argument is used to return a handle for this clock object, and the third argument provides the kernel with the memory needed to hold this object. This clock will not actually tick by itself. Instead it is the responsibility of application code to initialize a suitable hardware timer to generate interrupts at the appropriate frequency, install an interrupt handler for this, and call cyg_counter_tick from inside the DSR. Associated with each clock is a kernel counter, a handle for which can be obtained using cyg_clock_to_counter.

Clock Resolutions and Ticks

At the kernel level all clock-related operations including delays, timeouts and alarms work in units of clock ticks, rather than in units of seconds or milliseconds. If the calling code, whether the application or some other package, needs to operate using units such as milliseconds then it has to convert from these units to clock ticks.

The main reason for this is that it accurately reflects the hardware: calling something like nanosleep with a delay of ten nanoseconds will not work as intended on any real hardware because timer interrupts simply will not happen that frequently; instead calling cyg_thread_delay with the equivalent delay of 0 ticks gives a much clearer indication that the application is attempting something inappropriate for the target hardware. Similarly, passing a delay of five ticks to cyg_thread_delay makes it fairly obvious that the current thread will be suspended for somewhere between four and five clock periods, as opposed to passing 50000000 to nanosleep which suggests a granularity that is not actually provided.

A secondary reason is that conversion between clock ticks and units such as milliseconds can be somewhat expensive, and whenever possible should be done at compile-time or by the application developer rather than at run-time. This saves code size and cpu cycles.

The information needed to perform these conversions is the clock resolution. This is a structure with two fields, a dividend and a divisor, and specifies the number of nanoseconds between clock ticks. For example a clock that runs at 100Hz will have 10 milliseconds between clock ticks, or 10000000 nanoseconds. The ratio between the resolution's dividend and divisor will therefore be 10000000 to 1, and typical values for these might be 1000000000 and 100. If the clock runs at a different frequency, say 60Hz, the numbers could be 1000000000 and 60 respectively. Given a delay in nanoseconds, this can be converted to clock ticks by multiplying with the the divisor and then dividing by the dividend. For example a delay of 50 milliseconds corresponds to 50000000 nanoseconds, and with a clock frequency of 100Hz this can be converted to ((50000000 * 100) / 1000000000) = 5 clock ticks. Given the large numbers involved this arithmetic normally has to be done using 64-bit precision and the long long data type, but allows code to run on hardware with unusual clock frequencies.

The default frequency for the real-time clock on any platform is usually about 100Hz, but platform-specific documentation should be consulted for this information. Usually it is possible to override this default by configuration options, but again this depends on the capabilities of the underlying hardware. The resolution for any clock can be obtained using cyg_clock_get_resolution. For clocks created by application code, there is also a function cyg_clock_set_resolution. This does not affect the underlying hardware timer in any way, it merely updates the information that will be returned in subsequent calls to cyg_clock_get_resolution: changing the actual underlying clock frequency will require appropriate manipulation of the timer hardware.

Valid contexts

cyg_clock_create is usually only called during system initialization (if at all), but may also be called from thread context. The same applies to cyg_clock_delete. The remaining functions may be called during initialization, from thread context, or from DSR context, although it should be noted that there is no locking between cyg_clock_get_resolution and cyg_clock_set_resolution so theoretically it is possible that the former returns an inconsistent data structure.