summaryrefslogtreecommitdiffstats
path: root/bsp-howto/clock.rst
diff options
context:
space:
mode:
authorChris Johns <chrisj@rtems.org>2016-11-03 16:58:08 +1100
committerChris Johns <chrisj@rtems.org>2016-11-03 16:58:08 +1100
commit72a62ad88f82fe1ffee50024db4dd0f3fa5806f7 (patch)
tree6b0e527e67141f8126ba56b8a3c1eb90aeed5849 /bsp-howto/clock.rst
parentwaf: Use separate doctrees so avoid sphinx clashes. (diff)
downloadrtems-docs-72a62ad88f82fe1ffee50024db4dd0f3fa5806f7.tar.bz2
Rename all manuals with an _ to have a -. It helps released naming of files.
Diffstat (limited to 'bsp-howto/clock.rst')
-rw-r--r--bsp-howto/clock.rst297
1 files changed, 297 insertions, 0 deletions
diff --git a/bsp-howto/clock.rst b/bsp-howto/clock.rst
new file mode 100644
index 0000000..38b6d62
--- /dev/null
+++ b/bsp-howto/clock.rst
@@ -0,0 +1,297 @@
+.. comment SPDX-License-Identifier: CC-BY-SA-4.0
+
+.. COMMENT: COPYRIGHT (c) 1988-2002.
+.. COMMENT: On-Line Applications Research Corporation (OAR).
+.. COMMENT: All rights reserved.
+
+Clock Driver
+############
+
+Introduction
+============
+
+The purpose of the clock driver is to provide two services for the operating
+system.
+
+- A steady time basis to the kernel, so that the RTEMS primitives that need a
+ 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.
+
+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.
+
+.. code-block:: c
+
+ /*
+ * A section with functions, defines and macros to provide hardware specific
+ * functions for the Clock Driver Shell.
+ */
+ #include "../../../shared/clockdrv_shell.h"
+
+Initialization
+--------------
+
+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.
+
+- 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.
+
+- The desired variant uses a free running counter to provide accurate
+ timestamps. This variant is mandatory on SMP configurations.
+
+Clock Tick Only Variant
+~~~~~~~~~~~~~~~~~~~~~~~
+
+.. code-block:: c
+
+ static void some_support_initialize_hardware( void )
+ {
+ /* Initialize hardware */
+ }
+
+ #define Clock_driver_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"
+
+Simple Timecounter Variant
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. code-block:: c
+
+ #include <rtems/timecounter.h>
+
+ static rtems_timecounter_simple some_tc;
+
+ static uint32_t some_tc_get( rtems_timecounter_simple *tc )
+ {
+ return some.counter;
+ }
+
+ static bool some_tc_is_pending( rtems_timecounter_simple *tc )
+ {
+ return some.is_pending;
+ }
+
+ static uint32_t some_tc_get_timecount( struct timecounter *tc )
+ {
+ return rtems_timecounter_simple_downcounter_get(
+ tc,
+ some_tc_get,
+ some_tc_is_pending
+ );
+ }
+
+ static void some_tc_tick( void )
+ {
+ rtems_timecounter_simple_downcounter_tick( &some_tc, some_tc_get );
+ }
+
+ 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;
+
+ /* Initialize hardware */
+ rtems_timecounter_simple_install(
+ &some_tc,
+ frequency,
+ timecounter_ticks_per_clock_tick,
+ some_tc_get_timecount
+ );
+ }
+
+ #define Clock_driver_support_initialize_hardware() \
+ some_support_initialize_hardware()
+ #define Clock_driver_timecounter_tick() \
+ some_tc_tick()
+
+ #include "../../../shared/clockdrv_shell.h"
+
+Timecounter 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()``.
+
+.. 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 );
+ }
+
+ #define Clock_driver_support_initialize_hardware() \
+ some_support_initialize_hardware()
+
+ #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()``.
+
+.. code-block:: c
+
+ #include <bsp/irq.h>
+ #include <bsp/fatal.h>
+
+ static void some_support_install_isr( rtems_interrupt_handler isr )
+ {
+ rtems_status_code sc;
+ sc = rtems_interrupt_handler_install(
+ SOME_IRQ,
+ "Clock",
+ RTEMS_INTERRUPT_UNIQUE,
+ isr,
+ NULL
+ );
+ if ( sc != RTEMS_SUCCESSFUL ) {
+ bsp_fatal( SOME_FATAL_IRQ_INSTALL );
+ }
+ }
+
+ #define Clock_driver_support_install_isr( isr, old ) \
+ some_support_install_isr( isr )
+
+ #include "../../../shared/clockdrv_shell.h"
+
+Support At Tick
+---------------
+
+The hardware specific support at tick is specified by
+``Clock_driver_support_at_tick()``.
+
+.. code-block:: c
+
+ static void some_support_at_tick( void )
+ {
+ /* Clear interrupt */
+ }
+
+ #define Clock_driver_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
+``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.
+
+.. code-block:: c
+
+ static void some_support_shutdown_hardware( void )
+ {
+ /* Shutdown hardware */
+ }
+
+ #define Clock_driver_support_shutdown_hardware() \
+ some_support_shutdown_hardware()
+
+ #include "../../../shared/clockdrv_shell.h"
+
+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
+the optional ``#define CLOCK_DRIVER_ISRS_PER_TICK`` and ``#define
+CLOCK_DRIVER_ISRS_PER_TICK_VALUE`` defines. This is currently used only for
+x86 and it hopefully remains that way.
+
+.. code-block:: c
+
+ /* Enable multiple clock driver ticks per clock tick */
+ #define CLOCK_DRIVER_ISRS_PER_TICK 1
+
+ /* Specifiy the clock driver ticks per clock tick value */
+ #define CLOCK_DRIVER_ISRS_PER_TICK_VALUE 123
+
+ #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.
+This information is valuable when debugging a system. This variable is
+declared as follows:
+
+.. code-block:: c
+
+ volatile uint32_t Clock_driver_ticks;