[7150f00f] | 1 | /*-------------------------------------------------------------------------+ |
---|
| 2 | | timer.c v1.1 - PC386 BSP - 1997/08/07 |
---|
| 3 | +--------------------------------------------------------------------------+ |
---|
| 4 | | This file contains the PC386 timer package. |
---|
| 5 | +--------------------------------------------------------------------------+ |
---|
| 6 | | NOTE: It is important that the timer start/stop overhead be determined |
---|
| 7 | | when porting or modifying this code. |
---|
| 8 | +--------------------------------------------------------------------------+ |
---|
| 9 | | (C) Copyright 1997 - |
---|
| 10 | | - NavIST Group - Real-Time Distributed Systems and Industrial Automation |
---|
| 11 | | |
---|
| 12 | | http://pandora.ist.utl.pt |
---|
| 13 | | |
---|
| 14 | | Instituto Superior Tecnico * Lisboa * PORTUGAL |
---|
| 15 | +--------------------------------------------------------------------------+ |
---|
| 16 | | Disclaimer: |
---|
| 17 | | |
---|
| 18 | | This file is provided "AS IS" without warranty of any kind, either |
---|
| 19 | | expressed or implied. |
---|
| 20 | +--------------------------------------------------------------------------+ |
---|
| 21 | | This code is base on: |
---|
| 22 | | timer.c,v 1.7 1995/12/19 20:07:43 joel Exp - go32 BSP |
---|
[23291e99] | 23 | | |
---|
| 24 | | Rosimildo daSilva -ConnectTel, Inc - Fixed infinite loop in the Calibration |
---|
| 25 | | routine. I've seen this problems with faster machines ( pentiums ). Sometimes |
---|
| 26 | | RTEMS just hangs at startup. |
---|
| 27 | | |
---|
[7150f00f] | 28 | | With the following copyright notice: |
---|
| 29 | | ************************************************************************** |
---|
[08311cc3] | 30 | | * COPYRIGHT (c) 1989-1999. |
---|
[6f9c75c3] | 31 | | * On-Line Applications Research Corporation (OAR). |
---|
| 32 | | * |
---|
| 33 | | * The license and distribution terms for this file may be |
---|
| 34 | | * found in found in the file LICENSE in this distribution or at |
---|
| 35 | | * http://www.OARcorp.com/rtems/license.html. |
---|
[7150f00f] | 36 | | ************************************************************************** |
---|
[6f9c75c3] | 37 | | |
---|
| 38 | | $Id$ |
---|
[7150f00f] | 39 | +--------------------------------------------------------------------------*/ |
---|
| 40 | |
---|
| 41 | |
---|
| 42 | #include <stdlib.h> |
---|
| 43 | |
---|
| 44 | #include <bsp.h> |
---|
| 45 | #include <irq.h> |
---|
| 46 | |
---|
| 47 | /*-------------------------------------------------------------------------+ |
---|
| 48 | | Constants |
---|
| 49 | +--------------------------------------------------------------------------*/ |
---|
| 50 | #define AVG_OVERHEAD 0 /* 0.1 microseconds to start/stop timer. */ |
---|
| 51 | #define LEAST_VALID 1 /* Don't trust a value lower than this. */ |
---|
[eff217e] | 52 | #define SLOW_DOWN_IO 0x80 /* io which does nothing */ |
---|
[7150f00f] | 53 | |
---|
[eff217e] | 54 | #define TWO_MS (rtems_unsigned32)(2000) /* TWO_MS = 2000us (sic!) */ |
---|
| 55 | |
---|
| 56 | #define MSK_NULL_COUNT 0x40 /* bit counter available for reading */ |
---|
| 57 | |
---|
| 58 | #define CMD_READ_BACK_STATUS 0xE2 /* command read back status */ |
---|
[7150f00f] | 59 | /*-------------------------------------------------------------------------+ |
---|
| 60 | | Global Variables |
---|
| 61 | +--------------------------------------------------------------------------*/ |
---|
| 62 | volatile rtems_unsigned32 Ttimer_val; |
---|
| 63 | rtems_boolean Timer_driver_Find_average_overhead = TRUE; |
---|
[eff217e] | 64 | unsigned int loop1ms; |
---|
[7150f00f] | 65 | |
---|
[67a2288] | 66 | /*-------------------------------------------------------------------------+ |
---|
| 67 | | External Prototypes |
---|
| 68 | +--------------------------------------------------------------------------*/ |
---|
[2d7d605] | 69 | extern void timerisr(void); |
---|
[67a2288] | 70 | /* timer (int 08h) Interrupt Service Routine (defined in 'timerisr.s') */ |
---|
| 71 | |
---|
[7150f00f] | 72 | /*-------------------------------------------------------------------------+ |
---|
| 73 | | Pentium optimized timer handling. |
---|
| 74 | +--------------------------------------------------------------------------*/ |
---|
| 75 | #if defined(pentium) |
---|
| 76 | |
---|
| 77 | /*-------------------------------------------------------------------------+ |
---|
| 78 | | Function: rdtsc |
---|
| 79 | | Description: Read the value of PENTIUM on-chip cycle counter. |
---|
| 80 | | Global Variables: None. |
---|
| 81 | | Arguments: None. |
---|
| 82 | | Returns: Value of PENTIUM on-chip cycle counter. |
---|
| 83 | +--------------------------------------------------------------------------*/ |
---|
| 84 | static inline unsigned long long |
---|
| 85 | rdtsc(void) |
---|
| 86 | { |
---|
| 87 | /* Return the value of the on-chip cycle counter. */ |
---|
| 88 | unsigned long long result; |
---|
| 89 | asm volatile(".byte 0x0F, 0x31" : "=A" (result)); |
---|
| 90 | return result; |
---|
| 91 | } /* rdtsc */ |
---|
| 92 | |
---|
| 93 | |
---|
| 94 | /*-------------------------------------------------------------------------+ |
---|
| 95 | | Function: Timer_exit |
---|
| 96 | | Description: Timer cleanup routine at RTEMS exit. NOTE: This routine is |
---|
| 97 | | not really necessary, since there will be a reset at exit. |
---|
| 98 | | Global Variables: None. |
---|
| 99 | | Arguments: None. |
---|
| 100 | | Returns: Nothing. |
---|
| 101 | +--------------------------------------------------------------------------*/ |
---|
| 102 | void |
---|
| 103 | Timer_exit(void) |
---|
| 104 | { |
---|
| 105 | } /* Timer_exit */ |
---|
| 106 | |
---|
| 107 | |
---|
| 108 | /*-------------------------------------------------------------------------+ |
---|
| 109 | | Function: Timer_initialize |
---|
| 110 | | Description: Timer initialization routine. |
---|
| 111 | | Global Variables: Ttimer_val. |
---|
| 112 | | Arguments: None. |
---|
| 113 | | Returns: Nothing. |
---|
| 114 | +--------------------------------------------------------------------------*/ |
---|
| 115 | void |
---|
| 116 | Timer_initialize(void) |
---|
| 117 | { |
---|
| 118 | static rtems_boolean First = TRUE; |
---|
| 119 | |
---|
| 120 | if (First) |
---|
| 121 | { |
---|
| 122 | First = FALSE; |
---|
| 123 | |
---|
| 124 | atexit(Timer_exit); /* Try not to hose the system at exit. */ |
---|
| 125 | } |
---|
| 126 | Ttimer_val = rdtsc(); /* read starting time */ |
---|
| 127 | } /* Timer_initialize */ |
---|
| 128 | |
---|
| 129 | |
---|
| 130 | /*-------------------------------------------------------------------------+ |
---|
| 131 | | Function: Read_timer |
---|
| 132 | | Description: Read hardware timer value. |
---|
| 133 | | Global Variables: Ttimer_val, Timer_driver_Find_average_overhead. |
---|
| 134 | | Arguments: None. |
---|
| 135 | | Returns: Nothing. |
---|
| 136 | +--------------------------------------------------------------------------*/ |
---|
| 137 | rtems_unsigned32 |
---|
| 138 | Read_timer(void) |
---|
| 139 | { |
---|
| 140 | register rtems_unsigned32 total; |
---|
| 141 | |
---|
| 142 | total = (rtems_unsigned32)(rdtsc() - Ttimer_val); |
---|
| 143 | |
---|
| 144 | if (Timer_driver_Find_average_overhead) |
---|
| 145 | return total; |
---|
| 146 | else if (total < LEAST_VALID) |
---|
| 147 | return 0; /* below timer resolution */ |
---|
| 148 | else |
---|
| 149 | return (total - AVG_OVERHEAD); |
---|
| 150 | } /* Read_timer */ |
---|
| 151 | |
---|
| 152 | #else /* pentium */ |
---|
| 153 | |
---|
| 154 | /*-------------------------------------------------------------------------+ |
---|
| 155 | | Non-Pentium timer handling. |
---|
| 156 | +--------------------------------------------------------------------------*/ |
---|
| 157 | #define US_PER_ISR 250 /* Number of micro-seconds per timer interruption */ |
---|
| 158 | |
---|
[67a2288] | 159 | |
---|
[7150f00f] | 160 | /*-------------------------------------------------------------------------+ |
---|
[67a2288] | 161 | | Function: Timer_exit |
---|
| 162 | | Description: Timer cleanup routine at RTEMS exit. NOTE: This routine is |
---|
| 163 | | not really necessary, since there will be a reset at exit. |
---|
| 164 | | Global Variables: None. |
---|
| 165 | | Arguments: None. |
---|
| 166 | | Returns: Nothing. |
---|
[7150f00f] | 167 | +--------------------------------------------------------------------------*/ |
---|
[2d7d605] | 168 | static void |
---|
[67a2288] | 169 | timerOff(const rtems_raw_irq_connect_data* used) |
---|
| 170 | { |
---|
| 171 | /* |
---|
| 172 | * disable interrrupt at i8259 level |
---|
| 173 | */ |
---|
[0ebbf66] | 174 | BSP_irq_disable_at_i8259s(used->idtIndex - BSP_IRQ_VECTOR_BASE); |
---|
[67a2288] | 175 | /* reset timer mode to standard (DOS) value */ |
---|
| 176 | outport_byte(TIMER_MODE, TIMER_SEL0|TIMER_16BIT|TIMER_RATEGEN); |
---|
| 177 | outport_byte(TIMER_CNTR0, 0); |
---|
| 178 | outport_byte(TIMER_CNTR0, 0); |
---|
| 179 | } /* Timer_exit */ |
---|
| 180 | |
---|
| 181 | |
---|
[2d7d605] | 182 | static void |
---|
| 183 | timerOn(const rtems_raw_irq_connect_data* used) |
---|
[67a2288] | 184 | { |
---|
| 185 | /* load timer for US_PER_ISR microsecond period */ |
---|
| 186 | outport_byte(TIMER_MODE, TIMER_SEL0|TIMER_16BIT|TIMER_RATEGEN); |
---|
| 187 | outport_byte(TIMER_CNTR0, US_TO_TICK(US_PER_ISR) >> 0 & 0xff); |
---|
| 188 | outport_byte(TIMER_CNTR0, US_TO_TICK(US_PER_ISR) >> 8 & 0xff); |
---|
| 189 | /* |
---|
[bd8c8b2a] | 190 | * enable interrrupt at i8259 level |
---|
[67a2288] | 191 | */ |
---|
[0ebbf66] | 192 | BSP_irq_enable_at_i8259s(used->idtIndex - BSP_IRQ_VECTOR_BASE); |
---|
[67a2288] | 193 | } |
---|
| 194 | |
---|
[2d7d605] | 195 | static int |
---|
| 196 | timerIsOn(const rtems_raw_irq_connect_data *used) |
---|
| 197 | { |
---|
[0ebbf66] | 198 | return BSP_irq_enabled_at_i8259s(used->idtIndex - BSP_IRQ_VECTOR_BASE);} |
---|
[2d7d605] | 199 | |
---|
[67a2288] | 200 | static rtems_raw_irq_connect_data timer_raw_irq_data = { |
---|
[0ebbf66] | 201 | BSP_PERIODIC_TIMER + BSP_IRQ_VECTOR_BASE, |
---|
[67a2288] | 202 | timerisr, |
---|
| 203 | timerOn, |
---|
| 204 | timerOff, |
---|
[2d7d605] | 205 | timerIsOn |
---|
[67a2288] | 206 | }; |
---|
[7150f00f] | 207 | |
---|
| 208 | /*-------------------------------------------------------------------------+ |
---|
| 209 | | Function: Timer_exit |
---|
| 210 | | Description: Timer cleanup routine at RTEMS exit. NOTE: This routine is |
---|
| 211 | | not really necessary, since there will be a reset at exit. |
---|
| 212 | | Global Variables: None. |
---|
| 213 | | Arguments: None. |
---|
| 214 | | Returns: Nothing. |
---|
| 215 | +--------------------------------------------------------------------------*/ |
---|
| 216 | void |
---|
| 217 | Timer_exit(void) |
---|
| 218 | { |
---|
[67a2288] | 219 | i386_delete_idt_entry (&timer_raw_irq_data); |
---|
[7150f00f] | 220 | } /* Timer_exit */ |
---|
| 221 | |
---|
| 222 | /*-------------------------------------------------------------------------+ |
---|
| 223 | | Function: Timer_initialize |
---|
| 224 | | Description: Timer initialization routine. |
---|
| 225 | | Global Variables: Ttimer_val. |
---|
| 226 | | Arguments: None. |
---|
| 227 | | Returns: Nothing. |
---|
| 228 | +--------------------------------------------------------------------------*/ |
---|
| 229 | void |
---|
| 230 | Timer_initialize(void) |
---|
| 231 | { |
---|
| 232 | static rtems_boolean First = TRUE; |
---|
| 233 | |
---|
| 234 | if (First) |
---|
| 235 | { |
---|
| 236 | First = FALSE; |
---|
| 237 | |
---|
| 238 | atexit(Timer_exit); /* Try not to hose the system at exit. */ |
---|
[67a2288] | 239 | if (!i386_set_idt_entry (&timer_raw_irq_data)) { |
---|
| 240 | printk("raw handler connexion failed\n"); |
---|
| 241 | rtems_fatal_error_occurred(1); |
---|
| 242 | } |
---|
[7150f00f] | 243 | } |
---|
| 244 | /* wait for ISR to be called at least once */ |
---|
| 245 | Ttimer_val = 0; |
---|
| 246 | while (Ttimer_val == 0) |
---|
| 247 | continue; |
---|
| 248 | Ttimer_val = 0; |
---|
| 249 | } /* Timer_initialize */ |
---|
| 250 | |
---|
| 251 | |
---|
| 252 | /*-------------------------------------------------------------------------+ |
---|
| 253 | | Function: Read_timer |
---|
| 254 | | Description: Read hardware timer value. |
---|
| 255 | | Global Variables: Ttimer_val, Timer_driver_Find_average_overhead. |
---|
| 256 | | Arguments: None. |
---|
| 257 | | Returns: Nothing. |
---|
| 258 | +--------------------------------------------------------------------------*/ |
---|
| 259 | rtems_unsigned32 |
---|
| 260 | Read_timer(void) |
---|
| 261 | { |
---|
| 262 | register rtems_unsigned32 total, clicks; |
---|
| 263 | register rtems_unsigned8 lsb, msb; |
---|
| 264 | |
---|
| 265 | outport_byte(TIMER_MODE, TIMER_SEL0|TIMER_LATCH); |
---|
| 266 | inport_byte(TIMER_CNTR0, lsb); |
---|
| 267 | inport_byte(TIMER_CNTR0, msb); |
---|
| 268 | clicks = (msb << 8) | lsb; |
---|
| 269 | total = (Ttimer_val * US_PER_ISR) + (US_PER_ISR - TICK_TO_US(clicks)); |
---|
| 270 | |
---|
| 271 | if (Timer_driver_Find_average_overhead) |
---|
| 272 | return total; |
---|
| 273 | else if (total < LEAST_VALID) |
---|
| 274 | return 0; /* below timer resolution */ |
---|
| 275 | else |
---|
| 276 | return (total - AVG_OVERHEAD); |
---|
| 277 | } |
---|
| 278 | |
---|
| 279 | #endif /* pentium */ |
---|
| 280 | |
---|
| 281 | |
---|
| 282 | /*-------------------------------------------------------------------------+ |
---|
| 283 | | Function: Empty_function |
---|
| 284 | | Description: Empty function used in time tests. |
---|
| 285 | | Global Variables: None. |
---|
| 286 | | Arguments: None. |
---|
| 287 | | Returns: Nothing. |
---|
| 288 | +--------------------------------------------------------------------------*/ |
---|
| 289 | rtems_status_code Empty_function(void) |
---|
| 290 | { |
---|
| 291 | return RTEMS_SUCCESSFUL; |
---|
| 292 | } /* Empty function */ |
---|
| 293 | |
---|
| 294 | |
---|
| 295 | /*-------------------------------------------------------------------------+ |
---|
| 296 | | Function: Set_find_average_overhead |
---|
| 297 | | Description: Set internal Timer_driver_Find_average_overhead flag value. |
---|
| 298 | | Global Variables: Timer_driver_Find_average_overhead. |
---|
| 299 | | Arguments: find_flag - new value of the flag. |
---|
| 300 | | Returns: Nothing. |
---|
| 301 | +--------------------------------------------------------------------------*/ |
---|
| 302 | void |
---|
| 303 | Set_find_average_overhead(rtems_boolean find_flag) |
---|
| 304 | { |
---|
| 305 | Timer_driver_Find_average_overhead = find_flag; |
---|
| 306 | } /* Set_find_average_overhead */ |
---|
[eff217e] | 307 | |
---|
[23291e99] | 308 | |
---|
| 309 | |
---|
| 310 | /*-------------------------------------------------------------------------+ |
---|
| 311 | | Description: Loads timer 0 with value passed as arguemnt. |
---|
| 312 | | Returns: Nothing. |
---|
| 313 | +--------------------------------------------------------------------------*/ |
---|
| 314 | inline void loadTimerValue( unsigned short loadedValue ) |
---|
| 315 | { |
---|
| 316 | outport_byte(TIMER_MODE, TIMER_SEL0|TIMER_16BIT|TIMER_RATEGEN); |
---|
| 317 | outport_byte(TIMER_CNTR0, loadedValue >> 0 & 0xff); |
---|
| 318 | outport_byte(TIMER_CNTR0, loadedValue >> 8 & 0xff); |
---|
| 319 | } |
---|
| 320 | |
---|
| 321 | |
---|
| 322 | /*-------------------------------------------------------------------------+ |
---|
| 323 | | Description: Waits until the counter on timer 0 reaches 0. |
---|
| 324 | | Returns: Nothing. |
---|
| 325 | +--------------------------------------------------------------------------*/ |
---|
| 326 | inline void waitTimerStatus( void ) |
---|
| 327 | { |
---|
| 328 | unsigned char status; |
---|
| 329 | outport_byte(TIMER_MODE, CMD_READ_BACK_STATUS); /* read Status counter 0 */ |
---|
| 330 | inport_byte(TIMER_CNTR0, status); |
---|
| 331 | while (status & MSK_NULL_COUNT){ /* wait for counter ready */ |
---|
| 332 | outport_byte(TIMER_MODE, CMD_READ_BACK_STATUS); |
---|
| 333 | inport_byte(TIMER_CNTR0, status); |
---|
| 334 | } |
---|
| 335 | } |
---|
| 336 | |
---|
| 337 | |
---|
| 338 | /*-------------------------------------------------------------------------+ |
---|
| 339 | | Description: Reads the current value of the timer, and converts the |
---|
| 340 | | number of ticks to micro-seconds. |
---|
| 341 | | Returns: current number of microseconds since last value loaded.. |
---|
| 342 | +--------------------------------------------------------------------------*/ |
---|
| 343 | inline unsigned short readCurrentTimer() |
---|
| 344 | { |
---|
| 345 | unsigned short lsb, msb; |
---|
| 346 | outport_byte(TIMER_MODE, TIMER_SEL0|TIMER_LATCH); |
---|
| 347 | inport_byte(TIMER_CNTR0, lsb); |
---|
| 348 | inport_byte(TIMER_CNTR0, msb); |
---|
| 349 | return TICK_TO_US( ( msb << 8 ) | lsb ); |
---|
| 350 | } |
---|
| 351 | |
---|
| 352 | |
---|
| 353 | /*-------------------------------------------------------------------------+ |
---|
| 354 | * clockbits - Read low order bits of timer 0 (the TOD clock) |
---|
| 355 | * This works only for the 8254 chips used in ATs and 386s. |
---|
| 356 | * |
---|
| 357 | * The timer runs in mode 3 (square wave mode), counting down |
---|
| 358 | * by twos, twice for each cycle. So it is necessary to read back the |
---|
| 359 | * OUTPUT pin to see which half of the cycle we're in. I.e., the OUTPUT |
---|
| 360 | * pin forms the most significant bit of the count. Unfortunately, |
---|
| 361 | * the 8253 in the PC/XT lacks a command to read the OUTPUT pin... |
---|
| 362 | * |
---|
| 363 | * The PC's clock design is soooo brain damaged... |
---|
| 364 | * |
---|
| 365 | * Rosimildo - I've got this routine from the KA9Q32 distribution and |
---|
| 366 | * have updated it for the RTEMS environment. |
---|
| 367 | +--------------------------------------------------------------------------*/ |
---|
| 368 | unsigned int clockbits(void) |
---|
| 369 | { |
---|
| 370 | unsigned int stat,count1, count; |
---|
| 371 | |
---|
| 372 | do |
---|
| 373 | { |
---|
| 374 | outport_byte( 0x43, 0xc2 ); /* latch timer 0 count and status for reading */ |
---|
| 375 | inport_byte( 0x40, stat ); /* get status of timer 0 */ |
---|
| 376 | inport_byte( 0x40, count1 ); /* lsb of count */ |
---|
| 377 | inport_byte( 0x40, count ); /* msb of count */ |
---|
| 378 | count = count1 | ( count << 8 ); |
---|
| 379 | } while(stat & 0x40); /* reread if NULL COUNT bit set */ |
---|
| 380 | stat = (stat & 0x80) << 8; /* Shift OUTPUT to msb of 16-bit word */ |
---|
| 381 | if(count == 0) |
---|
| 382 | return stat ^ 0x8000; /* return complement of OUTPUT bit */ |
---|
| 383 | else |
---|
| 384 | return count | stat; /* Combine OUTPUT with counter */ |
---|
| 385 | } |
---|
| 386 | |
---|
| 387 | |
---|
[eff217e] | 388 | /*-------------------------------------------------------------------------+ |
---|
| 389 | | Function: Calibrate_loop_1ms |
---|
| 390 | | Description: Set loop variable to calibrate a 1ms loop |
---|
| 391 | | Global Variables: loop1ms |
---|
| 392 | | Arguments: none |
---|
| 393 | | Returns: Nothing. |
---|
| 394 | +--------------------------------------------------------------------------*/ |
---|
| 395 | void |
---|
[23291e99] | 396 | Calibrate_loop_1ms(void) |
---|
| 397 | { |
---|
[eff217e] | 398 | unsigned int i; |
---|
| 399 | unsigned short loadedValue, offset; |
---|
[5cfcd7e] | 400 | unsigned int timerValue, t1_ref, t2_ref=0; |
---|
[eff217e] | 401 | rtems_interrupt_level level; |
---|
| 402 | |
---|
[23291e99] | 403 | |
---|
| 404 | printk( "Calibrate_loop_1ms is starting, please wait ( but not too loooong. )\n" ); |
---|
| 405 | |
---|
| 406 | loop1ms = 200; |
---|
| 407 | timerValue = 0; |
---|
| 408 | |
---|
| 409 | /* Let's load the timer with 2ms, initially */ |
---|
| 410 | loadedValue = US_TO_TICK( 2000 ); |
---|
[eff217e] | 411 | |
---|
| 412 | rtems_interrupt_disable(level); |
---|
| 413 | /* |
---|
| 414 | * Compute the offset to apply due to read counter register |
---|
| 415 | */ |
---|
[23291e99] | 416 | offset = 0; |
---|
| 417 | loadTimerValue( loadedValue + offset ); |
---|
| 418 | waitTimerStatus(); |
---|
| 419 | t1_ref = clockbits(); |
---|
| 420 | offset = loadedValue - readCurrentTimer(); |
---|
| 421 | while( timerValue < 1000 ) |
---|
| 422 | { |
---|
[eff217e] | 423 | loop1ms++; |
---|
[23291e99] | 424 | loadTimerValue( loadedValue + offset ); |
---|
| 425 | waitTimerStatus(); |
---|
| 426 | t1_ref = clockbits(); |
---|
| 427 | for( i=0; i < loop1ms; i++ ) |
---|
| 428 | outport_byte( SLOW_DOWN_IO, 0 ); /* write is # 1us */ |
---|
| 429 | t2_ref = clockbits(); |
---|
| 430 | timerValue = TICK_TO_US( t1_ref - t2_ref ); /* timer0 is decrementing number of ticks */ |
---|
[eff217e] | 431 | } |
---|
[23291e99] | 432 | printk( "Calibrate_loop_1ms timerValue=%d, loop1ms=%d, t1_ref=%x, clockbits=%x, delta=%d\n", |
---|
| 433 | timerValue, loop1ms, t1_ref, t2_ref, t1_ref - t2_ref ); |
---|
[eff217e] | 434 | rtems_interrupt_enable(level); |
---|
| 435 | } |
---|
| 436 | |
---|
[23291e99] | 437 | |
---|
| 438 | |
---|
[eff217e] | 439 | /*-------------------------------------------------------------------------+ |
---|
| 440 | | Function: Wait_X_1ms |
---|
| 441 | | Description: loop which waits at least timeToWait ms |
---|
| 442 | | Global Variables: loop1ms |
---|
| 443 | | Arguments: timeToWait |
---|
| 444 | | Returns: Nothing. |
---|
| 445 | +--------------------------------------------------------------------------*/ |
---|
| 446 | void |
---|
| 447 | Wait_X_ms( unsigned int timeToWait){ |
---|
| 448 | |
---|
| 449 | unsigned int i, j; |
---|
| 450 | |
---|
| 451 | for (j=0; j<timeToWait ; j++) |
---|
| 452 | for (i=0; i<loop1ms; i++) |
---|
| 453 | outport_byte(SLOW_DOWN_IO, 0); /* write is # 1us */ |
---|
| 454 | } |
---|
| 455 | |
---|
| 456 | |
---|
| 457 | |
---|
| 458 | |
---|
| 459 | |
---|
| 460 | |
---|