source: rtems-docs/bsp_howto/clock.rst @ d389819

4.115
Last change on this file since d389819 was d389819, checked in by Amar Takhar <amar@…>, on 01/18/16 at 05:37:40

Convert all Unicode to ASCII(128)

  • Property mode set to 100644
File size: 9.0 KB
Line 
1Clock Driver
2############
3
4Introduction
5============
6
7The purpose of the clock driver is to provide two services for the operating
8system.
9
10- A steady time basis to the kernel, so that the RTEMS primitives that need
11  a clock tick work properly.  See the *Clock Manager* chapter of the*RTEMS Application C User's Guide* for more details.
12
13- An optional time counter to generate timestamps of the uptime and wall
14  clock time.
15
16The clock driver is usually located in the :file:`clock` directory of the BSP.
17Clock drivers should use the :dfn:`Clock Driver Shell` available via the:file:`clockdrv_shell.h` include file.
18
19Clock Driver Shell
20==================
21
22The :dfn:`Clock Driver Shell` include file defines the clock driver functions
23declared in ``#include <rtems/clockdrv.h>`` which are used by RTEMS
24configuration file ``#include <rtems/confdefs.h>``.  In case the application
25configuration defines ``#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER``,
26then the clock driver is registered and should provide its services to the
27operating system.  A hardware specific clock driver must provide some
28functions, defines and macros for the :dfn:`Clock Driver Shell` which are
29explained here step by step.  A clock driver file looks in general like this.
30.. code:: c
31
32    /*
33    * A section with functions, defines and macros to provide hardware specific
34    * functions for the Clock Driver Shell.
35    \*/
36    #include "../../../shared/clockdrv_shell.h"
37
38Initialization
39--------------
40
41Depending on the hardware capabilities one out of three clock driver variants
42must be selected.
43
44- The most basic clock driver provides only a periodic interrupt service
45  routine which calls ``rtems_clock_tick()``.  The interval is determined by
46  the application configuration via ``#define
47  CONFIGURE_MICROSECONDS_PER_TICK`` and can be obtained via``rtems_configuration_get_microseconds_per_tick()``.  The timestamp
48  resolution is limited to the clock tick interval.
49
50- In case the hardware lacks support for a free running counter, then the
51  module used for the clock tick may provide support for timestamps with a
52  resolution below the clock tick interval.  For this so called simple
53  timecounters can be used.
54
55- The desired variant uses a free running counter to provide accurate
56  timestamps.  This variant is mandatory on SMP configurations.
57
58Clock Tick Only Variant
59~~~~~~~~~~~~~~~~~~~~~~~
60
61.. code:: c
62
63    static void some_support_initialize_hardware( void )
64    {
65    /* Initialize hardware \*/
66    }
67    #define Clock_driver_support_initialize_hardware() \\
68    some_support_initialize_hardware()
69    /* Indicate that this clock driver lacks a proper timecounter in hardware \*/
70    #define CLOCK_DRIVER_USE_DUMMY_TIMECOUNTER
71    #include "../../../shared/clockdrv_shell.h"
72
73Simple Timecounter Variant
74~~~~~~~~~~~~~~~~~~~~~~~~~~
75
76.. code:: c
77
78    #include <rtems/timecounter.h>
79    static rtems_timecounter_simple some_tc;
80    static uint32_t some_tc_get( rtems_timecounter_simple \*tc )
81    {
82    return some.counter;
83    }
84    static bool some_tc_is_pending( rtems_timecounter_simple \*tc )
85    {
86    return some.is_pending;
87    }
88    static uint32_t some_tc_get_timecount( struct timecounter \*tc )
89    {
90    return rtems_timecounter_simple_downcounter_get(
91    tc,
92    some_tc_get,
93    some_tc_is_pending
94    );
95    }
96    static void some_tc_tick( void )
97    {
98    rtems_timecounter_simple_downcounter_tick( &some_tc, some_tc_get );
99    }
100    static void some_support_initialize_hardware( void )
101    {
102    uint32_t frequency = 123456;
103    uint64_t us_per_tick = rtems_configuration_get_microseconds_per_tick();
104    uint32_t timecounter_ticks_per_clock_tick =
105    ( frequency * us_per_tick ) / 1000000;
106    /* Initialize hardware \*/
107    rtems_timecounter_simple_install(
108    &some_tc,
109    frequency,
110    timecounter_ticks_per_clock_tick,
111    some_tc_get_timecount
112    );
113    }
114    #define Clock_driver_support_initialize_hardware() \\
115    some_support_initialize_hardware()
116    #define Clock_driver_timecounter_tick() \\
117    some_tc_tick()
118    #include "../../../shared/clockdrv_shell.h"
119
120Timecounter Variant
121~~~~~~~~~~~~~~~~~~~
122
123This variant is preferred since it is the most efficient and yields the most
124accurate timestamps.  It is also mandatory on SMP configurations to obtain
125valid timestamps.  The hardware must provide a periodic interrupt to service
126the clock tick and a free running counter for the timecounter.  The free
127running counter must have a power of two period.  The ``tc_counter_mask``
128must be initialized to the free running counter period minus one, e.g. for a
12932-bit counter this is 0xffffffff.  The ``tc_get_timecount`` function must
130return the current counter value (the counter values must increase, so if the
131counter counts down, a conversion is necessary).  Use``RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER`` for the ``tc_quality``.  Set``tc_frequency`` to the frequency of the free running counter in Hz.  All
132other fields of the ``struct timecounter`` must be zero initialized.
133Install the initialized timecounter via ``rtems_timecounter_install()``.
134.. code:: c
135
136    #include <rtems/timecounter.h>
137    static struct timecounter some_tc;
138    static uint32_t some_tc_get_timecount( struct timecounter \*tc )
139    {
140    some.free_running_counter;
141    }
142    static void some_support_initialize_hardware( void )
143    {
144    uint64_t us_per_tick = rtems_configuration_get_microseconds_per_tick();
145    uint32_t frequency = 123456;
146    /*
147    * The multiplication must be done in 64-bit arithmetic to avoid an integer
148    * overflow on targets with a high enough counter frequency.
149    \*/
150    uint32_t interval = (uint32_t) ( ( frequency * us_per_tick ) / 1000000 );
151    /*
152    * Initialize hardware and set up a periodic interrupt for the configuration
153    * based interval.
154    \*/
155    some_tc.tc_get_timecount = some_tc_get_timecount;
156    some_tc.tc_counter_mask = 0xffffffff;
157    some_tc.tc_frequency = frequency;
158    some_tc.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER;
159    rtems_timecounter_install( &some_tc );
160    }
161    #define Clock_driver_support_initialize_hardware() \\
162    some_support_initialize_hardware()
163    #include "../../../shared/clockdrv_shell.h"
164
165Install Clock Tick Interrupt Service Routine
166--------------------------------------------
167
168The clock driver must provide a function to install the clock tick interrupt
169service routine via ``Clock_driver_support_install_isr()``.
170.. code:: c
171
172    #include <bsp/irq.h>
173    #include <bsp/fatal.h>
174    static void some_support_install_isr( rtems_interrupt_handler isr )
175    {
176    rtems_status_code sc;
177    sc = rtems_interrupt_handler_install(
178    SOME_IRQ,
179    "Clock",
180    RTEMS_INTERRUPT_UNIQUE,
181    isr,
182    NULL
183    );
184    if ( sc != RTEMS_SUCCESSFUL ) {
185    bsp_fatal( SOME_FATAL_IRQ_INSTALL );
186    }
187    }
188    #define Clock_driver_support_install_isr( isr, old ) \\
189    some_support_install_isr( isr )
190    #include "../../../shared/clockdrv_shell.h"
191
192Support At Tick
193---------------
194
195The hardware specific support at tick is specified by``Clock_driver_support_at_tick()``.
196.. code:: c
197
198    static void some_support_at_tick( void )
199    {
200    /* Clear interrupt \*/
201    }
202    #define Clock_driver_support_at_tick() \\
203    some_support_at_tick()
204    #include "../../../shared/clockdrv_shell.h"
205
206System Shutdown Support
207-----------------------
208
209The :dfn:`Clock Driver Shell` provides the routine ``Clock_exit()`` that is
210scheduled to be run during system shutdown via the ``atexit()`` routine.
211The hardware specific shutdown support is specified by``Clock_driver_support_shutdown_hardware()`` which is used by``Clock_exit()``.  It should disable the clock tick source if it was
212enabled.  This can be used to prevent clock ticks after the system is shutdown.
213.. code:: c
214
215    static void some_support_shutdown_hardware( void )
216    {
217    /* Shutdown hardware \*/
218    }
219    #define Clock_driver_support_shutdown_hardware() \\
220    some_support_shutdown_hardware()
221    #include "../../../shared/clockdrv_shell.h"
222
223Multiple Clock Driver Ticks Per Clock Tick
224------------------------------------------
225
226In case the hardware needs more than one clock driver tick per clock tick (e.g.
227due to a limited range of the hardware timer), then this can be specified with
228the optional ``#define CLOCK_DRIVER_ISRS_PER_TICK`` and ``#define
229CLOCK_DRIVER_ISRS_PER_TICK_VALUE`` defines.  This is currently used only for x86
230and it hopefully remains that way.
231.. code:: c
232
233    /* Enable multiple clock driver ticks per clock tick \*/
234    #define CLOCK_DRIVER_ISRS_PER_TICK 1
235    /* Specifiy the clock driver ticks per clock tick value \*/
236    #define CLOCK_DRIVER_ISRS_PER_TICK_VALUE 123
237    #include "../../../shared/clockdrv_shell.h"
238
239Clock Driver Ticks Counter
240--------------------------
241
242The :dfn:`Clock Driver Shell` provide a global variable that is simply a count
243of the number of clock driver interrupt service routines that have occurred.
244This information is valuable when debugging a system.  This variable is
245declared as follows:
246.. code:: c
247
248    volatile uint32_t Clock_driver_ticks;
249
250.. COMMENT: COPYRIGHT (c) 1988-2002.
251
252.. COMMENT: On-Line Applications Research Corporation (OAR).
253
254.. COMMENT: All rights reserved.
255
Note: See TracBrowser for help on using the repository browser.