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

4.115
Last change on this file since c499856 was c499856, checked in by Chris Johns <chrisj@…>, on 03/20/14 at 21:10:47

Change all references of rtems.com to rtems.org.

  • Property mode set to 100644
File size: 7.2 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 *  benchmark_timer_initialize() and benchmark_timer_read().  benchmark_timer_read() usually returns
7 *  the number of microseconds since benchmark_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.org/license/LICENSE.
21 */
22
23#include <rtems.h>
24
25#include <rtems/score/sh_io.h>
26#include <rtems/score/iosh7750.h>
27
28extern uint32_t bsp_clicks_per_second;
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
40extern rtems_isr timerisr(void);
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
50bool benchmark_timer_find_average_overhead;
51
52/* benchmark_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
66benchmark_timer_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    rtems_interrupt_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 = bsp_clicks_per_second * cpudiv / (tidiv * 1000000);
137    microseconds_per_int = 0xFFFFFFFF / microseconds_divider;
138
139    /*
140     *  Hardware specific initialization
141     */
142
143    /* Stop the Timer 0 */
144    temp8 = read8(SH7750_TSTR);
145    temp8 &= ~SH7750_TSTR_STR1;
146    write8(temp8, SH7750_TSTR);
147
148    /* Establish interrupt handler */
149    _CPU_ISR_install_raw_handler( TIMER_VECTOR, timerisr, &ignored );
150
151    /* Reset timer constant and counter */
152    write32(0xFFFFFFFF, SH7750_TCOR1);
153    write32(0xFFFFFFFF, SH7750_TCNT1);
154
155    /* Select timer mode */
156    write16(
157        SH7750_TCR_UNIE |        /* Enable Underflow Interrupt */
158        SH7750_TCR_CKEG_RAISE |  /* Count on rising edge */
159        TCR1_TPSC,               /* Timer prescaler ratio */
160        SH7750_TCR1);
161
162    /* Set timer interrupt priority */
163    temp16 = read16(SH7750_IPRA);
164    temp16 = (temp16 & ~SH7750_IPRA_TMU1) | (TIMER_PRIO << SH7750_IPRA_TMU1_S);
165    write16(temp16, SH7750_IPRA);
166
167
168    rtems_interrupt_enable(level);
169
170    /* Start the Timer 1 */
171    temp8 = read8(SH7750_TSTR);
172    temp8 |= SH7750_TSTR_STR1;
173    write8(temp8, SH7750_TSTR);
174
175}
176
177/*
178 *  The following controls the behavior of benchmark_timer_read().
179 *
180 *  AVG_OVERHEAD is the overhead for starting and stopping the timer.  It
181 *  is usually deducted from the number returned.
182 *
183 *  LEAST_VALID is the lowest number this routine should trust.  Numbers
184 *  below this are "noise" and zero is returned.
185 */
186
187#define AVG_OVERHEAD      0  /* It typically takes X.X microseconds */
188                             /* (Y countdowns) to start/stop the timer. */
189                             /* This value is in microseconds. */
190#define LEAST_VALID       0 /* 20 */ /* Don't trust a clicks value lower than this */
191
192/* benchmark_timer_read --
193 *     Read timer value in microsecond units since timer start.
194 *
195 * PARAMETERS:
196 *     none
197 *
198 * RETURNS:
199 *     number of microseconds since timer has been started
200 */
201int
202benchmark_timer_read(void)
203{
204    uint32_t              clicks;
205    uint32_t              ints;
206    uint32_t              total;
207    rtems_interrupt_level level;
208    uint32_t              tcr;
209
210
211    rtems_interrupt_disable(level);
212
213    clicks = 0xFFFFFFFF - read32(SH7750_TCNT1);
214    tcr = read32(SH7750_TCR1);
215    ints = Timer_interrupts;
216
217    rtems_interrupt_enable(level);
218
219    /* Handle the case when timer overflowed but interrupt was not processed */
220    if ((clicks > 0xFF000000) && ((tcr & SH7750_TCR_UNF) != 0))
221    {
222        ints++;
223    }
224
225    total = microseconds_per_int * ints + (clicks / microseconds_divider);
226
227    if ( benchmark_timer_find_average_overhead )
228        return total;          /* in microsecond units */
229    else
230    {
231        if ( total < LEAST_VALID )
232            return 0;            /* below timer resolution */
233        /*
234         *  Somehow convert total into microseconds
235         */
236        return (total - AVG_OVERHEAD) ;
237    }
238}
239
240/* benchmark_timer_disable_subtracting_average_overhead --
241 *     This routine is invoked by the "Check Timer" (tmck) test in the
242 *     RTEMS Timing Test Suite. It makes the benchmark_timer_read routine not
243 *     subtract the overhead required to initialize and read the benchmark
244 *     timer.
245 *
246 * PARAMETERS:
247 *     find_flag - boolean flag, true if overhead must not be subtracted.
248 *
249 * RETURNS:
250 *     none
251 */
252void
253benchmark_timer_disable_subtracting_average_overhead(bool find_flag)
254{
255    benchmark_timer_find_average_overhead = find_flag;
256}
257
258/* timerisr --
259 *     Timer interrupt handler routine. This function invoked on timer
260 *     underflow event; once per 2^32 clocks. It should reset the timer
261 *     event and increment timer interrupts counter.
262 */
263void
264timerisr(void)
265{
266  uint8_t   temp8;
267
268  /* reset the flags of the status register */
269  temp8 = read8(SH7750_TCR1) & ~SH7750_TCR_UNF;
270  write8(temp8, SH7750_TCR1);
271
272  Timer_interrupts += 1;
273}
Note: See TracBrowser for help on using the repository browser.