- Timestamp:
- 04/20/15 09:08:22 (9 years ago)
- Branches:
- 4.11, 5, master
- Children:
- 7cd2484
- Parents:
- cc693845
- git-author:
- Alexander Krutwig <alexander.krutwig@…> (04/20/15 09:08:22)
- git-committer:
- Sebastian Huber <sebastian.huber@…> (05/20/15 06:40:29)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
doc/bsp_howto/clock.t
rcc693845 r31be416 8 8 @section Introduction 9 9 10 The purpose of the clock driver is to provide a steady time 11 basis to the kernel, so that the RTEMS primitives that need 12 a clock tick work properly. See the @code{Clock Manager} chapter 13 of the @b{RTEMS Application C User's Guide} for more details. 14 15 The clock driver is located in the @code{clock} directory of the BSP. 16 17 @section Clock Driver Global Variables 18 19 This section describes the global variables expected to be provided by 20 this driver. 21 22 @subsection Ticks Counter 23 24 Most of the clock device drivers provide a global variable 25 that is simply a count of the number of clock driver interrupt service 26 routines that have occured. This information is valuable when debugging 27 a system. This variable is declared as follows: 10 The purpose of the clock driver is to provide two services for the operating 11 system. 12 @itemize @bullet 13 @item A steady time basis to the kernel, so that the RTEMS primitives that need 14 a clock tick work properly. See the @cite{Clock Manager} chapter of the 15 @cite{RTEMS Application C User's Guide} for more details. 16 @item An optional time counter to generate timestamps of the uptime and wall 17 clock time. 18 @end itemize 19 20 The clock driver is usually located in the @file{clock} directory of the BSP. 21 Clock drivers should use the @dfn{Clock Driver Shell} available via the 22 @file{clockdrv_shell.h} include file. 23 24 @section Clock Driver Shell 25 26 The @dfn{Clock Driver Shell} include file defines the clock driver functions 27 declared in @code{#include <rtems/clockdrv.h>} which are used by RTEMS 28 configuration file @code{#include <rtems/confdefs.h>}. In case the application 29 configuration defines @code{#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER}, 30 then the clock driver is registered and should provide its services to the 31 operating system. A hardware specific clock driver must provide some 32 functions, defines and macros for the @dfn{Clock Driver Shell} which are 33 explained here step by step. A clock driver file looks in general like this. 34 35 @example 36 /* 37 * A section with functions, defines and macros to provide hardware specific 38 * functions for the Clock Driver Shell. 39 */ 40 41 #include "../../../shared/clockdrv_shell.h" 42 @end example 43 44 @subsection Initialization 45 46 Depending on the hardware capabilities one out of three clock driver variants 47 must be selected. 48 @itemize @bullet 49 @item The most basic clock driver provides only a periodic interrupt service 50 routine which calls @code{rtems_clock_tick()}. The interval is determined by 51 the application configuration via @code{#define 52 CONFIGURE_MICROSECONDS_PER_TICK} and can be obtained via 53 @code{rtems_configuration_get_microseconds_per_tick()}. The timestamp 54 resolution is limited to the clock tick interval. 55 @item In case the hardware lacks support for a free running counter, then the 56 module used for the clock tick may provide support for timestamps with a 57 resolution below the clock tick interval. For this so called simple 58 timecounters can be used. 59 @item The desired variant uses a free running counter to provide accurate 60 timestamps. This variant is mandatory on SMP configurations. 61 @end itemize 62 63 @subsubsection Clock Tick Only Variant 64 65 @example 66 static void some_support_initialize_hardware( void ) 67 @{ 68 /* Initialize hardware */ 69 @} 70 71 #define Clock_driver_support_initialize_hardware() \ 72 some_support_initialize_hardware() 73 74 /* Indicate that this clock driver lacks a proper timecounter in hardware */ 75 #define CLOCK_DRIVER_USE_DUMMY_TIMECOUNTER 76 77 #include "../../../shared/clockdrv_shell.h" 78 @end example 79 80 @subsubsection Simple Timecounter Variant 81 82 @example 83 #include <rtems/timecounter.h> 84 85 static rtems_timecounter_simple some_tc; 86 87 static uint32_t some_tc_get( rtems_timecounter_simple *tc ) 88 @{ 89 return some.counter; 90 @} 91 92 static bool some_tc_is_pending( rtems_timecounter_simple *tc ) 93 @{ 94 return some.is_pending; 95 @} 96 97 static uint32_t some_tc_get_timecount( struct timecounter *tc ) 98 @{ 99 return rtems_timecounter_simple_downcounter_get( 100 tc, 101 some_tc_get, 102 some_tc_is_pending 103 ); 104 @} 105 106 static void some_tc_tick( void ) 107 @{ 108 rtems_timecounter_simple_downcounter_tick( &some_tc, some_tc_get ); 109 @} 110 111 static void some_support_initialize_hardware( void ) 112 @{ 113 uint32_t frequency = 123456; 114 uint64_t us_per_tick = rtems_configuration_get_microseconds_per_tick(); 115 uint32_t timecounter_ticks_per_clock_tick = 116 ( frequency * us_per_tick ) / 1000000; 117 118 /* Initialize hardware */ 119 120 rtems_timecounter_simple_install( 121 &some_tc, 122 frequency, 123 timecounter_ticks_per_clock_tick, 124 some_tc_get_timecount 125 ); 126 @} 127 128 #define Clock_driver_support_initialize_hardware() \ 129 some_support_initialize_hardware() 130 131 #define Clock_driver_timecounter_tick() \ 132 some_tc_tick() 133 134 #include "../../../shared/clockdrv_shell.h" 135 @end example 136 137 @subsubsection Timecounter Variant 138 139 This variant is preferred since it is the most efficient and yields the most 140 accurate timestamps. It is also mandatory on SMP configurations to obtain 141 valid timestamps. The hardware must provide a periodic interrupt to service 142 the clock tick and a free running counter for the timecounter. The free 143 running counter must have a power of two period. The @code{tc_counter_mask} 144 must be initialized to the free running counter period minus one, e.g. for a 145 32-bit counter this is 0xffffffff. The @code{tc_get_timecount} function must 146 return the current counter value (the counter values must increase, so if the 147 counter counts down, a conversion is necessary). Use 148 @code{RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER} for the @code{tc_quality}. Set 149 @code{tc_frequency} to the frequency of the free running counter in Hz. All 150 other fields of the @code{struct timecounter} must be zero initialized. 151 Install the initialized timecounter via @code{rtems_timecounter_install()}. 152 153 @example 154 #include <rtems/timecounter.h> 155 156 static struct timecounter some_tc; 157 158 static uint32_t some_tc_get_timecount( struct timecounter *tc ) 159 @{ 160 some.free_running_counter; 161 @} 162 163 static void some_support_initialize_hardware( void ) 164 @{ 165 uint64_t us_per_tick = rtems_configuration_get_microseconds_per_tick(); 166 uint32_t frequency = 123456; 167 168 /* 169 * The multiplication must be done in 64-bit arithmetic to avoid an integer 170 * overflow on targets with a high enough counter frequency. 171 */ 172 uint32_t interval = (uint32_t) ( ( frequency * us_per_tick ) / 1000000 ); 173 174 /* 175 * Initialize hardware and set up a periodic interrupt for the configuration 176 * based interval. 177 */ 178 179 some_tc.tc_get_timecount = some_tc_get_timecount; 180 some_tc.tc_counter_mask = 0xffffffff; 181 some_tc.tc_frequency = frequency; 182 some_tc.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER; 183 rtems_timecounter_install( &some_tc ); 184 @} 185 186 #define Clock_driver_support_initialize_hardware() \ 187 some_support_initialize_hardware() 188 189 #include "../../../shared/clockdrv_shell.h" 190 @end example 191 192 @subsection Install Clock Tick Interrupt Service Routine 193 194 The clock driver must provide a function to install the clock tick interrupt 195 service routine via @code{Clock_driver_support_install_isr()}. 196 197 @example 198 #include <bsp/irq.h> 199 #include <bsp/fatal.h> 200 201 static void some_support_install_isr( rtems_interrupt_handler isr ) 202 @{ 203 rtems_status_code sc; 204 205 sc = rtems_interrupt_handler_install( 206 SOME_IRQ, 207 "Clock", 208 RTEMS_INTERRUPT_UNIQUE, 209 isr, 210 NULL 211 ); 212 if ( sc != RTEMS_SUCCESSFUL ) @{ 213 bsp_fatal( SOME_FATAL_IRQ_INSTALL ); 214 @} 215 @} 216 217 #define Clock_driver_support_install_isr( isr, old ) \ 218 some_support_install_isr( isr ) 219 220 #include "../../../shared/clockdrv_shell.h" 221 @end example 222 223 @subsection Support At Tick 224 225 The hardware specific support at tick is specified by 226 @code{Clock_driver_support_at_tick()}. 227 228 @example 229 static void some_support_at_tick( void ) 230 @{ 231 /* Clear interrupt */ 232 @} 233 234 #define Clock_driver_support_at_tick() \ 235 some_support_at_tick() 236 237 #include "../../../shared/clockdrv_shell.h" 238 @end example 239 240 @subsection System Shutdown Support 241 242 The @dfn{Clock Driver Shell} provides the routine @code{Clock_exit()} that is 243 scheduled to be run during system shutdown via the @code{atexit()} routine. 244 The hardware specific shutdown support is specified by 245 @code{Clock_driver_support_shutdown_hardware()} which is used by 246 @code{Clock_exit()}. It should disable the clock tick source if it was 247 enabled. This can be used to prevent clock ticks after the system is shutdown. 248 249 @example 250 static void some_support_shutdown_hardware( void ) 251 @{ 252 /* Shutdown hardware */ 253 @} 254 255 #define Clock_driver_support_shutdown_hardware() \ 256 some_support_shutdown_hardware() 257 258 #include "../../../shared/clockdrv_shell.h" 259 @end example 260 261 @subsection Multiple Clock Driver Ticks Per Clock Tick 262 263 In case the hardware needs more than one clock driver tick per clock tick (e.g. 264 due to a limited range of the hardware timer), then this can be specified with 265 the optional @code{#define CLOCK_DRIVER_ISRS_PER_TICK} and @code{#define 266 CLOCK_DRIVER_ISRS_PER_TICK_VALUE} defines. This is currently used only for x86 267 and it hopefully remains that way. 268 269 @example 270 /* Enable multiple clock driver ticks per clock tick */ 271 #define CLOCK_DRIVER_ISRS_PER_TICK 1 272 273 /* Specifiy the clock driver ticks per clock tick value */ 274 #define CLOCK_DRIVER_ISRS_PER_TICK_VALUE 123 275 276 #include "../../../shared/clockdrv_shell.h" 277 @end example 278 279 @subsection Clock Driver Ticks Counter 280 281 The @dfn{Clock Driver Shell} provide a global variable that is simply a count 282 of the number of clock driver interrupt service routines that have occurred. 283 This information is valuable when debugging a system. This variable is 284 declared as follows: 28 285 29 286 @example 30 287 volatile uint32_t Clock_driver_ticks; 31 288 @end example 32 33 @section Initialization34 35 The initialization routine is responsible for36 programming the hardware that will periodically37 generate an interrupt. A programmable interval timer is commonly38 used as the source of the clock tick.39 40 The device should be programmed such that an interrupt is generated41 every @i{m} microseconds, where @i{m} is equal to42 @code{rtems_configuration_get_microseconds_per_tick()}. Sometimes43 the periodic interval timer can use a prescaler so you have to look44 carefully at your user's manual to determine the correct value.45 46 You must use the RTEMS primitive @code{rtems_interrupt_catch} to install47 your clock interrupt service routine:48 49 @example50 rtems_interrupt_catch (Clock_ISR, CLOCK_VECTOR, &old_handler);51 @end example52 53 Since there is currently not a driver entry point invoked at system54 shutdown, many clock device drivers use the @code{atexit} routine55 to schedule their @code{Clock_exit} routine to execute when the56 system is shutdown.57 58 By convention, many of the clock drivers do not install the clock59 tick if the @code{ticks_per_timeslice} field of the Configuration60 Table is 0.61 62 @section System shutdown63 64 Many drivers provide the routine @code{Clock_exit} that is scheduled65 to be run during system shutdown via the @code{atexit} routine.66 The @code{Clock_exit} routine will disable the clock tick source67 if it was enabled. This can be used to prevent clock ticks after the68 system is shutdown.69 70 @section Clock Interrupt Subroutine71 72 It only has to inform the kernel that a ticker has elapsed, so call :73 74 @example75 @group76 rtems_isr Clock_isr( rtems_vector_number vector )77 @{78 invoke the rtems_clock_tick() directive to announce the tick79 if necessary for this hardware80 reload the programmable timer81 @}82 @end group83 @end example84 85 @section IO Control86 87 Prior to RTEMS 4.9, the Shared Memory MPCI Driver required a special88 IOCTL in the Clock Driver. This is no longer required and the Clock89 Driver does not have to provide an IOCTL method at all.90
Note: See TracChangeset
for help on using the changeset viewer.