1 | /** |
---|
2 | * @file timer.c |
---|
3 | * |
---|
4 | * GBA Timer driver. |
---|
5 | */ |
---|
6 | /* |
---|
7 | * RTEMS GBA BSP |
---|
8 | * |
---|
9 | * Copyright (c) 2002 by Jay Monkman <jtm@smoothsmoothie.com> |
---|
10 | * |
---|
11 | * Copyright (c) 2004 Markku Puro <markku.puro@kopteri.net> |
---|
12 | * |
---|
13 | * The license and distribution terms for this file may be |
---|
14 | * found in found in the file LICENSE in this distribution or at |
---|
15 | * http://www.rtems.com/license/LICENSE. |
---|
16 | * |
---|
17 | * |
---|
18 | * Notes: |
---|
19 | * This file manages the benchmark timer used by the RTEMS Timing Test |
---|
20 | * Suite. Each measured time period is demarcated by calls to |
---|
21 | * Timer_initialize() and Read_timer(). Read_timer() usually returns |
---|
22 | * the number of microseconds since Timer_initialize() exitted. |
---|
23 | * |
---|
24 | * It is important that the timer start/stop overhead be determined |
---|
25 | * when porting or modifying this code. |
---|
26 | * |
---|
27 | * $Id$ |
---|
28 | */ |
---|
29 | |
---|
30 | #include <rtems.h> |
---|
31 | #include <bsp.h> |
---|
32 | #include <irq.h> |
---|
33 | #include <gba.h> |
---|
34 | |
---|
35 | /* |
---|
36 | * Set up the timer hardware |
---|
37 | * 1 / 16.78Mhz => 59.595 ns |
---|
38 | * 64 / 16.78Mhz => 3.814 us |
---|
39 | * 256 / 16.78Mhz => 15.256 us |
---|
40 | * 1024 / 16.78Mhz => 61.025 us |
---|
41 | */ |
---|
42 | #define __TimePreScaler 1 |
---|
43 | #define __TickTime_ns ((1000000000L/__ClockFrequency)*__TimePreScaler) |
---|
44 | #define __TickTime_us ((1000000L/__ClockFrequency)*__TimePreScaler) |
---|
45 | |
---|
46 | #if (__TimePreScaler==1) |
---|
47 | #define GBA_TM0CNT_PS 0x0000 |
---|
48 | #elif (__TimePreScaler==64) |
---|
49 | #define GBA_TM0CNT_PS 0x0001 |
---|
50 | #elif (__TimePreScaler==256) |
---|
51 | #define GBA_TM0CNT_PS 0x0002 |
---|
52 | #elif (__TimePreScaler==1024) |
---|
53 | #define GBA_TM0CNT_PS 0x0003 |
---|
54 | #else |
---|
55 | #define GBA_TM0CNT_PS 0x0003 |
---|
56 | #endif |
---|
57 | |
---|
58 | rtems_boolean Timer_driver_Find_average_overhead; |
---|
59 | |
---|
60 | /** |
---|
61 | * @brief Timer_initialize start TM0 and TM1 |
---|
62 | * |
---|
63 | * @param None |
---|
64 | * @return None |
---|
65 | */ |
---|
66 | void Timer_initialize( void ) |
---|
67 | { |
---|
68 | GBA_REG_TM1CNT = 0x0000; /* Stop Counters */ |
---|
69 | GBA_REG_TM0CNT = 0x0000; |
---|
70 | GBA_REG_TM1D = 0x0000; /* Reset Counters */ |
---|
71 | GBA_REG_TM0D = 0x0000; |
---|
72 | /* Start Counters */ |
---|
73 | GBA_REG_TM1CNT = 0x0084; /* Start Count Up timing */ |
---|
74 | GBA_REG_TM0CNT = (0x0080|GBA_TM0CNT_PS); /* Start Count */ |
---|
75 | } |
---|
76 | |
---|
77 | /* |
---|
78 | * The following controls the behavior of Read_timer(). |
---|
79 | * |
---|
80 | * AVG_OVEREHAD is the overhead for starting and stopping the timer. It |
---|
81 | * is usually deducted from the number returned. |
---|
82 | * |
---|
83 | * LEAST_VALID is the lowest number this routine should trust. Numbers |
---|
84 | * below this are "noise" and zero is returned. |
---|
85 | */ |
---|
86 | |
---|
87 | #define AVG_OVERHEAD 3 /**< It typically takes 3 microseconds */ |
---|
88 | #define LEAST_VALID 1 /**< Don't trust a clicks value lower than this */ |
---|
89 | |
---|
90 | /** |
---|
91 | * @brief Read_timer return timer countervalue in microseconds. |
---|
92 | * |
---|
93 | * Used in Timing Test Suite. |
---|
94 | * |
---|
95 | * @param None |
---|
96 | * @return Timer value in microseconds |
---|
97 | */ |
---|
98 | uint32_t Read_timer( void ) |
---|
99 | { |
---|
100 | uint32_t ticks; |
---|
101 | uint32_t total; |
---|
102 | |
---|
103 | /* Stop Counters */ |
---|
104 | GBA_REG_TM0CNT = 0x0000; |
---|
105 | GBA_REG_TM1CNT = 0x0000; |
---|
106 | /* Read Counters */ |
---|
107 | ticks = (GBA_REG_TM1D<<16) | GBA_REG_TM0D; |
---|
108 | if ( ticks < LEAST_VALID ) { |
---|
109 | return 0; /* below timer resolution */ |
---|
110 | } |
---|
111 | /* convert to uS */ |
---|
112 | total = ((ticks * __TickTime_ns) / 1000); |
---|
113 | if ( Timer_driver_Find_average_overhead == 1 ) { |
---|
114 | return total; /* in microseconds */ |
---|
115 | } |
---|
116 | else { |
---|
117 | if ( total < AVG_OVERHEAD ) { |
---|
118 | return 0; |
---|
119 | } |
---|
120 | return (total - AVG_OVERHEAD); |
---|
121 | } |
---|
122 | } |
---|
123 | |
---|
124 | /** |
---|
125 | * @brief Empty function |
---|
126 | * |
---|
127 | * Empty function call used in loops to measure basic cost of looping |
---|
128 | * in Timing Test Suite. |
---|
129 | * |
---|
130 | * @param None |
---|
131 | * @return RTEMS_SUCCESSFUL |
---|
132 | */ |
---|
133 | rtems_status_code Empty_function( void ) |
---|
134 | { |
---|
135 | return RTEMS_SUCCESSFUL; |
---|
136 | } |
---|
137 | |
---|
138 | /** |
---|
139 | * @brief Set Timer_driver_Find_average_overhead flag. |
---|
140 | * |
---|
141 | * Used in Timing Test Suite. |
---|
142 | * |
---|
143 | * @param find_flag boolean find_flag |
---|
144 | * @return None |
---|
145 | */ |
---|
146 | void Set_find_average_overhead(rtems_boolean find_flag) |
---|
147 | { |
---|
148 | Timer_driver_Find_average_overhead = find_flag; |
---|
149 | } |
---|