[e945b049] | 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 | } |
---|