source: rtems-docs/bsp-howto/clock.rst @ bbdf66c

5am
Last change on this file since bbdf66c was bbdf66c, checked in by Sebastian Huber <sebastian.huber@…>, on 08/04/17 at 12:26:36

bsp: Optional clock driver shutdown

  • Property mode set to 100644
File size: 10.9 KB
Line 
1.. comment SPDX-License-Identifier: CC-BY-SA-4.0
2
3.. COMMENT: COPYRIGHT (c) 1988-2002.
4.. COMMENT: On-Line Applications Research Corporation (OAR).
5.. COMMENT: All rights reserved.
6
7Clock Driver
8************
9
10Introduction
11============
12
13The purpose of the clock driver is to provide two services for the operating
14system.
15
16- A steady time basis to the kernel, so that the RTEMS primitives that need a
17  clock tick work properly.  See the *Clock Manager* chapter of the *RTEMS
18  Application C User's Guide* for more details.
19
20- An optional `timecounter <http://www.freebsd.dk/pubs/timecounter.pdf>`_ to
21  provide timestamps of the uptime and wall clock time with higher resolution
22  than the clock tick.
23
24The clock driver is usually located in the :file:`clock` directory of the BSP.
25Clock drivers must use the :dfn:`Clock Driver Shell` available via the
26`clockdrv_shell.h <https://git.rtems.org/rtems/tree/c/src/lib/libbsp/shared/clockdrv_shell.h>`_
27include file.  This include file is not a normal header file and instead
28defines the clock driver functions declared in ``#include <rtems/clockdrv.h>``
29which are used by RTEMS configuration file ``#include <rtems/confdefs.h>``.  In
30case the application configuration defines
31``#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER``, then the clock driver is
32registered and should provide its services to the operating system.  The clock
33tick interval is determined by the application configuration via
34``#define CONFIGURE_MICROSECONDS_PER_TICK`` and can be obtained via
35``rtems_configuration_get_microseconds_per_tick()``.
36
37A hardware-specific clock driver must provide some functions, defines and
38macros for the :dfn:`Clock Driver Shell` which are explained here step by step.
39A clock driver file looks in general like this.
40
41.. code-block:: c
42
43    /*
44     * A section with functions, defines and macros to provide hardware-specific
45     * functions for the Clock Driver Shell.
46     */
47
48    #include "../../../shared/clockdrv_shell.h"
49
50Depending on the hardware capabilities one out of three clock driver variants
51must be selected.
52
53Timecounter
54    The variant which provides all features needs a free running hardware
55    counter and a periodic clock tick interrupt.  This variant is mandatory in
56    SMP configurations.
57
58Simple Timecounter
59    A simple timecounter can be used if the hardware provides no free running
60    hardware counter and only a periodic hardware counter synchronous to the
61    clock tick interrupt is available.
62
63Clock Tick Only
64    The most basic clock driver provides only a periodic clock tick interrupt.
65    The timestamp resolution is limited to the clock tick interval.
66
67Initialization
68==============
69
70Timecounter Variant
71~~~~~~~~~~~~~~~~~~~
72
73This variant is preferred since it is the most efficient and yields the most
74accurate timestamps.  It is also mandatory in SMP configurations to obtain
75valid timestamps.  The hardware must provide a periodic interrupt to service
76the clock tick and a free running counter for the timecounter.  The free
77running counter must have a power of two period.  The ``tc_counter_mask`` must
78be initialized to the free running counter period minus one, e.g. for a 17-bit
79counter this is ``0x0001ffff``.  The ``tc_get_timecount`` function must return
80the current counter value (the counter values must increase, so if the counter
81counts down, a conversion is necessary).  Use
82``RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER`` for the ``tc_quality``.  Set
83``tc_frequency`` to the frequency of the free running counter in Hz.  All other
84fields of the ``struct timecounter`` must be zero initialized.  Install the
85initialized timecounter via ``rtems_timecounter_install()``.
86
87For an example see the `QorIQ clock driver
88<https://git.rtems.org/rtems/tree/c/src/lib/libbsp/powerpc/qoriq/clock/clock-config.c>`_.
89
90.. code-block:: c
91
92    #include <rtems/timecounter.h>
93
94    static struct timecounter some_tc;
95
96    static uint32_t some_tc_get_timecount( struct timecounter *tc )
97    {
98      some.free_running_counter;
99    }
100
101    static void some_support_initialize_hardware( void )
102    {
103      uint64_t us_per_tick;
104      uint32_t counter_frequency_in_hz;
105      uint32_t counter_ticks_per_clock_tick;
106
107      us_per_tick = rtems_configuration_get_microseconds_per_tick();
108      counter_frequency_in_hz = some_tc_get_frequency();
109
110      /*
111       * The multiplication must be done in 64-bit arithmetic to avoid an integer
112       * overflow on targets with a high enough counter frequency.
113       */
114      counter_ticks_per_clock_tick =
115        (uint32_t) ( counter_frequency_in_hz * us_per_tick ) / 1000000;
116
117      /*
118       * Initialize hardware and set up a periodic interrupt for the configuration
119       * based counter ticks per clock tick.
120       */
121
122      some_tc.tc_get_timecount = some_tc_get_timecount;
123      some_tc.tc_counter_mask = 0xffffffff;
124      some_tc.tc_frequency = frequency;
125      some_tc.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER;
126      rtems_timecounter_install( &some_tc );
127    }
128
129    #define Clock_driver_support_initialize_hardware() \
130      some_support_initialize_hardware()
131
132    #include "../../../shared/clockdrv_shell.h"
133
134Simple Timecounter Variant
135~~~~~~~~~~~~~~~~~~~~~~~~~~
136
137For an example see the `ERC32 clock driver
138<https://git.rtems.org/rtems/tree/c/src/lib/libbsp/sparc/erc32/clock/ckinit.c>`_.
139
140.. code-block:: c
141
142    #include <rtems/timecounter.h>
143
144    static rtems_timecounter_simple some_tc;
145
146    static uint32_t some_tc_get( rtems_timecounter_simple *tc )
147    {
148      return some.counter;
149    }
150
151    static bool some_tc_is_pending( rtems_timecounter_simple *tc )
152    {
153      return some.is_pending;
154    }
155
156    static uint32_t some_tc_get_timecount( struct timecounter *tc )
157    {
158      return rtems_timecounter_simple_downcounter_get(
159        tc,
160        some_tc_get,
161        some_tc_is_pending
162      );
163    }
164
165    static void some_tc_tick( void )
166    {
167      rtems_timecounter_simple_downcounter_tick( &some_tc, some_tc_get );
168    }
169
170    static void some_support_initialize_hardware( void )
171    {
172      uint64_t us_per_tick;
173      uint32_t counter_frequency_in_hz;
174      uint32_t counter_ticks_per_clock_tick;
175
176      us_per_tick = rtems_configuration_get_microseconds_per_tick();
177      counter_frequency_in_hz = some_tc_get_frequency();
178      counter_ticks_per_clock_tick =
179        (uint32_t) ( counter_frequency_in_hz * us_per_tick ) / 1000000;
180
181      /* Initialize hardware */
182
183      rtems_timecounter_simple_install(
184        &some_tc,
185        counter_frequency_in_hz,
186        counter_ticks_per_clock_tick,
187        some_tc_get_timecount
188      );
189    }
190
191    #define Clock_driver_support_initialize_hardware() \
192      some_support_initialize_hardware()
193    #define Clock_driver_timecounter_tick() \
194      some_tc_tick()
195
196    #include "../../../shared/clockdrv_shell.h"
197
198Clock Tick Only Variant
199~~~~~~~~~~~~~~~~~~~~~~~
200
201For an example see the `Motrola 68360 clock driver
202<https://git.rtems.org/rtems/tree/c/src/lib/libbsp/m68k/gen68360/clock/clock.c>`_.
203
204.. code-block:: c
205
206    static void some_support_initialize_hardware( void )
207    {
208      /* Initialize hardware */
209    }
210
211    #define Clock_driver_support_initialize_hardware() \
212      some_support_initialize_hardware()
213
214    /* Indicate that this clock driver lacks a proper timecounter in hardware */
215
216    #define CLOCK_DRIVER_USE_DUMMY_TIMECOUNTER
217
218    #include "../../../shared/clockdrv_shell.h"
219
220Install Clock Tick Interrupt Service Routine
221============================================
222
223The clock driver must provide a function to install the clock tick interrupt
224service routine via ``Clock_driver_support_install_isr()``.
225
226.. code-block:: c
227
228    #include <bsp/irq.h>
229    #include <bsp/fatal.h>
230
231    static void some_support_install_isr( rtems_interrupt_handler isr )
232    {
233      rtems_status_code sc;
234      sc = rtems_interrupt_handler_install(
235        SOME_IRQ,
236        "Clock",
237        RTEMS_INTERRUPT_UNIQUE,
238        isr,
239        NULL
240      );
241      if ( sc != RTEMS_SUCCESSFUL ) {
242        bsp_fatal( SOME_FATAL_IRQ_INSTALL );
243      }
244    }
245
246    #define Clock_driver_support_install_isr( isr, old ) \
247      some_support_install_isr( isr )
248
249    #include "../../../shared/clockdrv_shell.h"
250
251Support At Tick
252===============
253
254The hardware-specific support at tick is specified by
255``Clock_driver_support_at_tick()``.
256
257.. code-block:: c
258
259    static void some_support_at_tick( void )
260    {
261      /* Clear interrupt */
262    }
263
264    #define Clock_driver_support_at_tick() \
265      some_support_at_tick()
266
267    #include "../../../shared/clockdrv_shell.h"
268
269System Shutdown Support
270=======================
271
272Optionally, the :dfn:`Clock Driver Shell` provides the routine ``Clock_exit()``
273that is scheduled to be run during system shutdown via the ``atexit()``
274routine.  The hardware-specific shutdown support is specified by
275``Clock_driver_support_shutdown_hardware()`` which is used by ``Clock_exit()``.
276It should disable the clock tick source if it was enabled.  This can be used to
277prevent clock ticks after the system is shutdown.  The
278``Clock_driver_support_shutdown_hardware()`` must be provided as a macro.  In
279case this macro is undefined, then the shutdown support is disabled.  This is
280useful for example on memory constrained systems to avoid the ``atexit()``
281overhead.
282
283.. code-block:: c
284
285    static void some_support_shutdown_hardware( void )
286    {
287      /* Shutdown hardware */
288    }
289
290    #define Clock_driver_support_shutdown_hardware() \
291      some_support_shutdown_hardware()
292
293    #include "../../../shared/clockdrv_shell.h"
294
295SMP Support
296===========
297
298In SMP configurations, the clock tick service must be executed for each
299processor used by RTEMS.  By default, the clock tick interrupt must be
300distributed to all processors used by RTEMS and each processor invokes the
301clock tick service individually.  A clock driver may delegate all the work to
302the boot processor.  It must define ``CLOCK_DRIVER_USE_ONLY_BOOT_PROCESSOR`` in
303this case.
304
305Clock drivers must define
306``Clock_driver_support_set_interrupt_affinity(online_processors)`` to set the
307interrupt affinity of the clock tick interrupt.
308
309Multiple Clock Driver Ticks Per Clock Tick
310==========================================
311
312In case the hardware needs more than one clock driver tick per clock tick (e.g.
313due to a limited range of the hardware timer), then this can be specified with
314the optional ``#define CLOCK_DRIVER_ISRS_PER_TICK`` and ``#define
315CLOCK_DRIVER_ISRS_PER_TICK_VALUE`` defines.  This is currently used only for
316x86 and it hopefully remains that way.
317
318.. code-block:: c
319
320    /* Enable multiple clock driver ticks per clock tick */
321    #define CLOCK_DRIVER_ISRS_PER_TICK 1
322
323    /* Specifiy the clock driver ticks per clock tick value */
324    #define CLOCK_DRIVER_ISRS_PER_TICK_VALUE 123
325
326    #include "../../../shared/clockdrv_shell.h"
327
328Clock Driver Ticks Counter
329==========================
330
331The :dfn:`Clock Driver Shell` provide a global variable that is simply a count
332of the number of clock driver interrupt service routines that have occurred.
333This information is valuable when debugging a system.  This variable is
334declared as follows:
335
336.. code-block:: c
337
338    volatile uint32_t Clock_driver_ticks;
Note: See TracBrowser for help on using the repository browser.