Changeset e7f40f0 in rtems-docs
- Timestamp:
- 12/21/16 09:55:46 (7 years ago)
- Branches:
- 5, 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)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
bsp-howto/clock.rst
rf517010 re7f40f0 18 18 Application C User's Guide* for more details. 19 19 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. 22 23 23 24 The 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. 25 Clock 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>`_ 27 include file. This include file is not a normal header file and instead 28 defines the clock driver functions declared in ``#include <rtems/clockdrv.h>`` 29 which are used by RTEMS configuration file ``#include <rtems/confdefs.h>``. In 30 case the application configuration defines 31 ``#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER``, then the clock driver is 32 registered and should provide its services to the operating system. The clock 33 tick 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 37 A hardware-specific clock driver must provide some functions, defines and 38 macros for the :dfn:`Clock Driver Shell` which are explained here step by step. 39 A clock driver file looks in general like this. 38 40 39 41 .. code-block:: c 40 42 41 43 /* 42 * A section with functions, defines and macros to provide hardware 44 * A section with functions, defines and macros to provide hardware-specific 43 45 * functions for the Clock Driver Shell. 44 46 */ 45 #include "../../../shared/clockdrv_shell.h" 46 47 Initialization 48 -------------- 47 48 #include "../../../shared/clockdrv_shell.h" 49 49 50 50 Depending on the hardware capabilities one out of three clock driver variants 51 51 must be selected. 52 52 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 53 Timecounter 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 58 Simple 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 63 Clock 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 67 Initialization 68 ============== 69 70 Timecounter Variant 71 ~~~~~~~~~~~~~~~~~~~ 72 73 This variant is preferred since it is the most efficient and yields the most 74 accurate timestamps. It is also mandatory in SMP configurations to obtain 75 valid timestamps. The hardware must provide a periodic interrupt to service 76 the clock tick and a free running counter for the timecounter. The free 77 running counter must have a power of two period. The ``tc_counter_mask`` must 78 be initialized to the free running counter period minus one, e.g. for a 17-bit 79 counter this is ``0x0001ffff``. The ``tc_get_timecount`` function must return 80 the current counter value (the counter values must increase, so if the counter 81 counts 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 84 fields of the ``struct timecounter`` must be zero initialized. Install the 85 initialized timecounter via ``rtems_timecounter_install()``. 86 87 For 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 } 71 100 72 101 static void some_support_initialize_hardware( void ) 73 102 { 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 ); 75 127 } 76 128 77 129 #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() 83 131 84 132 #include "../../../shared/clockdrv_shell.h" … … 86 134 Simple Timecounter Variant 87 135 ~~~~~~~~~~~~~~~~~~~~~~~~~~ 136 137 For an example see the `ERC32 clock driver 138 <https://git.rtems.org/rtems/tree/c/src/lib/libbsp/sparc/erc32/clock/ckinit.c>`_. 88 139 89 140 .. code-block:: c … … 119 170 static void some_support_initialize_hardware( void ) 120 171 { 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; 125 180 126 181 /* Initialize hardware */ 182 127 183 rtems_timecounter_simple_install( 128 184 &some_tc, 129 frequency,130 timecounter_ticks_per_clock_tick,185 counter_frequency_in_hz, 186 counter_ticks_per_clock_tick, 131 187 some_tc_get_timecount 132 188 ); … … 134 190 135 191 #define Clock_driver_support_initialize_hardware() \ 136 192 some_support_initialize_hardware() 137 193 #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 198 Clock Tick Only Variant 199 ~~~~~~~~~~~~~~~~~~~~~~~ 200 201 For 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 169 205 170 206 static void some_support_initialize_hardware( void ) 171 207 { 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 */ 190 209 } 191 210 192 211 #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 194 217 195 218 #include "../../../shared/clockdrv_shell.h" 196 219 197 220 Install Clock Tick Interrupt Service Routine 198 -------------------------------------------- 221 ============================================ 199 222 200 223 The clock driver must provide a function to install the clock tick interrupt … … 222 245 223 246 #define Clock_driver_support_install_isr( isr, old ) \ 224 247 some_support_install_isr( isr ) 225 248 226 249 #include "../../../shared/clockdrv_shell.h" 227 250 228 251 Support At Tick 229 --------------- 230 231 The hardware 252 =============== 253 254 The hardware-specific support at tick is specified by 232 255 ``Clock_driver_support_at_tick()``. 233 256 … … 240 263 241 264 #define Clock_driver_support_at_tick() \ 242 265 some_support_at_tick() 243 266 244 267 #include "../../../shared/clockdrv_shell.h" 245 268 246 269 System Shutdown Support 247 ----------------------- 270 ======================= 248 271 249 272 The :dfn:`Clock Driver Shell` provides the routine ``Clock_exit()`` that is 250 273 scheduled to be run during system shutdown via the ``atexit()`` routine. The 251 hardware 274 hardware-specific shutdown support is specified by 252 275 ``Clock_driver_support_shutdown_hardware()`` which is used by ``Clock_exit()``. 253 276 It should disable the clock tick source if it was enabled. This can be used to … … 262 285 263 286 #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 291 SMP Support 292 =========== 293 294 In SMP configurations, the clock tick service must be executed for each 295 processor used by RTEMS. By default, the clock tick interrupt must be 296 distributed to all processors used by RTEMS and each processor invokes the 297 clock tick service individually. A clock driver may delegate all the work to 298 the boot processor. It must define ``CLOCK_DRIVER_USE_ONLY_BOOT_PROCESSOR`` in 299 this case. 300 301 Clock drivers must define 302 ``Clock_driver_support_set_interrupt_affinity(online_processors)`` to set the 303 interrupt affinity of the clock tick interrupt. 267 304 268 305 Multiple Clock Driver Ticks Per Clock Tick 269 ------------------------------------------ 306 ========================================== 270 307 271 308 In case the hardware needs more than one clock driver tick per clock tick (e.g. … … 286 323 287 324 Clock Driver Ticks Counter 288 -------------------------- 325 ========================== 289 326 290 327 The :dfn:`Clock Driver Shell` provide a global variable that is simply a count
Note: See TracChangeset
for help on using the changeset viewer.