1 /*****************************************************************************
2 * Copyright 2003 - 2008 Broadcom Corporation. All rights reserved.
4 * Unless you and Broadcom execute a separate written software license
5 * agreement governing use of this software, this software is licensed to you
6 * under the terms of the GNU General Public License version 2, available at
7 * http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
9 * Notwithstanding the above, under no circumstances may you combine this
10 * software in any way with any other Broadcom software provided under a
11 * license other than the GPL, without Broadcom's express prior written
13 *****************************************************************************/
15 /****************************************************************************/
19 * @brief Low level Timer driver routines
23 * These routines provide basic timer functionality only.
25 /****************************************************************************/
27 /* ---- Include Files ---------------------------------------------------- */
29 #include <csp/errno.h>
30 #include <csp/stdint.h>
32 #include <csp/tmrHw.h>
33 #include <mach/csp/tmrHw_reg.h>
35 #define tmrHw_ASSERT(a) if (!(a)) *(char *)0 = 0
36 #define tmrHw_MILLISEC_PER_SEC (1000)
38 #define tmrHw_LOW_1_RESOLUTION_COUNT (tmrHw_LOW_RESOLUTION_CLOCK / tmrHw_MILLISEC_PER_SEC)
39 #define tmrHw_LOW_1_MAX_MILLISEC (0xFFFFFFFF / tmrHw_LOW_1_RESOLUTION_COUNT)
40 #define tmrHw_LOW_16_RESOLUTION_COUNT (tmrHw_LOW_1_RESOLUTION_COUNT / 16)
41 #define tmrHw_LOW_16_MAX_MILLISEC (0xFFFFFFFF / tmrHw_LOW_16_RESOLUTION_COUNT)
42 #define tmrHw_LOW_256_RESOLUTION_COUNT (tmrHw_LOW_1_RESOLUTION_COUNT / 256)
43 #define tmrHw_LOW_256_MAX_MILLISEC (0xFFFFFFFF / tmrHw_LOW_256_RESOLUTION_COUNT)
45 #define tmrHw_HIGH_1_RESOLUTION_COUNT (tmrHw_HIGH_RESOLUTION_CLOCK / tmrHw_MILLISEC_PER_SEC)
46 #define tmrHw_HIGH_1_MAX_MILLISEC (0xFFFFFFFF / tmrHw_HIGH_1_RESOLUTION_COUNT)
47 #define tmrHw_HIGH_16_RESOLUTION_COUNT (tmrHw_HIGH_1_RESOLUTION_COUNT / 16)
48 #define tmrHw_HIGH_16_MAX_MILLISEC (0xFFFFFFFF / tmrHw_HIGH_16_RESOLUTION_COUNT)
49 #define tmrHw_HIGH_256_RESOLUTION_COUNT (tmrHw_HIGH_1_RESOLUTION_COUNT / 256)
50 #define tmrHw_HIGH_256_MAX_MILLISEC (0xFFFFFFFF / tmrHw_HIGH_256_RESOLUTION_COUNT)
52 static void ResetTimer(tmrHw_ID_t timerId
)
53 __attribute__ ((section(".aramtext")));
54 static int tmrHw_divide(int num
, int denom
)
55 __attribute__ ((section(".aramtext")));
57 /****************************************************************************/
59 * @brief Get timer capability
61 * This function returns various capabilities/attributes of a timer
66 /****************************************************************************/
67 uint32_t tmrHw_getTimerCapability(tmrHw_ID_t timerId
, /* [ IN ] Timer Id */
68 tmrHw_CAPABILITY_e capability
/* [ IN ] Timer capability */
71 case tmrHw_CAPABILITY_CLOCK
:
73 1) ? tmrHw_LOW_RESOLUTION_CLOCK
:
74 tmrHw_HIGH_RESOLUTION_CLOCK
;
75 case tmrHw_CAPABILITY_RESOLUTION
:
83 /****************************************************************************/
85 * @brief Resets a timer
87 * This function initializes timer
92 /****************************************************************************/
93 static void ResetTimer(tmrHw_ID_t timerId
/* [ IN ] Timer Id */
96 pTmrHw
[timerId
].LoadValue
= 0;
97 pTmrHw
[timerId
].CurrentValue
= 0xFFFFFFFF;
98 pTmrHw
[timerId
].Control
= 0;
99 pTmrHw
[timerId
].BackgroundLoad
= 0;
100 /* Always configure as a 32 bit timer */
101 pTmrHw
[timerId
].Control
|= tmrHw_CONTROL_32BIT
;
102 /* Clear interrupt only if raw status interrupt is set */
103 if (pTmrHw
[timerId
].RawInterruptStatus
) {
104 pTmrHw
[timerId
].InterruptClear
= 0xFFFFFFFF;
108 /****************************************************************************/
110 * @brief Sets counter value for an interval in ms
112 * @return On success: Effective counter value set
116 /****************************************************************************/
117 static tmrHw_INTERVAL_t
SetTimerPeriod(tmrHw_ID_t timerId
, /* [ IN ] Timer Id */
118 tmrHw_INTERVAL_t msec
/* [ IN ] Interval in milli-second */
123 if (timerId
== 0 || timerId
== 1) {
124 if (msec
<= tmrHw_LOW_1_MAX_MILLISEC
) {
125 pTmrHw
[timerId
].Control
|= tmrHw_CONTROL_PRESCALE_1
;
126 scale
= tmrHw_LOW_1_RESOLUTION_COUNT
;
127 } else if (msec
<= tmrHw_LOW_16_MAX_MILLISEC
) {
128 pTmrHw
[timerId
].Control
|= tmrHw_CONTROL_PRESCALE_16
;
129 scale
= tmrHw_LOW_16_RESOLUTION_COUNT
;
130 } else if (msec
<= tmrHw_LOW_256_MAX_MILLISEC
) {
131 pTmrHw
[timerId
].Control
|= tmrHw_CONTROL_PRESCALE_256
;
132 scale
= tmrHw_LOW_256_RESOLUTION_COUNT
;
137 count
= msec
* scale
;
138 /* Set counter value */
139 pTmrHw
[timerId
].LoadValue
= count
;
140 pTmrHw
[timerId
].BackgroundLoad
= count
;
142 } else if (timerId
== 2 || timerId
== 3) {
143 if (msec
<= tmrHw_HIGH_1_MAX_MILLISEC
) {
144 pTmrHw
[timerId
].Control
|= tmrHw_CONTROL_PRESCALE_1
;
145 scale
= tmrHw_HIGH_1_RESOLUTION_COUNT
;
146 } else if (msec
<= tmrHw_HIGH_16_MAX_MILLISEC
) {
147 pTmrHw
[timerId
].Control
|= tmrHw_CONTROL_PRESCALE_16
;
148 scale
= tmrHw_HIGH_16_RESOLUTION_COUNT
;
149 } else if (msec
<= tmrHw_HIGH_256_MAX_MILLISEC
) {
150 pTmrHw
[timerId
].Control
|= tmrHw_CONTROL_PRESCALE_256
;
151 scale
= tmrHw_HIGH_256_RESOLUTION_COUNT
;
156 count
= msec
* scale
;
157 /* Set counter value */
158 pTmrHw
[timerId
].LoadValue
= count
;
159 pTmrHw
[timerId
].BackgroundLoad
= count
;
161 return count
/ scale
;
164 /****************************************************************************/
166 * @brief Configures a periodic timer in terms of timer interrupt rate
168 * This function initializes a periodic timer to generate specific number of
169 * timer interrupt per second
171 * @return On success: Effective timer frequency
175 /****************************************************************************/
176 tmrHw_RATE_t
tmrHw_setPeriodicTimerRate(tmrHw_ID_t timerId
, /* [ IN ] Timer Id */
177 tmrHw_RATE_t rate
/* [ IN ] Number of timer interrupt per second */
179 uint32_t resolution
= 0;
183 /* Set timer mode periodic */
184 pTmrHw
[timerId
].Control
|= tmrHw_CONTROL_PERIODIC
;
185 pTmrHw
[timerId
].Control
&= ~tmrHw_CONTROL_ONESHOT
;
186 /* Set timer in highest resolution */
187 pTmrHw
[timerId
].Control
|= tmrHw_CONTROL_PRESCALE_1
;
189 if (rate
&& (timerId
== 0 || timerId
== 1)) {
190 if (rate
> tmrHw_LOW_RESOLUTION_CLOCK
) {
193 resolution
= tmrHw_LOW_RESOLUTION_CLOCK
;
194 } else if (rate
&& (timerId
== 2 || timerId
== 3)) {
195 if (rate
> tmrHw_HIGH_RESOLUTION_CLOCK
) {
198 resolution
= tmrHw_HIGH_RESOLUTION_CLOCK
;
203 /* Find the counter value */
204 count
= resolution
/ rate
;
205 /* Set counter value */
206 pTmrHw
[timerId
].LoadValue
= count
;
207 pTmrHw
[timerId
].BackgroundLoad
= count
;
209 return resolution
/ count
;
212 /****************************************************************************/
214 * @brief Configures a periodic timer to generate timer interrupt after
215 * certain time interval
217 * This function initializes a periodic timer to generate timer interrupt
218 * after every time interval in millisecond
220 * @return On success: Effective interval set in milli-second
224 /****************************************************************************/
225 tmrHw_INTERVAL_t
tmrHw_setPeriodicTimerInterval(tmrHw_ID_t timerId
, /* [ IN ] Timer Id */
226 tmrHw_INTERVAL_t msec
/* [ IN ] Interval in milli-second */
230 /* Set timer mode periodic */
231 pTmrHw
[timerId
].Control
|= tmrHw_CONTROL_PERIODIC
;
232 pTmrHw
[timerId
].Control
&= ~tmrHw_CONTROL_ONESHOT
;
234 return SetTimerPeriod(timerId
, msec
);
237 /****************************************************************************/
239 * @brief Configures a periodic timer to generate timer interrupt just once
240 * after certain time interval
242 * This function initializes a periodic timer to generate a single ticks after
243 * certain time interval in millisecond
245 * @return On success: Effective interval set in milli-second
249 /****************************************************************************/
250 tmrHw_INTERVAL_t
tmrHw_setOneshotTimerInterval(tmrHw_ID_t timerId
, /* [ IN ] Timer Id */
251 tmrHw_INTERVAL_t msec
/* [ IN ] Interval in milli-second */
255 /* Set timer mode oneshot */
256 pTmrHw
[timerId
].Control
|= tmrHw_CONTROL_PERIODIC
;
257 pTmrHw
[timerId
].Control
|= tmrHw_CONTROL_ONESHOT
;
259 return SetTimerPeriod(timerId
, msec
);
262 /****************************************************************************/
264 * @brief Configures a timer to run as a free running timer
266 * This function initializes a timer to run as a free running timer
268 * @return Timer resolution (count / sec)
271 /****************************************************************************/
272 tmrHw_RATE_t
tmrHw_setFreeRunningTimer(tmrHw_ID_t timerId
, /* [ IN ] Timer Id */
273 uint32_t divider
/* [ IN ] Dividing the clock frequency */
278 /* Set timer as free running mode */
279 pTmrHw
[timerId
].Control
&= ~tmrHw_CONTROL_PERIODIC
;
280 pTmrHw
[timerId
].Control
&= ~tmrHw_CONTROL_ONESHOT
;
283 pTmrHw
[timerId
].Control
|= tmrHw_CONTROL_PRESCALE_256
;
285 } else if (divider
>= 8) {
286 pTmrHw
[timerId
].Control
|= tmrHw_CONTROL_PRESCALE_16
;
289 pTmrHw
[timerId
].Control
|= tmrHw_CONTROL_PRESCALE_1
;
293 if (timerId
== 0 || timerId
== 1) {
294 return tmrHw_divide(tmrHw_LOW_RESOLUTION_CLOCK
, scale
);
295 } else if (timerId
== 2 || timerId
== 3) {
296 return tmrHw_divide(tmrHw_HIGH_RESOLUTION_CLOCK
, scale
);
302 /****************************************************************************/
304 * @brief Starts a timer
306 * This function starts a preconfigured timer
308 * @return -1 - On Failure
312 /****************************************************************************/
313 int tmrHw_startTimer(tmrHw_ID_t timerId
/* [ IN ] Timer id */
315 pTmrHw
[timerId
].Control
|= tmrHw_CONTROL_TIMER_ENABLE
;
319 /****************************************************************************/
321 * @brief Stops a timer
323 * This function stops a running timer
325 * @return -1 - On Failure
329 /****************************************************************************/
330 int tmrHw_stopTimer(tmrHw_ID_t timerId
/* [ IN ] Timer id */
332 pTmrHw
[timerId
].Control
&= ~tmrHw_CONTROL_TIMER_ENABLE
;
336 /****************************************************************************/
338 * @brief Gets current timer count
340 * This function returns the current timer value
342 * @return Current downcounting timer value
345 /****************************************************************************/
346 uint32_t tmrHw_GetCurrentCount(tmrHw_ID_t timerId
/* [ IN ] Timer id */
348 /* return 32 bit timer value */
349 switch (pTmrHw
[timerId
].Control
& tmrHw_CONTROL_MODE_MASK
) {
350 case tmrHw_CONTROL_FREE_RUNNING
:
351 if (pTmrHw
[timerId
].CurrentValue
) {
352 return tmrHw_MAX_COUNT
- pTmrHw
[timerId
].CurrentValue
;
355 case tmrHw_CONTROL_PERIODIC
:
356 case tmrHw_CONTROL_ONESHOT
:
357 return pTmrHw
[timerId
].BackgroundLoad
-
358 pTmrHw
[timerId
].CurrentValue
;
363 /****************************************************************************/
365 * @brief Gets timer count rate
367 * This function returns the number of counts per second
372 /****************************************************************************/
373 tmrHw_RATE_t
tmrHw_getCountRate(tmrHw_ID_t timerId
/* [ IN ] Timer id */
375 uint32_t divider
= 0;
377 switch (pTmrHw
[timerId
].Control
& tmrHw_CONTROL_PRESCALE_MASK
) {
378 case tmrHw_CONTROL_PRESCALE_1
:
381 case tmrHw_CONTROL_PRESCALE_16
:
384 case tmrHw_CONTROL_PRESCALE_256
:
391 if (timerId
== 0 || timerId
== 1) {
392 return tmrHw_divide(tmrHw_LOW_RESOLUTION_CLOCK
, divider
);
394 return tmrHw_divide(tmrHw_HIGH_RESOLUTION_CLOCK
, divider
);
399 /****************************************************************************/
401 * @brief Enables timer interrupt
403 * This function enables the timer interrupt
408 /****************************************************************************/
409 void tmrHw_enableInterrupt(tmrHw_ID_t timerId
/* [ IN ] Timer id */
411 pTmrHw
[timerId
].Control
|= tmrHw_CONTROL_INTERRUPT_ENABLE
;
414 /****************************************************************************/
416 * @brief Disables timer interrupt
418 * This function disable the timer interrupt
423 /****************************************************************************/
424 void tmrHw_disableInterrupt(tmrHw_ID_t timerId
/* [ IN ] Timer id */
426 pTmrHw
[timerId
].Control
&= ~tmrHw_CONTROL_INTERRUPT_ENABLE
;
429 /****************************************************************************/
431 * @brief Clears the interrupt
433 * This function clears the timer interrupt
438 * Must be called under the context of ISR
440 /****************************************************************************/
441 void tmrHw_clearInterrupt(tmrHw_ID_t timerId
/* [ IN ] Timer id */
443 pTmrHw
[timerId
].InterruptClear
= 0x1;
446 /****************************************************************************/
448 * @brief Gets the interrupt status
450 * This function returns timer interrupt status
452 * @return Interrupt status
454 /****************************************************************************/
455 tmrHw_INTERRUPT_STATUS_e
tmrHw_getInterruptStatus(tmrHw_ID_t timerId
/* [ IN ] Timer id */
457 if (pTmrHw
[timerId
].InterruptStatus
) {
458 return tmrHw_INTERRUPT_STATUS_SET
;
460 return tmrHw_INTERRUPT_STATUS_UNSET
;
464 /****************************************************************************/
466 * @brief Indentifies a timer causing interrupt
468 * This functions returns a timer causing interrupt
470 * @return 0xFFFFFFFF : No timer causing an interrupt
471 * ! 0xFFFFFFFF : timer causing an interrupt
473 * tmrHw_clearIntrrupt() must be called with a valid timer id after calling this function
475 /****************************************************************************/
476 tmrHw_ID_t
tmrHw_getInterruptSource(void /* void */
480 for (i
= 0; i
< tmrHw_TIMER_NUM_COUNT
; i
++) {
481 if (pTmrHw
[i
].InterruptStatus
) {
489 /****************************************************************************/
491 * @brief Displays specific timer registers
497 /****************************************************************************/
498 void tmrHw_printDebugInfo(tmrHw_ID_t timerId
, /* [ IN ] Timer id */
499 int (*fpPrint
) (const char *, ...) /* [ IN ] Print callback function */
501 (*fpPrint
) ("Displaying register contents \n\n");
502 (*fpPrint
) ("Timer %d: Load value 0x%X\n", timerId
,
503 pTmrHw
[timerId
].LoadValue
);
504 (*fpPrint
) ("Timer %d: Background load value 0x%X\n", timerId
,
505 pTmrHw
[timerId
].BackgroundLoad
);
506 (*fpPrint
) ("Timer %d: Control 0x%X\n", timerId
,
507 pTmrHw
[timerId
].Control
);
508 (*fpPrint
) ("Timer %d: Interrupt clear 0x%X\n", timerId
,
509 pTmrHw
[timerId
].InterruptClear
);
510 (*fpPrint
) ("Timer %d: Interrupt raw interrupt 0x%X\n", timerId
,
511 pTmrHw
[timerId
].RawInterruptStatus
);
512 (*fpPrint
) ("Timer %d: Interrupt status 0x%X\n", timerId
,
513 pTmrHw
[timerId
].InterruptStatus
);
516 /****************************************************************************/
518 * @brief Use a timer to perform a busy wait delay for a number of usecs.
522 /****************************************************************************/
523 void tmrHw_udelay(tmrHw_ID_t timerId
, /* [ IN ] Timer id */
524 unsigned long usecs
/* [ IN ] usec to delay */
526 tmrHw_RATE_t usec_tick_rate
;
527 tmrHw_COUNT_t start_time
;
528 tmrHw_COUNT_t delta_time
;
530 start_time
= tmrHw_GetCurrentCount(timerId
);
531 usec_tick_rate
= tmrHw_divide(tmrHw_getCountRate(timerId
), 1000000);
532 delta_time
= usecs
* usec_tick_rate
;
535 while (delta_time
> (tmrHw_GetCurrentCount(timerId
) - start_time
))
539 /****************************************************************************/
541 * @brief Local Divide function
543 * This function does the divide
545 * @return divide value
548 /****************************************************************************/
549 static int tmrHw_divide(int num
, int denom
)
554 /* Shift denom and t up to the largest value to optimize algorithm */
555 /* t contains the units of each divide */
556 while ((denom
& 0x40000000) == 0) { /* fails if denom=0 */
561 /* Initialize the result */
565 /* Determine if there exists a positive remainder */
566 if ((num
- denom
) >= 0) {
567 /* Accumlate t to the result and calculate a new remainder */
571 /* Continue to shift denom and shift t down to 0 */