Changeset e7f40f0 in rtems-docs


Ignore:
Timestamp:
12/21/16 09:55:46 (6 years ago)
Author:
Sebastian Huber <sebastian.huber@…>
Branches:
5, am, master
Children:
2c780bf
Parents:
f517010
git-author:
Sebastian Huber <sebastian.huber@…> (12/21/16 09:55:46)
git-committer:
Sebastian Huber <sebastian.huber@…> (12/21/16 10:08:32)
Message:

Rework Clock Driver chapter

Update #2737.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • bsp-howto/clock.rst

    rf517010 re7f40f0  
    1818  Application C User's Guide* for more details.
    1919
    20 - An optional time counter to generate timestamps of the uptime and wall clock
    21   time.
     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.
    2223
    2324The clock driver is usually located in the :file:`clock` directory of the BSP.
    24 Clock drivers should use the :dfn:`Clock Driver Shell` available via the
    25 :file:`clockdrv_shell.h` include file.
    26 
    27 Clock Driver Shell
    28 ==================
    29 
    30 The :dfn:`Clock Driver Shell` include file defines the clock driver functions
    31 declared in ``#include <rtems/clockdrv.h>`` which are used by RTEMS
    32 configuration file ``#include <rtems/confdefs.h>``.  In case the application
    33 configuration defines ``#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER``,
    34 then the clock driver is registered and should provide its services to the
    35 operating system.  A hardware specific clock driver must provide some
    36 functions, defines and macros for the :dfn:`Clock Driver Shell` which are
    37 explained here step by step.  A clock driver file looks in general like this.
     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.
    3840
    3941.. code-block:: c
    4042
    4143    /*
    42      * A section with functions, defines and macros to provide hardware specific
     44     * A section with functions, defines and macros to provide hardware-specific
    4345     * functions for the Clock Driver Shell.
    4446     */
    45     #include "../../../shared/clockdrv_shell.h"
    46 
    47 Initialization
    48 --------------
     47
     48    #include "../../../shared/clockdrv_shell.h"
    4949
    5050Depending on the hardware capabilities one out of three clock driver variants
    5151must be selected.
    5252
    53 - The most basic clock driver provides only a periodic interrupt service
    54   routine which calls ``rtems_clock_tick()``.  The interval is determined by
    55   the application configuration via ``#define CONFIGURE_MICROSECONDS_PER_TICK``
    56   and can be obtained via ``rtems_configuration_get_microseconds_per_tick()``.
    57   The timestamp resolution is limited to the clock tick interval.
    58 
    59 - In case the hardware lacks support for a free running counter, then the
    60   module used for the clock tick may provide support for timestamps with a
    61   resolution below the clock tick interval.  For this so called simple
    62   timecounters can be used.
    63 
    64 - The desired variant uses a free running counter to provide accurate
    65   timestamps.  This variant is mandatory on SMP configurations.
    66 
    67 Clock Tick Only Variant
    68 ~~~~~~~~~~~~~~~~~~~~~~~
    69 
    70 .. code-block:: c
     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    }
    71100
    72101    static void some_support_initialize_hardware( void )
    73102    {
    74       /* Initialize hardware */
     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 );
    75127    }
    76128
    77129    #define Clock_driver_support_initialize_hardware() \
    78               some_support_initialize_hardware()
    79 
    80     /* Indicate that this clock driver lacks a proper timecounter in hardware */
    81 
    82     #define CLOCK_DRIVER_USE_DUMMY_TIMECOUNTER
     130      some_support_initialize_hardware()
    83131
    84132    #include "../../../shared/clockdrv_shell.h"
     
    86134Simple Timecounter Variant
    87135~~~~~~~~~~~~~~~~~~~~~~~~~~
     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>`_.
    88139
    89140.. code-block:: c
     
    119170    static void some_support_initialize_hardware( void )
    120171    {
    121       uint32_t frequency = 123456;
    122       uint64_t us_per_tick = rtems_configuration_get_microseconds_per_tick();
    123       uint32_t timecounter_ticks_per_clock_tick =
    124                              ( frequency * us_per_tick ) / 1000000;
     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;
    125180
    126181      /* Initialize hardware */
     182
    127183      rtems_timecounter_simple_install(
    128184        &some_tc,
    129         frequency,
    130         timecounter_ticks_per_clock_tick,
     185        counter_frequency_in_hz,
     186        counter_ticks_per_clock_tick,
    131187        some_tc_get_timecount
    132188      );
     
    134190
    135191    #define Clock_driver_support_initialize_hardware() \
    136               some_support_initialize_hardware()
     192      some_support_initialize_hardware()
    137193    #define Clock_driver_timecounter_tick() \
    138               some_tc_tick()
    139 
    140     #include "../../../shared/clockdrv_shell.h"
    141 
    142 Timecounter Variant
    143 ~~~~~~~~~~~~~~~~~~~
    144 
    145 This variant is preferred since it is the most efficient and yields the most
    146 accurate timestamps.  It is also mandatory on SMP configurations to obtain
    147 valid timestamps.  The hardware must provide a periodic interrupt to service
    148 the clock tick and a free running counter for the timecounter.  The free
    149 running counter must have a power of two period.  The ``tc_counter_mask`` must
    150 be initialized to the free running counter period minus one, e.g. for a 32-bit
    151 counter this is 0xffffffff.  The ``tc_get_timecount`` function must return the
    152 current counter value (the counter values must increase, so if the counter
    153 counts down, a conversion is necessary).  Use
    154 ``RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER`` for the ``tc_quality``.  Set
    155 ``tc_frequency`` to the frequency of the free running counter in Hz.  All other
    156 fields of the ``struct timecounter`` must be zero initialized.  Install the
    157 initialized timecounter via ``rtems_timecounter_install()``.
    158 
    159 .. code-block:: c
    160 
    161     #include <rtems/timecounter.h>
    162 
    163     static struct timecounter some_tc;
    164 
    165     static uint32_t some_tc_get_timecount( struct timecounter *tc )
    166     {
    167       some.free_running_counter;
    168     }
     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
    169205
    170206    static void some_support_initialize_hardware( void )
    171207    {
    172       uint64_t us_per_tick = rtems_configuration_get_microseconds_per_tick();
    173       uint32_t frequency = 123456;
    174 
    175       /*
    176        * The multiplication must be done in 64-bit arithmetic to avoid an integer
    177        * overflow on targets with a high enough counter frequency.
    178        */
    179       uint32_t interval = (uint32_t) ( ( frequency * us_per_tick ) / 1000000 );
    180 
    181       /*
    182        * Initialize hardware and set up a periodic interrupt for the configuration
    183        * based interval.
    184        */
    185       some_tc.tc_get_timecount = some_tc_get_timecount;
    186       some_tc.tc_counter_mask = 0xffffffff;
    187       some_tc.tc_frequency = frequency;
    188       some_tc.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER;
    189       rtems_timecounter_install( &some_tc );
     208      /* Initialize hardware */
    190209    }
    191210
    192211    #define Clock_driver_support_initialize_hardware() \
    193               some_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
    194217
    195218    #include "../../../shared/clockdrv_shell.h"
    196219
    197220Install Clock Tick Interrupt Service Routine
    198 --------------------------------------------
     221============================================
    199222
    200223The clock driver must provide a function to install the clock tick interrupt
     
    222245
    223246    #define Clock_driver_support_install_isr( isr, old ) \
    224               some_support_install_isr( isr )
     247      some_support_install_isr( isr )
    225248
    226249    #include "../../../shared/clockdrv_shell.h"
    227250
    228251Support At Tick
    229 ---------------
    230 
    231 The hardware specific support at tick is specified by
     252===============
     253
     254The hardware-specific support at tick is specified by
    232255``Clock_driver_support_at_tick()``.
    233256
     
    240263
    241264    #define Clock_driver_support_at_tick() \
    242               some_support_at_tick()
     265      some_support_at_tick()
    243266
    244267    #include "../../../shared/clockdrv_shell.h"
    245268
    246269System Shutdown Support
    247 -----------------------
     270=======================
    248271
    249272The :dfn:`Clock Driver Shell` provides the routine ``Clock_exit()`` that is
    250273scheduled to be run during system shutdown via the ``atexit()`` routine.  The
    251 hardware specific shutdown support is specified by
     274hardware-specific shutdown support is specified by
    252275``Clock_driver_support_shutdown_hardware()`` which is used by ``Clock_exit()``.
    253276It should disable the clock tick source if it was enabled.  This can be used to
     
    262285
    263286    #define Clock_driver_support_shutdown_hardware() \
    264               some_support_shutdown_hardware()
    265 
    266     #include "../../../shared/clockdrv_shell.h"
     287      some_support_shutdown_hardware()
     288
     289    #include "../../../shared/clockdrv_shell.h"
     290
     291SMP Support
     292===========
     293
     294In SMP configurations, the clock tick service must be executed for each
     295processor used by RTEMS.  By default, the clock tick interrupt must be
     296distributed to all processors used by RTEMS and each processor invokes the
     297clock tick service individually.  A clock driver may delegate all the work to
     298the boot processor.  It must define ``CLOCK_DRIVER_USE_ONLY_BOOT_PROCESSOR`` in
     299this case.
     300
     301Clock drivers must define
     302``Clock_driver_support_set_interrupt_affinity(online_processors)`` to set the
     303interrupt affinity of the clock tick interrupt.
    267304
    268305Multiple Clock Driver Ticks Per Clock Tick
    269 ------------------------------------------
     306==========================================
    270307
    271308In case the hardware needs more than one clock driver tick per clock tick (e.g.
     
    286323
    287324Clock Driver Ticks Counter
    288 --------------------------
     325==========================
    289326
    290327The :dfn:`Clock Driver Shell` provide a global variable that is simply a count
Note: See TracChangeset for help on using the changeset viewer.