1 | /** |
---|
2 | * @file timer.c |
---|
3 | * |
---|
4 | * @ingroup lpc176x |
---|
5 | * |
---|
6 | * @brief Timer controller for the mbed lpc1768 board. |
---|
7 | */ |
---|
8 | |
---|
9 | /* |
---|
10 | * Copyright (c) 2014 Taller Technologies. |
---|
11 | * |
---|
12 | * @author Boretto Martin (martin.boretto@tallertechnologies.com) |
---|
13 | * @author Diaz Marcos (marcos.diaz@tallertechnologies.com) |
---|
14 | * @author Lenarduzzi Federico (federico.lenarduzzi@tallertechnologies.com) |
---|
15 | * @author Daniel Chicco (daniel.chicco@tallertechnologies.com) |
---|
16 | * |
---|
17 | * The license and distribution terms for this file may be |
---|
18 | * found in the file LICENSE in this distribution or at |
---|
19 | * http://www.rtems.org/license/LICENSE. |
---|
20 | */ |
---|
21 | |
---|
22 | #include <stdio.h> |
---|
23 | #include <rtems/status-checks.h> |
---|
24 | #include <bsp.h> |
---|
25 | #include <bsp/irq.h> |
---|
26 | #include <bsp/io.h> |
---|
27 | #include <bsp/timer.h> |
---|
28 | |
---|
29 | /** |
---|
30 | * @brief Represents all the timers. |
---|
31 | */ |
---|
32 | const lpc176x_timer timers[ LPC176X_TIMER_COUNT ] = |
---|
33 | { |
---|
34 | { |
---|
35 | .device = (lpc176x_timer_device *) LPC176X_TMR0_BASE_ADDR, |
---|
36 | .module = LPC176X_MODULE_TIMER_0, |
---|
37 | .pinselcap = LPC176X_TIMER0_CAPTURE_PORTS, |
---|
38 | .pinselemat = LPC176X_TIMER0_EMATCH_PORTS, |
---|
39 | }, |
---|
40 | { |
---|
41 | .device = (lpc176x_timer_device *) LPC176X_TMR1_BASE_ADDR, |
---|
42 | .module = LPC176X_MODULE_TIMER_1, |
---|
43 | .pinselcap = LPC176X_TIMER1_CAPTURE_PORTS, |
---|
44 | .pinselemat = LPC176X_TIMER1_EMATCH_PORTS, |
---|
45 | }, |
---|
46 | { |
---|
47 | .device = (lpc176x_timer_device *) LPC176X_TMR2_BASE_ADDR, |
---|
48 | .module = LPC176X_MODULE_TIMER_2, |
---|
49 | .pinselcap = LPC176X_TIMER2_CAPTURE_PORTS, |
---|
50 | .pinselemat = LPC176X_TIMER2_EMATCH_PORTS, |
---|
51 | }, |
---|
52 | { |
---|
53 | .device = (lpc176x_timer_device *) LPC176X_TMR3_BASE_ADDR, |
---|
54 | .module = LPC176X_MODULE_TIMER_3, |
---|
55 | .pinselcap = LPC176X_TIMER3_CAPTURE_PORTS, |
---|
56 | .pinselemat = LPC176X_TIMER3_EMATCH_PORTS, |
---|
57 | } |
---|
58 | }; |
---|
59 | |
---|
60 | /** |
---|
61 | * @brief Represents all the functions according to the timers. |
---|
62 | */ |
---|
63 | lpc176x_timer_functions functions_vector[ LPC176X_TIMER_COUNT ] = |
---|
64 | { |
---|
65 | { |
---|
66 | .funct_vector = NULL |
---|
67 | }, |
---|
68 | { |
---|
69 | .funct_vector = NULL |
---|
70 | }, |
---|
71 | { |
---|
72 | .funct_vector = NULL |
---|
73 | }, |
---|
74 | { |
---|
75 | .funct_vector = NULL |
---|
76 | } |
---|
77 | }; |
---|
78 | |
---|
79 | /** |
---|
80 | * @brief Calls the corresponding interrupt function and pass the timer |
---|
81 | * as parameter. |
---|
82 | * |
---|
83 | * @param timer The specific device. |
---|
84 | * @param interruptnumber Interrupt number. |
---|
85 | */ |
---|
86 | static inline void lpc176x_call_desired_isr( |
---|
87 | const lpc176x_timer_number number, |
---|
88 | const lpc176x_isr_function interruptfunction |
---|
89 | ) |
---|
90 | { |
---|
91 | if ( ( *functions_vector[ number ].funct_vector )[ interruptfunction ] != |
---|
92 | NULL ) { |
---|
93 | ( *functions_vector[ number ].funct_vector )[ interruptfunction ]( number ); |
---|
94 | } |
---|
95 | |
---|
96 | /* else implies that the function vector points NULL. Also, |
---|
97 | there is nothing to do. */ |
---|
98 | } |
---|
99 | |
---|
100 | /** |
---|
101 | * @brief Gets true if the selected interrupt is pending |
---|
102 | * |
---|
103 | * @param number: the number of the timer. |
---|
104 | * @param interrupt: the interrupt we are checking for. |
---|
105 | * @return TRUE if the interrupt is pending. |
---|
106 | */ |
---|
107 | static inline bool lpc176x_timer_interrupt_is_pending( |
---|
108 | const lpc176x_timer_number tnumber, |
---|
109 | const lpc176x_isr_function function |
---|
110 | ) |
---|
111 | { |
---|
112 | assert( ( tnumber < LPC176X_TIMER_COUNT ) |
---|
113 | && ( function < LPC176X_ISR_FUNCTIONS_COUNT ) ); |
---|
114 | |
---|
115 | return ( timers[ tnumber ].device->IR & |
---|
116 | LPC176X_TIMER_INTERRUPT_SOURCE_BIT( function ) ); |
---|
117 | } |
---|
118 | |
---|
119 | /** |
---|
120 | * @brief Resets interrupt status for the selected interrupt |
---|
121 | * |
---|
122 | * @param tnumber: the number of the timer |
---|
123 | * @param interrupt: the interrupt we are resetting |
---|
124 | */ |
---|
125 | static inline void lpc176x_timer_reset_interrupt( |
---|
126 | const lpc176x_timer_number tnumber, |
---|
127 | const lpc176x_isr_function function |
---|
128 | ) |
---|
129 | { |
---|
130 | assert( ( tnumber < LPC176X_TIMER_COUNT ) |
---|
131 | && ( function < LPC176X_ISR_FUNCTIONS_COUNT ) ); |
---|
132 | timers[ tnumber ].device->IR = |
---|
133 | LPC176X_TIMER_INTERRUPT_SOURCE_BIT( function ); |
---|
134 | } |
---|
135 | |
---|
136 | inline rtems_status_code lpc176x_timer_reset( |
---|
137 | const lpc176x_timer_number tnumber ) |
---|
138 | { |
---|
139 | rtems_status_code status_code = RTEMS_INVALID_NUMBER; |
---|
140 | |
---|
141 | if ( tnumber < LPC176X_TIMER_COUNT ) { |
---|
142 | timers[ tnumber ].device->TCR = LPC176X_TIMER_RESET; |
---|
143 | status_code = RTEMS_SUCCESSFUL; |
---|
144 | } |
---|
145 | |
---|
146 | /* else implies that the timer number is invalid. Also, |
---|
147 | an invalid number is returned. */ |
---|
148 | |
---|
149 | return status_code; |
---|
150 | } |
---|
151 | |
---|
152 | inline rtems_status_code lpc176x_timer_set_mode( |
---|
153 | const lpc176x_timer_number tnumber, |
---|
154 | const lpc176x_timer_mode mode |
---|
155 | ) |
---|
156 | { |
---|
157 | rtems_status_code status_code = RTEMS_INVALID_NUMBER; |
---|
158 | |
---|
159 | if ( tnumber < LPC176X_TIMER_COUNT ) { |
---|
160 | timers[ tnumber ].device->CTCR = mode; |
---|
161 | status_code = RTEMS_SUCCESSFUL; |
---|
162 | } |
---|
163 | |
---|
164 | /* else implies that the timer number is invalid. Also, |
---|
165 | an invalid number is returned. */ |
---|
166 | |
---|
167 | return status_code; |
---|
168 | } |
---|
169 | |
---|
170 | inline rtems_status_code lpc176x_timer_start( |
---|
171 | const lpc176x_timer_number tnumber ) |
---|
172 | { |
---|
173 | rtems_status_code status_code = RTEMS_INVALID_NUMBER; |
---|
174 | |
---|
175 | if ( tnumber < LPC176X_TIMER_COUNT ) { |
---|
176 | timers[ tnumber ].device->TCR = LPC176X_TIMER_START; |
---|
177 | status_code = RTEMS_SUCCESSFUL; |
---|
178 | } |
---|
179 | |
---|
180 | /* else implies that the timer number is invalid. Also, |
---|
181 | an invalid number is returned. */ |
---|
182 | |
---|
183 | return status_code; |
---|
184 | } |
---|
185 | |
---|
186 | inline rtems_status_code lpc176x_timer_is_started( |
---|
187 | const lpc176x_timer_number tnumber, |
---|
188 | bool *is_started |
---|
189 | ) |
---|
190 | { |
---|
191 | rtems_status_code status_code = RTEMS_INVALID_NUMBER; |
---|
192 | |
---|
193 | if ( tnumber < LPC176X_TIMER_COUNT ) { |
---|
194 | *is_started = ( timers[ tnumber ].device->TCR & LPC176X_TIMER_START ) == |
---|
195 | LPC176X_TIMER_START; |
---|
196 | status_code = RTEMS_SUCCESSFUL; |
---|
197 | } |
---|
198 | |
---|
199 | /* else implies that the timer number is invalid. Also, |
---|
200 | an invalid number is returned. */ |
---|
201 | |
---|
202 | return status_code; |
---|
203 | } |
---|
204 | |
---|
205 | inline rtems_status_code lpc176x_timer_set_resolution( |
---|
206 | const lpc176x_timer_number tnumber, |
---|
207 | const lpc176x_microseconds resolution |
---|
208 | ) |
---|
209 | { |
---|
210 | rtems_status_code status_code = RTEMS_INVALID_NUMBER; |
---|
211 | |
---|
212 | if ( tnumber < LPC176X_TIMER_COUNT ) { |
---|
213 | timers[ tnumber ].device->PR = ( LPC176X_CCLK / |
---|
214 | LPC176X_TIMER_PRESCALER_DIVISOR ) * |
---|
215 | resolution; |
---|
216 | status_code = RTEMS_SUCCESSFUL; |
---|
217 | } |
---|
218 | |
---|
219 | /* else implies that the timer number is invalid. Also, |
---|
220 | an invalid number is returned. */ |
---|
221 | |
---|
222 | return status_code; |
---|
223 | } |
---|
224 | |
---|
225 | rtems_status_code lpc176x_timer_match_config( |
---|
226 | const lpc176x_timer_number tnumber, |
---|
227 | const lpc176x_match_port match_port, |
---|
228 | const lpc176x_match_function function, |
---|
229 | const uint32_t match_value |
---|
230 | ) |
---|
231 | { |
---|
232 | rtems_status_code status_code = RTEMS_INVALID_NUMBER; |
---|
233 | |
---|
234 | if ( ( tnumber < LPC176X_TIMER_COUNT ) |
---|
235 | && ( match_port < LPC176X_EMATCH_PORTS_COUNT ) |
---|
236 | && ( function < LPC176X_TIMER_MATCH_FUNCTION_COUNT ) ) { |
---|
237 | timers[ tnumber ].device->MCR = |
---|
238 | LPC176X_SET_MCR( timers[ tnumber ].device->MCR, |
---|
239 | match_port, function ); |
---|
240 | timers[ tnumber ].device->MR[ match_port ] = match_value; |
---|
241 | status_code = RTEMS_SUCCESSFUL; |
---|
242 | } |
---|
243 | |
---|
244 | /* else implies that the timer number, or a match port or a function |
---|
245 | is invalid. Also, an invalid number is returned. */ |
---|
246 | |
---|
247 | return status_code; |
---|
248 | } |
---|
249 | |
---|
250 | inline rtems_status_code lpc176x_timer_capture_config( |
---|
251 | const lpc176x_timer_number tnumber, |
---|
252 | const lpc176x_capture_port capture_port, |
---|
253 | const lpc176x_capture_function function |
---|
254 | ) |
---|
255 | { |
---|
256 | rtems_status_code status_code = RTEMS_INVALID_NUMBER; |
---|
257 | |
---|
258 | if ( ( tnumber < LPC176X_TIMER_COUNT ) |
---|
259 | && ( capture_port < LPC176X_CAPTURE_PORTS_COUNT ) |
---|
260 | && ( function < LPC176X_TIMER_CAPTURE_FUNCTION_COUNT ) ) { |
---|
261 | timers[ tnumber ].device->CCR = |
---|
262 | LPC176X_SET_CCR( timers[ tnumber ].device->CCR, |
---|
263 | capture_port, function ); |
---|
264 | lpc176x_pin_select( timers[ tnumber ].pinselcap[ capture_port ], |
---|
265 | LPC176X_PIN_FUNCTION_11 ); |
---|
266 | } |
---|
267 | |
---|
268 | /* else implies that the timer number or the capture port is invalid. Also, |
---|
269 | an invalid number is returned. */ |
---|
270 | |
---|
271 | return status_code; |
---|
272 | } |
---|
273 | |
---|
274 | inline rtems_status_code lpc176x_timer_external_match_config( |
---|
275 | const lpc176x_timer_number number, |
---|
276 | const lpc176x_match_port match_port, |
---|
277 | const lpc176x_ext_match_function function |
---|
278 | ) |
---|
279 | { |
---|
280 | rtems_status_code status_code = RTEMS_INVALID_NUMBER; |
---|
281 | |
---|
282 | if ( ( number < LPC176X_TIMER_COUNT ) |
---|
283 | && ( match_port < LPC176X_EMATCH_PORTS_COUNT ) ) { |
---|
284 | timers[ number ].device->EMR = |
---|
285 | LPC176X_SET_EMR( timers[ number ].device->EMR, |
---|
286 | match_port, function ); |
---|
287 | lpc176x_pin_select( timers[ number ].pinselemat[ match_port ], |
---|
288 | LPC176X_PIN_FUNCTION_11 ); |
---|
289 | status_code = RTEMS_SUCCESSFUL; |
---|
290 | } |
---|
291 | |
---|
292 | /* else implies that the timer number or the match port is invalid. Also, |
---|
293 | an invalid number is returned. */ |
---|
294 | |
---|
295 | return status_code; |
---|
296 | } |
---|
297 | |
---|
298 | inline uint32_t lpc176x_timer_get_capvalue( |
---|
299 | const lpc176x_timer_number number, |
---|
300 | const lpc176x_capture_port capture_port |
---|
301 | ) |
---|
302 | { |
---|
303 | assert( ( number < LPC176X_TIMER_COUNT ) |
---|
304 | && ( capture_port < LPC176X_CAPTURE_PORTS_COUNT ) ); |
---|
305 | |
---|
306 | return timers[ number ].device->CR[ capture_port ]; |
---|
307 | } |
---|
308 | |
---|
309 | inline uint32_t lpc176x_timer_get_timer_value( |
---|
310 | const lpc176x_timer_number tnumber ) |
---|
311 | { |
---|
312 | assert( tnumber < LPC176X_TIMER_COUNT ); |
---|
313 | |
---|
314 | return timers[ tnumber ].device->TC; |
---|
315 | } |
---|
316 | |
---|
317 | inline rtems_status_code lpc176x_timer_set_timer_value( |
---|
318 | const lpc176x_timer_number tnumber, |
---|
319 | const uint32_t timer_value |
---|
320 | ) |
---|
321 | { |
---|
322 | rtems_status_code status_code = RTEMS_INVALID_NUMBER; |
---|
323 | |
---|
324 | if ( tnumber < LPC176X_TIMER_COUNT ) { |
---|
325 | timers[ tnumber ].device->TC = timer_value; |
---|
326 | status_code = RTEMS_SUCCESSFUL; |
---|
327 | } |
---|
328 | |
---|
329 | /* else implies that the timer number is invalid. Also, |
---|
330 | an invalid number is returned. */ |
---|
331 | |
---|
332 | return status_code; |
---|
333 | } |
---|
334 | |
---|
335 | void lpc176x_timer_isr( void *arg ) |
---|
336 | { |
---|
337 | const lpc176x_timer_number tnumber = (lpc176x_timer_number) arg; |
---|
338 | |
---|
339 | if ( tnumber < LPC176X_TIMER_COUNT ) { |
---|
340 | lpc176x_isr_function i; |
---|
341 | |
---|
342 | for ( i = 0; i < LPC176X_ISR_FUNCTIONS_COUNT; ++i ) { |
---|
343 | if ( lpc176x_timer_interrupt_is_pending( tnumber, i ) ) { |
---|
344 | lpc176x_call_desired_isr( tnumber, i ); |
---|
345 | lpc176x_timer_reset_interrupt( tnumber, i ); |
---|
346 | } |
---|
347 | |
---|
348 | /* else implies that the current timer is not pending. Also, |
---|
349 | there is nothing to do. */ |
---|
350 | } |
---|
351 | } |
---|
352 | |
---|
353 | /* else implies that the timer number is not valid. Also, |
---|
354 | there is nothing to do. */ |
---|
355 | } |
---|
356 | |
---|
357 | rtems_status_code lpc176x_timer_init( const lpc176x_timer_number tnumber ) |
---|
358 | { |
---|
359 | rtems_status_code status_code = RTEMS_INVALID_NUMBER; |
---|
360 | |
---|
361 | if ( tnumber < LPC176X_TIMER_COUNT ) { |
---|
362 | status_code = lpc176x_module_enable( timers[ tnumber ].module, |
---|
363 | LPC176X_MODULE_PCLK_DEFAULT ); |
---|
364 | RTEMS_CHECK_SC( status_code, "Enabling the timer module." ); |
---|
365 | |
---|
366 | status_code = lpc176x_timer_reset( tnumber ); |
---|
367 | status_code = lpc176x_timer_set_mode( tnumber, |
---|
368 | LPC176X_TIMER_MODE_TIMER ); |
---|
369 | status_code = lpc176x_timer_set_resolution( tnumber, |
---|
370 | LPC176X_TIMER_DEFAULT_RESOLUTION ); |
---|
371 | |
---|
372 | timers[ tnumber ].device->MCR = LPC176X_TIMER_CLEAR_FUNCTION; |
---|
373 | timers[ tnumber ].device->CCR = LPC176X_TIMER_CLEAR_FUNCTION; |
---|
374 | timers[ tnumber ].device->EMR = LPC176X_TIMER_CLEAR_FUNCTION; |
---|
375 | } |
---|
376 | |
---|
377 | /* else implies that the timer number is not valid. Also, |
---|
378 | an invalid number is returned. */ |
---|
379 | |
---|
380 | return status_code; |
---|
381 | } |
---|
382 | |
---|
383 | rtems_status_code lpc176x_timer_init_with_interrupt( |
---|
384 | const lpc176x_timer_number tnumber, |
---|
385 | const lpc176x_isr_funct_vector *const vector |
---|
386 | ) |
---|
387 | { |
---|
388 | rtems_status_code status_code = RTEMS_INVALID_NUMBER; |
---|
389 | |
---|
390 | char isrname[ LPC176X_ISR_NAME_STRING_SIZE ]; |
---|
391 | |
---|
392 | snprintf( isrname, LPC176X_ISR_NAME_STRING_SIZE, "TimerIsr%d", tnumber ); |
---|
393 | |
---|
394 | if ( tnumber < LPC176X_TIMER_COUNT && vector != NULL ) { |
---|
395 | functions_vector[ tnumber ].funct_vector = vector; |
---|
396 | |
---|
397 | status_code = lpc176x_timer_init( tnumber ); |
---|
398 | status_code = rtems_interrupt_handler_install( |
---|
399 | LPC176X_TIMER_VECTOR_NUMBER( tnumber ), |
---|
400 | isrname, |
---|
401 | RTEMS_INTERRUPT_UNIQUE, |
---|
402 | lpc176x_timer_isr, |
---|
403 | (void *) tnumber ); |
---|
404 | } |
---|
405 | |
---|
406 | return status_code; |
---|
407 | } |
---|