source: rtems/c/src/lib/libcpu/sh/sh7750/timer/timer.c @ 3906b3ea

4.104.114.84.95
Last change on this file since 3906b3ea was 3906b3ea, checked in by Ralf Corsepius <ralf.corsepius@…>, on 04/16/04 at 21:29:43

Remove stray white spaces.

  • Property mode set to 100644
File size: 7.3 KB
Line 
1/*
2 *  timer driver for the Hitachi SH 7750
3 *
4 *  This file manages the benchmark timer used by the RTEMS Timing Test
5 *  Suite.  Each measured time period is demarcated by calls to
6 *  Timer_initialize() and Read_timer().  Read_timer() usually returns
7 *  the number of microseconds since Timer_initialize() exitted.
8 *
9 *  NOTE: It is important that the timer start/stop overhead be
10 *        determined when porting or modifying this code.
11 *
12 *  Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
13 *  Author: Victor V. Vengerov <vvv@oktet.ru>
14 *
15 *  COPYRIGHT (c) 1998.
16 *  On-Line Applications Research Corporation (OAR).
17 *
18 *  The license and distribution terms for this file may be
19 *  found in the file LICENSE in this distribution or at
20 *  http://www.rtems.com/license/LICENSE.
21 *
22 *  $Id$
23 */
24
25#include <rtems.h>
26
27#include <rtems/score/sh_io.h>
28#include <rtems/score/iosh7750.h>
29
30#ifndef TIMER_PRIO
31#define TIMER_PRIO 15
32#endif
33
34/* Timer prescaler division ratio */
35#define TIMER_PRESCALER 4
36#define TCR1_TPSC       SH7750_TCR_TPSC_DIV4
37
38#define TIMER_VECTOR SH7750_EVT_TO_NUM(SH7750_EVT_TUNI1)
39
40rtems_isr timerisr();
41
42static uint32_t   Timer_interrupts;
43
44/* Counter should be divided to this value to obtain time in microseconds */
45static uint32_t   microseconds_divider;
46
47/* Interrupt period in microseconds */
48static uint32_t   microseconds_per_int;
49
50rtems_boolean Timer_driver_Find_average_overhead;
51
52/* Timer_initialize --
53 *     Initialize Timer 1 to operate as a RTEMS benchmark timer:
54 *        - determine timer clock frequency
55 *        - install timer interrupt handler
56 *        - configure the Timer 1 hardware
57 *        - start the timer
58 *
59 * PARAMETERS:
60 *     none
61 *
62 * RETURNS:
63 *     none
64 */
65void
66Timer_initialize(void)
67{
68    uint8_t         temp8;
69    uint16_t        temp16;
70    rtems_interrupt_level level;
71    rtems_isr            *ignored;
72    int                   cpudiv = 1;
73    int                   tidiv = 1;
74
75    Timer_interrupts  = 0;
76    _CPU_ISR_Disable(level);
77
78    /* Get CPU frequency divider from clock unit */
79    switch (read16(SH7750_FRQCR) & SH7750_FRQCR_IFC)
80    {
81        case SH7750_FRQCR_IFCDIV1:
82            cpudiv = 1;
83            break;
84
85        case SH7750_FRQCR_IFCDIV2:
86            cpudiv = 2;
87            break;
88
89        case SH7750_FRQCR_IFCDIV3:
90            cpudiv = 3;
91            break;
92
93        case SH7750_FRQCR_IFCDIV4:
94            cpudiv = 4;
95            break;
96
97        case SH7750_FRQCR_IFCDIV6:
98            cpudiv = 6;
99            break;
100
101        case SH7750_FRQCR_IFCDIV8:
102            cpudiv = 8;
103            break;
104
105        default:
106            rtems_fatal_error_occurred( RTEMS_NOT_CONFIGURED);
107    }
108
109    /* Get peripheral module frequency divider from clock unit */
110    switch (read16(SH7750_FRQCR) & SH7750_FRQCR_PFC)
111    {
112        case SH7750_FRQCR_PFCDIV2:
113            tidiv = 2 * TIMER_PRESCALER;
114            break;
115
116        case SH7750_FRQCR_PFCDIV3:
117            tidiv = 3 * TIMER_PRESCALER;
118            break;
119
120        case SH7750_FRQCR_PFCDIV4:
121            tidiv = 4 * TIMER_PRESCALER;
122            break;
123
124        case SH7750_FRQCR_PFCDIV6:
125            tidiv = 6 * TIMER_PRESCALER;
126            break;
127
128        case SH7750_FRQCR_PFCDIV8:
129            tidiv = 8 * TIMER_PRESCALER;
130            break;
131
132        default:
133            rtems_fatal_error_occurred( RTEMS_NOT_CONFIGURED);
134    }
135
136    microseconds_divider =
137        rtems_cpu_configuration_get_clicks_per_second() * cpudiv /
138        (tidiv * 1000000);
139    microseconds_per_int = 0xFFFFFFFF / microseconds_divider;
140
141    /*
142     *  Hardware specific initialization
143     */
144
145    /* Stop the Timer 0 */
146    temp8 = read8(SH7750_TSTR);
147    temp8 &= ~SH7750_TSTR_STR1;
148    write8(temp8, SH7750_TSTR);
149
150    /* Establish interrupt handler */
151    _CPU_ISR_install_raw_handler( TIMER_VECTOR, timerisr, &ignored );
152
153    /* Reset timer constant and counter */
154    write32(0xFFFFFFFF, SH7750_TCOR1);
155    write32(0xFFFFFFFF, SH7750_TCNT1);
156
157    /* Select timer mode */
158    write16(
159        SH7750_TCR_UNIE |        /* Enable Underflow Interrupt */
160        SH7750_TCR_CKEG_RAISE |  /* Count on rising edge */
161        TCR1_TPSC,               /* Timer prescaler ratio */
162        SH7750_TCR1);
163
164    /* Set timer interrupt priority */
165    temp16 = read16(SH7750_IPRA);
166    temp16 = (temp16 & ~SH7750_IPRA_TMU1) | (TIMER_PRIO << SH7750_IPRA_TMU1_S);
167    write16(temp16, SH7750_IPRA);
168
169
170    _CPU_ISR_Enable(level);
171
172    /* Start the Timer 1 */
173    temp8 = read8(SH7750_TSTR);
174    temp8 |= SH7750_TSTR_STR1;
175    write8(temp8, SH7750_TSTR);
176
177}
178
179/*
180 *  The following controls the behavior of Read_timer().
181 *
182 *  AVG_OVERHEAD is the overhead for starting and stopping the timer.  It
183 *  is usually deducted from the number returned.
184 *
185 *  LEAST_VALID is the lowest number this routine should trust.  Numbers
186 *  below this are "noise" and zero is returned.
187 */
188
189#define AVG_OVERHEAD      0  /* It typically takes X.X microseconds */
190                             /* (Y countdowns) to start/stop the timer. */
191                             /* This value is in microseconds. */
192#define LEAST_VALID       0 /* 20 */ /* Don't trust a clicks value lower than this */
193
194/* Read_timer --
195 *     Read timer value in microsecond units since timer start.
196 *
197 * PARAMETERS:
198 *     none
199 *
200 * RETURNS:
201 *     number of microseconds since timer has been started
202 */
203int
204Read_timer(void)
205{
206    uint32_t   clicks;
207    uint32_t   ints;
208    uint32_t   total ;
209    rtems_interrupt_level level;
210    uint32_t   tcr;
211
212
213    _CPU_ISR_Disable(level);
214
215    clicks = 0xFFFFFFFF - read32(SH7750_TCNT1);
216    tcr = read32(SH7750_TCR1);
217    ints = Timer_interrupts;
218
219    _CPU_ISR_Enable(level);
220
221    /* Handle the case when timer overflowed but interrupt was not processed */
222    if ((clicks > 0xFF000000) && ((tcr & SH7750_TCR_UNF) != 0))
223    {
224        ints++;
225    }
226
227    total = microseconds_per_int * ints + (clicks / microseconds_divider);
228
229    if ( Timer_driver_Find_average_overhead )
230        return total;          /* in microsecond units */
231    else
232    {
233        if ( total < LEAST_VALID )
234            return 0;            /* below timer resolution */
235        /*
236         *  Somehow convert total into microseconds
237         */
238        return (total - AVG_OVERHEAD) ;
239    }
240}
241
242/* Empty_function --
243 *     Empty function call used in loops to measure basic cost of looping
244 *     in Timing Test Suite.
245 *
246 * PARAMETERS:
247 *     none
248 *
249 * RETURNS:
250 *     RTEMS_SUCCESSFUL
251 */
252rtems_status_code
253Empty_function( void )
254{
255  return RTEMS_SUCCESSFUL;
256}
257
258/* Set_find_average_overhead --
259 *     This routine is invoked by the "Check Timer" (tmck) test in the
260 *     RTEMS Timing Test Suite. It makes the Read_timer routine not
261 *     subtract the overhead required to initialize and read the benchmark
262 *     timer.
263 *
264 * PARAMETERS:
265 *     find_flag - boolean flag, TRUE if overhead must not be subtracted.
266 *
267 * RETURNS:
268 *     none
269 */
270void
271Set_find_average_overhead(rtems_boolean find_flag)
272{
273    Timer_driver_Find_average_overhead = find_flag;
274}
275
276/* timerisr --
277 *     Timer interrupt handler routine. This function invoked on timer
278 *     underflow event; once per 2^32 clocks. It should reset the timer
279 *     event and increment timer interrupts counter.
280 */
281void
282timerisr(void)
283{
284  uint8_t   temp8;
285
286  /* reset the flags of the status register */
287  temp8 = read8(SH7750_TCR1) & ~SH7750_TCR_UNF;
288  write8(temp8, SH7750_TCR1);
289
290  Timer_interrupts += 1;
291}
Note: See TracBrowser for help on using the repository browser.