tmrHw.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576
  1. /*****************************************************************************
  2. * Copyright 2003 - 2008 Broadcom Corporation. All rights reserved.
  3. *
  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").
  8. *
  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
  12. * consent.
  13. *****************************************************************************/
  14. /****************************************************************************/
  15. /**
  16. * @file tmrHw.c
  17. *
  18. * @brief Low level Timer driver routines
  19. *
  20. * @note
  21. *
  22. * These routines provide basic timer functionality only.
  23. */
  24. /****************************************************************************/
  25. /* ---- Include Files ---------------------------------------------------- */
  26. #include <csp/errno.h>
  27. #include <csp/stdint.h>
  28. #include <csp/tmrHw.h>
  29. #include <mach/csp/tmrHw_reg.h>
  30. #define tmrHw_ASSERT(a) if (!(a)) *(char *)0 = 0
  31. #define tmrHw_MILLISEC_PER_SEC (1000)
  32. #define tmrHw_LOW_1_RESOLUTION_COUNT (tmrHw_LOW_RESOLUTION_CLOCK / tmrHw_MILLISEC_PER_SEC)
  33. #define tmrHw_LOW_1_MAX_MILLISEC (0xFFFFFFFF / tmrHw_LOW_1_RESOLUTION_COUNT)
  34. #define tmrHw_LOW_16_RESOLUTION_COUNT (tmrHw_LOW_1_RESOLUTION_COUNT / 16)
  35. #define tmrHw_LOW_16_MAX_MILLISEC (0xFFFFFFFF / tmrHw_LOW_16_RESOLUTION_COUNT)
  36. #define tmrHw_LOW_256_RESOLUTION_COUNT (tmrHw_LOW_1_RESOLUTION_COUNT / 256)
  37. #define tmrHw_LOW_256_MAX_MILLISEC (0xFFFFFFFF / tmrHw_LOW_256_RESOLUTION_COUNT)
  38. #define tmrHw_HIGH_1_RESOLUTION_COUNT (tmrHw_HIGH_RESOLUTION_CLOCK / tmrHw_MILLISEC_PER_SEC)
  39. #define tmrHw_HIGH_1_MAX_MILLISEC (0xFFFFFFFF / tmrHw_HIGH_1_RESOLUTION_COUNT)
  40. #define tmrHw_HIGH_16_RESOLUTION_COUNT (tmrHw_HIGH_1_RESOLUTION_COUNT / 16)
  41. #define tmrHw_HIGH_16_MAX_MILLISEC (0xFFFFFFFF / tmrHw_HIGH_16_RESOLUTION_COUNT)
  42. #define tmrHw_HIGH_256_RESOLUTION_COUNT (tmrHw_HIGH_1_RESOLUTION_COUNT / 256)
  43. #define tmrHw_HIGH_256_MAX_MILLISEC (0xFFFFFFFF / tmrHw_HIGH_256_RESOLUTION_COUNT)
  44. static void ResetTimer(tmrHw_ID_t timerId)
  45. __attribute__ ((section(".aramtext")));
  46. static int tmrHw_divide(int num, int denom)
  47. __attribute__ ((section(".aramtext")));
  48. /****************************************************************************/
  49. /**
  50. * @brief Get timer capability
  51. *
  52. * This function returns various capabilities/attributes of a timer
  53. *
  54. * @return Capability
  55. *
  56. */
  57. /****************************************************************************/
  58. uint32_t tmrHw_getTimerCapability(tmrHw_ID_t timerId, /* [ IN ] Timer Id */
  59. tmrHw_CAPABILITY_e capability /* [ IN ] Timer capability */
  60. ) {
  61. switch (capability) {
  62. case tmrHw_CAPABILITY_CLOCK:
  63. return (timerId <=
  64. 1) ? tmrHw_LOW_RESOLUTION_CLOCK :
  65. tmrHw_HIGH_RESOLUTION_CLOCK;
  66. case tmrHw_CAPABILITY_RESOLUTION:
  67. return 32;
  68. default:
  69. return 0;
  70. }
  71. return 0;
  72. }
  73. /****************************************************************************/
  74. /**
  75. * @brief Resets a timer
  76. *
  77. * This function initializes timer
  78. *
  79. * @return void
  80. *
  81. */
  82. /****************************************************************************/
  83. static void ResetTimer(tmrHw_ID_t timerId /* [ IN ] Timer Id */
  84. ) {
  85. /* Reset timer */
  86. pTmrHw[timerId].LoadValue = 0;
  87. pTmrHw[timerId].CurrentValue = 0xFFFFFFFF;
  88. pTmrHw[timerId].Control = 0;
  89. pTmrHw[timerId].BackgroundLoad = 0;
  90. /* Always configure as a 32 bit timer */
  91. pTmrHw[timerId].Control |= tmrHw_CONTROL_32BIT;
  92. /* Clear interrupt only if raw status interrupt is set */
  93. if (pTmrHw[timerId].RawInterruptStatus) {
  94. pTmrHw[timerId].InterruptClear = 0xFFFFFFFF;
  95. }
  96. }
  97. /****************************************************************************/
  98. /**
  99. * @brief Sets counter value for an interval in ms
  100. *
  101. * @return On success: Effective counter value set
  102. * On failure: 0
  103. *
  104. */
  105. /****************************************************************************/
  106. static tmrHw_INTERVAL_t SetTimerPeriod(tmrHw_ID_t timerId, /* [ IN ] Timer Id */
  107. tmrHw_INTERVAL_t msec /* [ IN ] Interval in milli-second */
  108. ) {
  109. uint32_t scale = 0;
  110. uint32_t count = 0;
  111. if (timerId == 0 || timerId == 1) {
  112. if (msec <= tmrHw_LOW_1_MAX_MILLISEC) {
  113. pTmrHw[timerId].Control |= tmrHw_CONTROL_PRESCALE_1;
  114. scale = tmrHw_LOW_1_RESOLUTION_COUNT;
  115. } else if (msec <= tmrHw_LOW_16_MAX_MILLISEC) {
  116. pTmrHw[timerId].Control |= tmrHw_CONTROL_PRESCALE_16;
  117. scale = tmrHw_LOW_16_RESOLUTION_COUNT;
  118. } else if (msec <= tmrHw_LOW_256_MAX_MILLISEC) {
  119. pTmrHw[timerId].Control |= tmrHw_CONTROL_PRESCALE_256;
  120. scale = tmrHw_LOW_256_RESOLUTION_COUNT;
  121. } else {
  122. return 0;
  123. }
  124. count = msec * scale;
  125. /* Set counter value */
  126. pTmrHw[timerId].LoadValue = count;
  127. pTmrHw[timerId].BackgroundLoad = count;
  128. } else if (timerId == 2 || timerId == 3) {
  129. if (msec <= tmrHw_HIGH_1_MAX_MILLISEC) {
  130. pTmrHw[timerId].Control |= tmrHw_CONTROL_PRESCALE_1;
  131. scale = tmrHw_HIGH_1_RESOLUTION_COUNT;
  132. } else if (msec <= tmrHw_HIGH_16_MAX_MILLISEC) {
  133. pTmrHw[timerId].Control |= tmrHw_CONTROL_PRESCALE_16;
  134. scale = tmrHw_HIGH_16_RESOLUTION_COUNT;
  135. } else if (msec <= tmrHw_HIGH_256_MAX_MILLISEC) {
  136. pTmrHw[timerId].Control |= tmrHw_CONTROL_PRESCALE_256;
  137. scale = tmrHw_HIGH_256_RESOLUTION_COUNT;
  138. } else {
  139. return 0;
  140. }
  141. count = msec * scale;
  142. /* Set counter value */
  143. pTmrHw[timerId].LoadValue = count;
  144. pTmrHw[timerId].BackgroundLoad = count;
  145. }
  146. return count / scale;
  147. }
  148. /****************************************************************************/
  149. /**
  150. * @brief Configures a periodic timer in terms of timer interrupt rate
  151. *
  152. * This function initializes a periodic timer to generate specific number of
  153. * timer interrupt per second
  154. *
  155. * @return On success: Effective timer frequency
  156. * On failure: 0
  157. *
  158. */
  159. /****************************************************************************/
  160. tmrHw_RATE_t tmrHw_setPeriodicTimerRate(tmrHw_ID_t timerId, /* [ IN ] Timer Id */
  161. tmrHw_RATE_t rate /* [ IN ] Number of timer interrupt per second */
  162. ) {
  163. uint32_t resolution = 0;
  164. uint32_t count = 0;
  165. ResetTimer(timerId);
  166. /* Set timer mode periodic */
  167. pTmrHw[timerId].Control |= tmrHw_CONTROL_PERIODIC;
  168. pTmrHw[timerId].Control &= ~tmrHw_CONTROL_ONESHOT;
  169. /* Set timer in highest resolution */
  170. pTmrHw[timerId].Control |= tmrHw_CONTROL_PRESCALE_1;
  171. if (rate && (timerId == 0 || timerId == 1)) {
  172. if (rate > tmrHw_LOW_RESOLUTION_CLOCK) {
  173. return 0;
  174. }
  175. resolution = tmrHw_LOW_RESOLUTION_CLOCK;
  176. } else if (rate && (timerId == 2 || timerId == 3)) {
  177. if (rate > tmrHw_HIGH_RESOLUTION_CLOCK) {
  178. return 0;
  179. } else {
  180. resolution = tmrHw_HIGH_RESOLUTION_CLOCK;
  181. }
  182. } else {
  183. return 0;
  184. }
  185. /* Find the counter value */
  186. count = resolution / rate;
  187. /* Set counter value */
  188. pTmrHw[timerId].LoadValue = count;
  189. pTmrHw[timerId].BackgroundLoad = count;
  190. return resolution / count;
  191. }
  192. /****************************************************************************/
  193. /**
  194. * @brief Configures a periodic timer to generate timer interrupt after
  195. * certain time interval
  196. *
  197. * This function initializes a periodic timer to generate timer interrupt
  198. * after every time interval in millisecond
  199. *
  200. * @return On success: Effective interval set in milli-second
  201. * On failure: 0
  202. *
  203. */
  204. /****************************************************************************/
  205. tmrHw_INTERVAL_t tmrHw_setPeriodicTimerInterval(tmrHw_ID_t timerId, /* [ IN ] Timer Id */
  206. tmrHw_INTERVAL_t msec /* [ IN ] Interval in milli-second */
  207. ) {
  208. ResetTimer(timerId);
  209. /* Set timer mode periodic */
  210. pTmrHw[timerId].Control |= tmrHw_CONTROL_PERIODIC;
  211. pTmrHw[timerId].Control &= ~tmrHw_CONTROL_ONESHOT;
  212. return SetTimerPeriod(timerId, msec);
  213. }
  214. /****************************************************************************/
  215. /**
  216. * @brief Configures a periodic timer to generate timer interrupt just once
  217. * after certain time interval
  218. *
  219. * This function initializes a periodic timer to generate a single ticks after
  220. * certain time interval in millisecond
  221. *
  222. * @return On success: Effective interval set in milli-second
  223. * On failure: 0
  224. *
  225. */
  226. /****************************************************************************/
  227. tmrHw_INTERVAL_t tmrHw_setOneshotTimerInterval(tmrHw_ID_t timerId, /* [ IN ] Timer Id */
  228. tmrHw_INTERVAL_t msec /* [ IN ] Interval in milli-second */
  229. ) {
  230. ResetTimer(timerId);
  231. /* Set timer mode oneshot */
  232. pTmrHw[timerId].Control |= tmrHw_CONTROL_PERIODIC;
  233. pTmrHw[timerId].Control |= tmrHw_CONTROL_ONESHOT;
  234. return SetTimerPeriod(timerId, msec);
  235. }
  236. /****************************************************************************/
  237. /**
  238. * @brief Configures a timer to run as a free running timer
  239. *
  240. * This function initializes a timer to run as a free running timer
  241. *
  242. * @return Timer resolution (count / sec)
  243. *
  244. */
  245. /****************************************************************************/
  246. tmrHw_RATE_t tmrHw_setFreeRunningTimer(tmrHw_ID_t timerId, /* [ IN ] Timer Id */
  247. uint32_t divider /* [ IN ] Dividing the clock frequency */
  248. ) {
  249. uint32_t scale = 0;
  250. ResetTimer(timerId);
  251. /* Set timer as free running mode */
  252. pTmrHw[timerId].Control &= ~tmrHw_CONTROL_PERIODIC;
  253. pTmrHw[timerId].Control &= ~tmrHw_CONTROL_ONESHOT;
  254. if (divider >= 64) {
  255. pTmrHw[timerId].Control |= tmrHw_CONTROL_PRESCALE_256;
  256. scale = 256;
  257. } else if (divider >= 8) {
  258. pTmrHw[timerId].Control |= tmrHw_CONTROL_PRESCALE_16;
  259. scale = 16;
  260. } else {
  261. pTmrHw[timerId].Control |= tmrHw_CONTROL_PRESCALE_1;
  262. scale = 1;
  263. }
  264. if (timerId == 0 || timerId == 1) {
  265. return tmrHw_divide(tmrHw_LOW_RESOLUTION_CLOCK, scale);
  266. } else if (timerId == 2 || timerId == 3) {
  267. return tmrHw_divide(tmrHw_HIGH_RESOLUTION_CLOCK, scale);
  268. }
  269. return 0;
  270. }
  271. /****************************************************************************/
  272. /**
  273. * @brief Starts a timer
  274. *
  275. * This function starts a preconfigured timer
  276. *
  277. * @return -1 - On Failure
  278. * 0 - On Success
  279. *
  280. */
  281. /****************************************************************************/
  282. int tmrHw_startTimer(tmrHw_ID_t timerId /* [ IN ] Timer id */
  283. ) {
  284. pTmrHw[timerId].Control |= tmrHw_CONTROL_TIMER_ENABLE;
  285. return 0;
  286. }
  287. /****************************************************************************/
  288. /**
  289. * @brief Stops a timer
  290. *
  291. * This function stops a running timer
  292. *
  293. * @return -1 - On Failure
  294. * 0 - On Success
  295. *
  296. */
  297. /****************************************************************************/
  298. int tmrHw_stopTimer(tmrHw_ID_t timerId /* [ IN ] Timer id */
  299. ) {
  300. pTmrHw[timerId].Control &= ~tmrHw_CONTROL_TIMER_ENABLE;
  301. return 0;
  302. }
  303. /****************************************************************************/
  304. /**
  305. * @brief Gets current timer count
  306. *
  307. * This function returns the current timer value
  308. *
  309. * @return Current downcounting timer value
  310. *
  311. */
  312. /****************************************************************************/
  313. uint32_t tmrHw_GetCurrentCount(tmrHw_ID_t timerId /* [ IN ] Timer id */
  314. ) {
  315. /* return 32 bit timer value */
  316. switch (pTmrHw[timerId].Control & tmrHw_CONTROL_MODE_MASK) {
  317. case tmrHw_CONTROL_FREE_RUNNING:
  318. if (pTmrHw[timerId].CurrentValue) {
  319. return tmrHw_MAX_COUNT - pTmrHw[timerId].CurrentValue;
  320. }
  321. break;
  322. case tmrHw_CONTROL_PERIODIC:
  323. case tmrHw_CONTROL_ONESHOT:
  324. return pTmrHw[timerId].BackgroundLoad -
  325. pTmrHw[timerId].CurrentValue;
  326. }
  327. return 0;
  328. }
  329. /****************************************************************************/
  330. /**
  331. * @brief Gets timer count rate
  332. *
  333. * This function returns the number of counts per second
  334. *
  335. * @return Count rate
  336. *
  337. */
  338. /****************************************************************************/
  339. tmrHw_RATE_t tmrHw_getCountRate(tmrHw_ID_t timerId /* [ IN ] Timer id */
  340. ) {
  341. uint32_t divider = 0;
  342. switch (pTmrHw[timerId].Control & tmrHw_CONTROL_PRESCALE_MASK) {
  343. case tmrHw_CONTROL_PRESCALE_1:
  344. divider = 1;
  345. break;
  346. case tmrHw_CONTROL_PRESCALE_16:
  347. divider = 16;
  348. break;
  349. case tmrHw_CONTROL_PRESCALE_256:
  350. divider = 256;
  351. break;
  352. default:
  353. tmrHw_ASSERT(0);
  354. }
  355. if (timerId == 0 || timerId == 1) {
  356. return tmrHw_divide(tmrHw_LOW_RESOLUTION_CLOCK, divider);
  357. } else {
  358. return tmrHw_divide(tmrHw_HIGH_RESOLUTION_CLOCK, divider);
  359. }
  360. return 0;
  361. }
  362. /****************************************************************************/
  363. /**
  364. * @brief Enables timer interrupt
  365. *
  366. * This function enables the timer interrupt
  367. *
  368. * @return N/A
  369. *
  370. */
  371. /****************************************************************************/
  372. void tmrHw_enableInterrupt(tmrHw_ID_t timerId /* [ IN ] Timer id */
  373. ) {
  374. pTmrHw[timerId].Control |= tmrHw_CONTROL_INTERRUPT_ENABLE;
  375. }
  376. /****************************************************************************/
  377. /**
  378. * @brief Disables timer interrupt
  379. *
  380. * This function disable the timer interrupt
  381. *
  382. * @return N/A
  383. *
  384. */
  385. /****************************************************************************/
  386. void tmrHw_disableInterrupt(tmrHw_ID_t timerId /* [ IN ] Timer id */
  387. ) {
  388. pTmrHw[timerId].Control &= ~tmrHw_CONTROL_INTERRUPT_ENABLE;
  389. }
  390. /****************************************************************************/
  391. /**
  392. * @brief Clears the interrupt
  393. *
  394. * This function clears the timer interrupt
  395. *
  396. * @return N/A
  397. *
  398. * @note
  399. * Must be called under the context of ISR
  400. */
  401. /****************************************************************************/
  402. void tmrHw_clearInterrupt(tmrHw_ID_t timerId /* [ IN ] Timer id */
  403. ) {
  404. pTmrHw[timerId].InterruptClear = 0x1;
  405. }
  406. /****************************************************************************/
  407. /**
  408. * @brief Gets the interrupt status
  409. *
  410. * This function returns timer interrupt status
  411. *
  412. * @return Interrupt status
  413. */
  414. /****************************************************************************/
  415. tmrHw_INTERRUPT_STATUS_e tmrHw_getInterruptStatus(tmrHw_ID_t timerId /* [ IN ] Timer id */
  416. ) {
  417. if (pTmrHw[timerId].InterruptStatus) {
  418. return tmrHw_INTERRUPT_STATUS_SET;
  419. } else {
  420. return tmrHw_INTERRUPT_STATUS_UNSET;
  421. }
  422. }
  423. /****************************************************************************/
  424. /**
  425. * @brief Indentifies a timer causing interrupt
  426. *
  427. * This functions returns a timer causing interrupt
  428. *
  429. * @return 0xFFFFFFFF : No timer causing an interrupt
  430. * ! 0xFFFFFFFF : timer causing an interrupt
  431. * @note
  432. * tmrHw_clearIntrrupt() must be called with a valid timer id after calling this function
  433. */
  434. /****************************************************************************/
  435. tmrHw_ID_t tmrHw_getInterruptSource(void /* void */
  436. ) {
  437. int i;
  438. for (i = 0; i < tmrHw_TIMER_NUM_COUNT; i++) {
  439. if (pTmrHw[i].InterruptStatus) {
  440. return i;
  441. }
  442. }
  443. return 0xFFFFFFFF;
  444. }
  445. /****************************************************************************/
  446. /**
  447. * @brief Displays specific timer registers
  448. *
  449. *
  450. * @return void
  451. *
  452. */
  453. /****************************************************************************/
  454. void tmrHw_printDebugInfo(tmrHw_ID_t timerId, /* [ IN ] Timer id */
  455. int (*fpPrint) (const char *, ...) /* [ IN ] Print callback function */
  456. ) {
  457. (*fpPrint) ("Displaying register contents \n\n");
  458. (*fpPrint) ("Timer %d: Load value 0x%X\n", timerId,
  459. pTmrHw[timerId].LoadValue);
  460. (*fpPrint) ("Timer %d: Background load value 0x%X\n", timerId,
  461. pTmrHw[timerId].BackgroundLoad);
  462. (*fpPrint) ("Timer %d: Control 0x%X\n", timerId,
  463. pTmrHw[timerId].Control);
  464. (*fpPrint) ("Timer %d: Interrupt clear 0x%X\n", timerId,
  465. pTmrHw[timerId].InterruptClear);
  466. (*fpPrint) ("Timer %d: Interrupt raw interrupt 0x%X\n", timerId,
  467. pTmrHw[timerId].RawInterruptStatus);
  468. (*fpPrint) ("Timer %d: Interrupt status 0x%X\n", timerId,
  469. pTmrHw[timerId].InterruptStatus);
  470. }
  471. /****************************************************************************/
  472. /**
  473. * @brief Use a timer to perform a busy wait delay for a number of usecs.
  474. *
  475. * @return N/A
  476. */
  477. /****************************************************************************/
  478. void tmrHw_udelay(tmrHw_ID_t timerId, /* [ IN ] Timer id */
  479. unsigned long usecs /* [ IN ] usec to delay */
  480. ) {
  481. tmrHw_RATE_t usec_tick_rate;
  482. tmrHw_COUNT_t start_time;
  483. tmrHw_COUNT_t delta_time;
  484. start_time = tmrHw_GetCurrentCount(timerId);
  485. usec_tick_rate = tmrHw_divide(tmrHw_getCountRate(timerId), 1000000);
  486. delta_time = usecs * usec_tick_rate;
  487. /* Busy wait */
  488. while (delta_time > (tmrHw_GetCurrentCount(timerId) - start_time))
  489. ;
  490. }
  491. /****************************************************************************/
  492. /**
  493. * @brief Local Divide function
  494. *
  495. * This function does the divide
  496. *
  497. * @return divide value
  498. *
  499. */
  500. /****************************************************************************/
  501. static int tmrHw_divide(int num, int denom)
  502. {
  503. int r;
  504. int t = 1;
  505. /* Shift denom and t up to the largest value to optimize algorithm */
  506. /* t contains the units of each divide */
  507. while ((denom & 0x40000000) == 0) { /* fails if denom=0 */
  508. denom = denom << 1;
  509. t = t << 1;
  510. }
  511. /* Intialize the result */
  512. r = 0;
  513. do {
  514. /* Determine if there exists a positive remainder */
  515. if ((num - denom) >= 0) {
  516. /* Accumlate t to the result and calculate a new remainder */
  517. num = num - denom;
  518. r = r + t;
  519. }
  520. /* Continue to shift denom and shift t down to 0 */
  521. denom = denom >> 1;
  522. t = t >> 1;
  523. } while (t != 0);
  524. return r;
  525. }