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

5am
Last change on this file since 27515ec was 27515ec, checked in by Sebastian Huber <sebastian.huber@…>, on 09/18/17 at 06:26:50

bsp-howto: Clock_driver_support_install_isr()

Close #3139.

  • Property mode set to 100644
File size: 11.0 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 may provide a function to install the clock tick interrupt
224service routine via ``Clock_driver_support_install_isr()``.  The clock tick
225interrupt service routine is passed as the one and only parameter to this
226macro.  The default implementation will do nothing.
227
228.. code-block:: c
229
230    #include <bsp/irq.h>
231    #include <bsp/fatal.h>
232
233    static void some_support_install_isr( rtems_interrupt_handler isr )
234    {
235      rtems_status_code sc;
236      sc = rtems_interrupt_handler_install(
237        SOME_IRQ,
238        "Clock",
239        RTEMS_INTERRUPT_UNIQUE,
240        isr,
241        NULL
242      );
243      if ( sc != RTEMS_SUCCESSFUL ) {
244        bsp_fatal( SOME_FATAL_IRQ_INSTALL );
245      }
246    }
247
248    #define Clock_driver_support_install_isr( isr ) \
249      some_support_install_isr( isr )
250
251    #include "../../../shared/clockdrv_shell.h"
252
253Support At Tick
254===============
255
256The hardware-specific support at tick is specified by
257``Clock_driver_support_at_tick()``.
258
259.. code-block:: c
260
261    static void some_support_at_tick( void )
262    {
263      /* Clear interrupt */
264    }
265
266    #define Clock_driver_support_at_tick() \
267      some_support_at_tick()
268
269    #include "../../../shared/clockdrv_shell.h"
270
271System Shutdown Support
272=======================
273
274Optionally, the :dfn:`Clock Driver Shell` provides the routine ``Clock_exit()``
275that is scheduled to be run during system shutdown via the ``atexit()``
276routine.  The hardware-specific shutdown support is specified by
277``Clock_driver_support_shutdown_hardware()`` which is used by ``Clock_exit()``.
278It should disable the clock tick source if it was enabled.  This can be used to
279prevent clock ticks after the system is shutdown.  The
280``Clock_driver_support_shutdown_hardware()`` must be provided as a macro.  In
281case this macro is undefined, then the shutdown support is disabled.  This is
282useful for example on memory constrained systems to avoid the ``atexit()``
283overhead.
284
285.. code-block:: c
286
287    static void some_support_shutdown_hardware( void )
288    {
289      /* Shutdown hardware */
290    }
291
292    #define Clock_driver_support_shutdown_hardware() \
293      some_support_shutdown_hardware()
294
295    #include "../../../shared/clockdrv_shell.h"
296
297SMP Support
298===========
299
300In SMP configurations, the clock tick service must be executed for each
301processor used by RTEMS.  By default, the clock tick interrupt must be
302distributed to all processors used by RTEMS and each processor invokes the
303clock tick service individually.  A clock driver may delegate all the work to
304the boot processor.  It must define ``CLOCK_DRIVER_USE_ONLY_BOOT_PROCESSOR`` in
305this case.
306
307Clock drivers must define
308``Clock_driver_support_set_interrupt_affinity(online_processors)`` to set the
309interrupt affinity of the clock tick interrupt.
310
311Multiple Clock Driver Ticks Per Clock Tick
312==========================================
313
314In case the hardware needs more than one clock driver tick per clock tick (e.g.
315due to a limited range of the hardware timer), then this can be specified with
316the optional ``#define CLOCK_DRIVER_ISRS_PER_TICK`` and ``#define
317CLOCK_DRIVER_ISRS_PER_TICK_VALUE`` defines.  This is currently used only for
318x86 and it hopefully remains that way.
319
320.. code-block:: c
321
322    /* Enable multiple clock driver ticks per clock tick */
323    #define CLOCK_DRIVER_ISRS_PER_TICK 1
324
325    /* Specifiy the clock driver ticks per clock tick value */
326    #define CLOCK_DRIVER_ISRS_PER_TICK_VALUE 123
327
328    #include "../../../shared/clockdrv_shell.h"
329
330Clock Driver Ticks Counter
331==========================
332
333The :dfn:`Clock Driver Shell` provide a global variable that is simply a count
334of the number of clock driver interrupt service routines that have occurred.
335This information is valuable when debugging a system.  This variable is
336declared as follows:
337
338.. code-block:: c
339
340    volatile uint32_t Clock_driver_ticks;
Note: See TracBrowser for help on using the repository browser.