[rtems-docs commit] Rework Clock Driver chapter

Sebastian Huber sebh at rtems.org
Wed Dec 21 10:08:51 UTC 2016


Module:    rtems-docs
Branch:    master
Commit:    e7f40f04d39d3d87d30b50a02bab90a72a9dae61
Changeset: http://git.rtems.org/rtems-docs/commit/?id=e7f40f04d39d3d87d30b50a02bab90a72a9dae61

Author:    Sebastian Huber <sebastian.huber at embedded-brains.de>
Date:      Wed Dec 21 10:55:46 2016 +0100

Rework Clock Driver chapter

Update #2737.

---

 bsp-howto/clock.rst | 237 ++++++++++++++++++++++++++++++----------------------
 1 file changed, 137 insertions(+), 100 deletions(-)

diff --git a/bsp-howto/clock.rst b/bsp-howto/clock.rst
index f1d4c3b..55c94ac 100644
--- a/bsp-howto/clock.rst
+++ b/bsp-howto/clock.rst
@@ -17,75 +17,126 @@ system.
   clock tick work properly.  See the *Clock Manager* chapter of the *RTEMS
   Application C User's Guide* for more details.
 
-- An optional time counter to generate timestamps of the uptime and wall clock
-  time.
+- An optional `timecounter <http://www.freebsd.dk/pubs/timecounter.pdf>`_ to
+  provide timestamps of the uptime and wall clock time with higher resolution
+  than the clock tick.
 
 The clock driver is usually located in the :file:`clock` directory of the BSP.
-Clock drivers should use the :dfn:`Clock Driver Shell` available via the
-:file:`clockdrv_shell.h` include file.
-
-Clock Driver Shell
-==================
-
-The :dfn:`Clock Driver Shell` include file defines the clock driver functions
-declared in ``#include <rtems/clockdrv.h>`` which are used by RTEMS
-configuration file ``#include <rtems/confdefs.h>``.  In case the application
-configuration defines ``#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER``,
-then the clock driver is registered and should provide its services to the
-operating system.  A hardware specific clock driver must provide some
-functions, defines and macros for the :dfn:`Clock Driver Shell` which are
-explained here step by step.  A clock driver file looks in general like this.
+Clock drivers must use the :dfn:`Clock Driver Shell` available via the
+`clockdrv_shell.h <https://git.rtems.org/rtems/tree/c/src/lib/libbsp/shared/clockdrv_shell.h>`_
+include file.  This include file is not a normal header file and instead
+defines the clock driver functions declared in ``#include <rtems/clockdrv.h>``
+which are used by RTEMS configuration file ``#include <rtems/confdefs.h>``.  In
+case the application configuration defines
+``#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER``, then the clock driver is
+registered and should provide its services to the operating system.  The clock
+tick interval is determined by the application configuration via
+``#define CONFIGURE_MICROSECONDS_PER_TICK`` and can be obtained via
+``rtems_configuration_get_microseconds_per_tick()``.
+
+A hardware-specific clock driver must provide some functions, defines and
+macros for the :dfn:`Clock Driver Shell` which are explained here step by step.
+A clock driver file looks in general like this.
 
 .. code-block:: c
 
     /*
-     * A section with functions, defines and macros to provide hardware specific
+     * A section with functions, defines and macros to provide hardware-specific
      * functions for the Clock Driver Shell.
      */
-    #include "../../../shared/clockdrv_shell.h"
 
-Initialization
---------------
+    #include "../../../shared/clockdrv_shell.h"
 
 Depending on the hardware capabilities one out of three clock driver variants
 must be selected.
 
-- The most basic clock driver provides only a periodic interrupt service
-  routine which calls ``rtems_clock_tick()``.  The interval is determined by
-  the application configuration via ``#define CONFIGURE_MICROSECONDS_PER_TICK``
-  and can be obtained via ``rtems_configuration_get_microseconds_per_tick()``.
-  The timestamp resolution is limited to the clock tick interval.
+Timecounter
+    The variant which provides all features needs a free running hardware
+    counter and a periodic clock tick interrupt.  This variant is mandatory in
+    SMP configurations.
 
-- In case the hardware lacks support for a free running counter, then the
-  module used for the clock tick may provide support for timestamps with a
-  resolution below the clock tick interval.  For this so called simple
-  timecounters can be used.
+Simple Timecounter
+    A simple timecounter can be used if the hardware provides no free running
+    hardware counter and only a periodic hardware counter synchronous to the
+    clock tick interrupt is available.
 
-- The desired variant uses a free running counter to provide accurate
-  timestamps.  This variant is mandatory on SMP configurations.
+Clock Tick Only
+    The most basic clock driver provides only a periodic clock tick interrupt.
+    The timestamp resolution is limited to the clock tick interval.
 
-Clock Tick Only Variant
-~~~~~~~~~~~~~~~~~~~~~~~
+Initialization
+==============
+
+Timecounter Variant
+~~~~~~~~~~~~~~~~~~~
+
+This variant is preferred since it is the most efficient and yields the most
+accurate timestamps.  It is also mandatory in SMP configurations to obtain
+valid timestamps.  The hardware must provide a periodic interrupt to service
+the clock tick and a free running counter for the timecounter.  The free
+running counter must have a power of two period.  The ``tc_counter_mask`` must
+be initialized to the free running counter period minus one, e.g. for a 17-bit
+counter this is ``0x0001ffff``.  The ``tc_get_timecount`` function must return
+the current counter value (the counter values must increase, so if the counter
+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 other
+fields of the ``struct timecounter`` must be zero initialized.  Install the
+initialized timecounter via ``rtems_timecounter_install()``.
+
+For an example see the `QorIQ clock driver
+<https://git.rtems.org/rtems/tree/c/src/lib/libbsp/powerpc/qoriq/clock/clock-config.c>`_.
 
 .. code-block:: c
 
-    static void some_support_initialize_hardware( void )
+    #include <rtems/timecounter.h>
+
+    static struct timecounter some_tc;
+
+    static uint32_t some_tc_get_timecount( struct timecounter *tc )
     {
-      /* Initialize hardware */
+      some.free_running_counter;
     }
 
-    #define Clock_driver_support_initialize_hardware() \
-              some_support_initialize_hardware()
+    static void some_support_initialize_hardware( void )
+    {
+      uint64_t us_per_tick;
+      uint32_t counter_frequency_in_hz;
+      uint32_t counter_ticks_per_clock_tick;
 
-    /* Indicate that this clock driver lacks a proper timecounter in hardware */
+      us_per_tick = rtems_configuration_get_microseconds_per_tick();
+      counter_frequency_in_hz = some_tc_get_frequency();
 
-    #define CLOCK_DRIVER_USE_DUMMY_TIMECOUNTER
+      /*
+       * The multiplication must be done in 64-bit arithmetic to avoid an integer
+       * overflow on targets with a high enough counter frequency.
+       */
+      counter_ticks_per_clock_tick =
+        (uint32_t) ( counter_frequency_in_hz * us_per_tick ) / 1000000;
+
+      /*
+       * Initialize hardware and set up a periodic interrupt for the configuration
+       * based counter ticks per clock tick.
+       */
+
+      some_tc.tc_get_timecount = some_tc_get_timecount;
+      some_tc.tc_counter_mask = 0xffffffff;
+      some_tc.tc_frequency = frequency;
+      some_tc.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER;
+      rtems_timecounter_install( &some_tc );
+    }
+
+    #define Clock_driver_support_initialize_hardware() \
+      some_support_initialize_hardware()
 
     #include "../../../shared/clockdrv_shell.h"
 
 Simple Timecounter Variant
 ~~~~~~~~~~~~~~~~~~~~~~~~~~
 
+For an example see the `ERC32 clock driver
+<https://git.rtems.org/rtems/tree/c/src/lib/libbsp/sparc/erc32/clock/ckinit.c>`_.
+
 .. code-block:: c
 
     #include <rtems/timecounter.h>
@@ -118,84 +169,56 @@ Simple Timecounter Variant
 
     static void some_support_initialize_hardware( void )
     {
-      uint32_t frequency = 123456;
-      uint64_t us_per_tick = rtems_configuration_get_microseconds_per_tick();
-      uint32_t timecounter_ticks_per_clock_tick =
-                             ( frequency * us_per_tick ) / 1000000;
+      uint64_t us_per_tick;
+      uint32_t counter_frequency_in_hz;
+      uint32_t counter_ticks_per_clock_tick;
+
+      us_per_tick = rtems_configuration_get_microseconds_per_tick();
+      counter_frequency_in_hz = some_tc_get_frequency();
+      counter_ticks_per_clock_tick =
+        (uint32_t) ( counter_frequency_in_hz * us_per_tick ) / 1000000;
 
       /* Initialize hardware */
+
       rtems_timecounter_simple_install(
         &some_tc,
-        frequency,
-        timecounter_ticks_per_clock_tick,
+        counter_frequency_in_hz,
+        counter_ticks_per_clock_tick,
         some_tc_get_timecount
       );
     }
 
     #define Clock_driver_support_initialize_hardware() \
-              some_support_initialize_hardware()
+      some_support_initialize_hardware()
     #define Clock_driver_timecounter_tick() \
-              some_tc_tick()
+      some_tc_tick()
 
     #include "../../../shared/clockdrv_shell.h"
 
-Timecounter Variant
-~~~~~~~~~~~~~~~~~~~
+Clock Tick Only Variant
+~~~~~~~~~~~~~~~~~~~~~~~
 
-This variant is preferred since it is the most efficient and yields the most
-accurate timestamps.  It is also mandatory on SMP configurations to obtain
-valid timestamps.  The hardware must provide a periodic interrupt to service
-the clock tick and a free running counter for the timecounter.  The free
-running counter must have a power of two period.  The ``tc_counter_mask`` must
-be initialized to the free running counter period minus one, e.g. for a 32-bit
-counter this is 0xffffffff.  The ``tc_get_timecount`` function must return the
-current counter value (the counter values must increase, so if the counter
-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 other
-fields of the ``struct timecounter`` must be zero initialized.  Install the
-initialized timecounter via ``rtems_timecounter_install()``.
+For an example see the `Motrola 68360 clock driver
+<https://git.rtems.org/rtems/tree/c/src/lib/libbsp/m68k/gen68360/clock/clock.c>`_.
 
 .. code-block:: c
 
-    #include <rtems/timecounter.h>
-
-    static struct timecounter some_tc;
-
-    static uint32_t some_tc_get_timecount( struct timecounter *tc )
-    {
-      some.free_running_counter;
-    }
-
     static void some_support_initialize_hardware( void )
     {
-      uint64_t us_per_tick = rtems_configuration_get_microseconds_per_tick();
-      uint32_t frequency = 123456;
-
-      /*
-       * The multiplication must be done in 64-bit arithmetic to avoid an integer
-       * overflow on targets with a high enough counter frequency.
-       */
-      uint32_t interval = (uint32_t) ( ( frequency * us_per_tick ) / 1000000 );
-
-      /*
-       * Initialize hardware and set up a periodic interrupt for the configuration
-       * based interval.
-       */
-      some_tc.tc_get_timecount = some_tc_get_timecount;
-      some_tc.tc_counter_mask = 0xffffffff;
-      some_tc.tc_frequency = frequency;
-      some_tc.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER;
-      rtems_timecounter_install( &some_tc );
+      /* Initialize hardware */
     }
 
     #define Clock_driver_support_initialize_hardware() \
-              some_support_initialize_hardware()
+      some_support_initialize_hardware()
+
+    /* Indicate that this clock driver lacks a proper timecounter in hardware */
+
+    #define CLOCK_DRIVER_USE_DUMMY_TIMECOUNTER
 
     #include "../../../shared/clockdrv_shell.h"
 
 Install Clock Tick Interrupt Service Routine
---------------------------------------------
+============================================
 
 The clock driver must provide a function to install the clock tick interrupt
 service routine via ``Clock_driver_support_install_isr()``.
@@ -221,14 +244,14 @@ service routine via ``Clock_driver_support_install_isr()``.
     }
 
     #define Clock_driver_support_install_isr( isr, old ) \
-              some_support_install_isr( isr )
+      some_support_install_isr( isr )
 
     #include "../../../shared/clockdrv_shell.h"
 
 Support At Tick
----------------
+===============
 
-The hardware specific support at tick is specified by
+The hardware-specific support at tick is specified by
 ``Clock_driver_support_at_tick()``.
 
 .. code-block:: c
@@ -239,16 +262,16 @@ The hardware specific support at tick is specified by
     }
 
     #define Clock_driver_support_at_tick() \
-              some_support_at_tick()
+      some_support_at_tick()
 
     #include "../../../shared/clockdrv_shell.h"
 
 System Shutdown Support
------------------------
+=======================
 
 The :dfn:`Clock Driver Shell` provides the routine ``Clock_exit()`` that is
 scheduled to be run during system shutdown via the ``atexit()`` routine.  The
-hardware specific shutdown support is specified by
+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 enabled.  This can be used to
 prevent clock ticks after the system is shutdown.
@@ -261,12 +284,26 @@ prevent clock ticks after the system is shutdown.
     }
 
     #define Clock_driver_support_shutdown_hardware() \
-              some_support_shutdown_hardware()
+      some_support_shutdown_hardware()
 
     #include "../../../shared/clockdrv_shell.h"
 
+SMP Support
+===========
+
+In SMP configurations, the clock tick service must be executed for each
+processor used by RTEMS.  By default, the clock tick interrupt must be
+distributed to all processors used by RTEMS and each processor invokes the
+clock tick service individually.  A clock driver may delegate all the work to
+the boot processor.  It must define ``CLOCK_DRIVER_USE_ONLY_BOOT_PROCESSOR`` in
+this case.
+
+Clock drivers must define
+``Clock_driver_support_set_interrupt_affinity(online_processors)`` to set the
+interrupt affinity of the clock tick interrupt.
+
 Multiple Clock Driver Ticks Per Clock Tick
-------------------------------------------
+==========================================
 
 In case the hardware needs more than one clock driver tick per clock tick (e.g.
 due to a limited range of the hardware timer), then this can be specified with
@@ -285,7 +322,7 @@ x86 and it hopefully remains that way.
     #include "../../../shared/clockdrv_shell.h"
 
 Clock Driver Ticks Counter
---------------------------
+==========================
 
 The :dfn:`Clock Driver Shell` provide a global variable that is simply a count
 of the number of clock driver interrupt service routines that have occurred.




More information about the vc mailing list