am_hal_systick.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453
  1. //*****************************************************************************
  2. //
  3. // am_hal_systick.c
  4. //! @file
  5. //!
  6. //! @brief Functions for interfacing with the SYSTICK
  7. //!
  8. //! @addtogroup systick2 System Timer (SYSTICK)
  9. //! @ingroup apollo2hal
  10. //! @{
  11. //
  12. //*****************************************************************************
  13. //*****************************************************************************
  14. //
  15. // Copyright (c) 2017, Ambiq Micro
  16. // All rights reserved.
  17. //
  18. // Redistribution and use in source and binary forms, with or without
  19. // modification, are permitted provided that the following conditions are met:
  20. //
  21. // 1. Redistributions of source code must retain the above copyright notice,
  22. // this list of conditions and the following disclaimer.
  23. //
  24. // 2. Redistributions in binary form must reproduce the above copyright
  25. // notice, this list of conditions and the following disclaimer in the
  26. // documentation and/or other materials provided with the distribution.
  27. //
  28. // 3. Neither the name of the copyright holder nor the names of its
  29. // contributors may be used to endorse or promote products derived from this
  30. // software without specific prior written permission.
  31. //
  32. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  33. // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  34. // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  35. // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
  36. // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  37. // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  38. // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  39. // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  40. // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  41. // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  42. // POSSIBILITY OF SUCH DAMAGE.
  43. //
  44. // This is part of revision 1.2.11 of the AmbiqSuite Development Package.
  45. //
  46. //*****************************************************************************
  47. #include <stdint.h>
  48. #include <stdbool.h>
  49. #include "am_mcu_apollo.h"
  50. //*****************************************************************************
  51. //
  52. // Macro definitions
  53. //
  54. //*****************************************************************************
  55. #define SYSTICK_MAX_TICKS ((1 << 24)-1)
  56. #define MAX_U32 (0xffffffff)
  57. //*****************************************************************************
  58. //
  59. //! @brief Start the SYSTICK.
  60. //!
  61. //! This function starts the systick timer.
  62. //!
  63. //! @note This timer does not run in deep-sleep mode as it runs from the core
  64. //! clock, which is gated in deep-sleep. If a timer is needed in deep-sleep use
  65. //! one of the ctimers instead. Also to note is this timer will consume higher
  66. //! power than the ctimers.
  67. //!
  68. //! @return None.
  69. //
  70. //*****************************************************************************
  71. void
  72. am_hal_systick_start(void)
  73. {
  74. //
  75. // Start the systick timer.
  76. //
  77. AM_REG(SYSTICK, SYSTCSR) |= AM_REG_SYSTICK_SYSTCSR_ENABLE_M;
  78. }
  79. //*****************************************************************************
  80. //
  81. //! @brief Stop the SYSTICK.
  82. //!
  83. //! This function stops the systick timer.
  84. //!
  85. //! @note This timer does not run in deep-sleep mode as it runs from the core
  86. //! clock, which is gated in deep-sleep. If a timer is needed in deep-sleep use
  87. //! one of the ctimers instead. Also to note is this timer will consume higher
  88. //! power than the ctimers.
  89. //!
  90. //! @return None.
  91. //
  92. //*****************************************************************************
  93. void
  94. am_hal_systick_stop(void)
  95. {
  96. //
  97. // Stop the systick timer.
  98. //
  99. AM_REG(SYSTICK, SYSTCSR) &= ~AM_REG_SYSTICK_SYSTCSR_ENABLE_M;
  100. }
  101. //*****************************************************************************
  102. //
  103. //! @brief Enable the interrupt in the SYSTICK.
  104. //!
  105. //! This function enables the interupt in the systick timer.
  106. //!
  107. //! @return None.
  108. //
  109. //*****************************************************************************
  110. void
  111. am_hal_systick_int_enable(void)
  112. {
  113. //
  114. // Enable the systick timer interrupt.
  115. //
  116. AM_REG(SYSTICK, SYSTCSR) |= AM_REG_SYSTICK_SYSTCSR_TICKINT_M;
  117. }
  118. //*****************************************************************************
  119. //
  120. //! @brief Disable the interrupt in the SYSTICK.
  121. //!
  122. //! This function disables the interupt in the systick timer.
  123. //!
  124. //! @return None.
  125. //
  126. //*****************************************************************************
  127. void
  128. am_hal_systick_int_disable(void)
  129. {
  130. //
  131. // Disable the systick timer interrupt.
  132. //
  133. AM_REG(SYSTICK, SYSTCSR) &= ~AM_REG_SYSTICK_SYSTCSR_TICKINT_M;
  134. }
  135. //*****************************************************************************
  136. //
  137. //! @brief Reads the interrupt status.
  138. //!
  139. //! This function reads the interrupt status in the systick timer.
  140. //!
  141. //! @return the interrupt status.
  142. //
  143. //*****************************************************************************
  144. uint32_t
  145. am_hal_systick_int_status_get(void)
  146. {
  147. //
  148. // Return the systick timer interrupt status.
  149. //
  150. return AM_REG(SYSTICK, SYSTCSR) & AM_REG_SYSTICK_SYSTCSR_COUNTFLAG_M;
  151. }
  152. //*****************************************************************************
  153. //
  154. //! @brief Reset the interrupt in the SYSTICK.
  155. //!
  156. //! This function resets the systick timer by clearing out the configuration
  157. //! register.
  158. //!
  159. //! @return None.
  160. //
  161. //*****************************************************************************
  162. void
  163. am_hal_systick_reset(void)
  164. {
  165. //
  166. // Reset the systick timer interrupt.
  167. //
  168. AM_REG(SYSTICK, SYSTCSR) = 0x0;
  169. }
  170. //*****************************************************************************
  171. //
  172. //! @brief Load the value into the SYSTICK.
  173. //!
  174. //! @param ui32LoadVal the desired load value for the systick. Maximum value is
  175. //! 0x00FF.FFFF.
  176. //!
  177. //! This function loads the desired value into the systick timer.
  178. //!
  179. //! @return None.
  180. //
  181. //*****************************************************************************
  182. void
  183. am_hal_systick_load(uint32_t ui32LoadVal)
  184. {
  185. //
  186. // Write the reload register.
  187. //
  188. AM_REG(SYSTICK, SYSTRVR) = ui32LoadVal;
  189. }
  190. //*****************************************************************************
  191. //
  192. //! @brief Get the current count value in the SYSTICK.
  193. //!
  194. //! This function gets the current count value in the systick timer.
  195. //!
  196. //! @return Current count value.
  197. //
  198. //*****************************************************************************
  199. uint32_t
  200. am_hal_systick_count(void)
  201. {
  202. //
  203. // Return the current systick timer count value.
  204. //
  205. return AM_REG(SYSTICK, SYSTCVR);
  206. }
  207. //*****************************************************************************
  208. //
  209. //! @brief Wait the specified number of ticks.
  210. //!
  211. //! This function delays for the given number of SysTick ticks.
  212. //!
  213. //! @note If the SysTick timer is being used elsewhere, it will be corrupted
  214. //! by calling this function.
  215. //!
  216. //! @return 0 if successful.
  217. //
  218. //*****************************************************************************
  219. uint32_t
  220. am_hal_systick_wait_ticks(uint32_t u32Ticks)
  221. {
  222. if ( u32Ticks == 0 )
  223. {
  224. u32Ticks++; // Make sure we get the COUNTFLAG
  225. }
  226. //
  227. // The proper SysTick initialization sequence is: (p 4-36 of the M4 UG).
  228. // 1. Program reload value
  229. // 2. Clear current value
  230. // 3. Program CSR
  231. //
  232. // Set the reload value to the required number of ticks.
  233. //
  234. AM_REG(SYSTICK, SYSTRVR) = u32Ticks;
  235. //
  236. // Clear the current count.
  237. //
  238. AM_REG(SYSTICK, SYSTCVR) = 0x0;
  239. //
  240. // Set to use the processor clock, but don't cause an exception (we'll poll).
  241. //
  242. AM_REG(SYSTICK, SYSTCSR) = AM_REG_SYSTICK_SYSTCSR_ENABLE_M;
  243. //
  244. // Poll till done
  245. //
  246. while ( !(AM_REG(SYSTICK, SYSTCSR) & AM_REG_SYSTICK_SYSTCSR_COUNTFLAG_M) );
  247. //
  248. // And disable systick before exiting.
  249. //
  250. AM_REG(SYSTICK, SYSTCSR) = 0;
  251. return 0;
  252. }
  253. //*****************************************************************************
  254. //
  255. //! @brief Delay the specified number of microseconds.
  256. //!
  257. //! This function will use the SysTick timer to delay until the specified
  258. //! number of microseconds have elapsed. It uses the processor clocks and
  259. //! takes into account the current CORESEL setting.
  260. //!
  261. //! @note If the SysTick timer is being used elsewhere, it will be corrupted
  262. //! by calling this function.
  263. //!
  264. //! @return Total number of SysTick ticks delayed.
  265. //
  266. //*****************************************************************************
  267. uint32_t
  268. am_hal_systick_delay_us(uint32_t u32NumUs)
  269. {
  270. uint32_t u32ClkFreq, u32nLoops, u32Ticks, uRet;
  271. uint32_t u32CoreSel = AM_BFR(CLKGEN, CCTRL, CORESEL);
  272. u32nLoops = 1;
  273. switch (u32CoreSel)
  274. {
  275. //
  276. // We need to compute the required number of ticks. To do so and to
  277. // minimize divide operations, we'll use the following equation:
  278. // u32Ticks = (u32NumUs * HFCR_EXACT)/1000000
  279. // = (u32NumUs * (HFCR_EXACT * 1024)/1000000) / 1024
  280. // The values for the variable u32ClkFreq are computed as follows:
  281. // u32ClkFreq = (24390200 * 1024) / ((clksel+1)*1000000);
  282. // (and we'll do the remaining divide by 1024, using a shift, later).
  283. //
  284. case 0:
  285. u32ClkFreq = 24975;
  286. if ( u32NumUs > ((SYSTICK_MAX_TICKS / 24975)*1024) )
  287. {
  288. u32nLoops = (u32NumUs / ((SYSTICK_MAX_TICKS / 24975)*1024)) + 1;
  289. u32NumUs /= u32nLoops;
  290. }
  291. if ( u32NumUs > (MAX_U32 / 24975) )
  292. {
  293. u32Ticks = (u32NumUs >> 10) * u32ClkFreq;
  294. }
  295. else
  296. {
  297. u32Ticks = (u32NumUs * u32ClkFreq) >> 10;
  298. }
  299. break;
  300. case 1:
  301. u32ClkFreq = 12487;
  302. if ( u32NumUs > ((SYSTICK_MAX_TICKS / 12487)*1024) )
  303. {
  304. u32nLoops = (u32NumUs / ((SYSTICK_MAX_TICKS / 12487)*1024)) + 1;
  305. u32NumUs /= u32nLoops;
  306. }
  307. if ( u32NumUs > (MAX_U32 / 12487) )
  308. {
  309. u32Ticks = (u32NumUs >> 10) * u32ClkFreq;
  310. }
  311. else
  312. {
  313. u32Ticks = (u32NumUs * u32ClkFreq) >> 10;
  314. }
  315. break;
  316. case 2:
  317. u32ClkFreq = 8325;
  318. if ( u32NumUs > ((SYSTICK_MAX_TICKS / 8325)*1024) )
  319. {
  320. u32nLoops = (u32NumUs / ((SYSTICK_MAX_TICKS / 8325)*1024)) + 1;
  321. u32NumUs /= u32nLoops;
  322. }
  323. if ( u32NumUs > (MAX_U32 / 8325) )
  324. {
  325. u32Ticks = (u32NumUs >> 10) * u32ClkFreq;
  326. }
  327. else
  328. {
  329. u32Ticks = (u32NumUs * u32ClkFreq) >> 10;
  330. }
  331. break;
  332. case 3:
  333. u32ClkFreq = 6243;
  334. if ( u32NumUs > ((SYSTICK_MAX_TICKS / 6243)*1024) )
  335. {
  336. u32nLoops = (u32NumUs / ((SYSTICK_MAX_TICKS / 6243)*1024)) + 1;
  337. u32NumUs /= u32nLoops;
  338. }
  339. if ( u32NumUs > (MAX_U32 / 6243) )
  340. {
  341. u32Ticks = (u32NumUs >> 10) * u32ClkFreq;
  342. }
  343. else
  344. {
  345. u32Ticks = (u32NumUs * u32ClkFreq) >> 10;
  346. }
  347. break;
  348. case 4:
  349. u32ClkFreq = 4995;
  350. if ( u32NumUs > ((SYSTICK_MAX_TICKS / 4995)*1024) )
  351. {
  352. u32nLoops = (u32NumUs / ((SYSTICK_MAX_TICKS / 4995)*1024)) + 1;
  353. u32NumUs /= u32nLoops;
  354. }
  355. if ( u32NumUs > (MAX_U32 / 4995) )
  356. {
  357. u32Ticks = (u32NumUs >> 10) * u32ClkFreq;
  358. }
  359. else
  360. {
  361. u32Ticks = (u32NumUs * u32ClkFreq) >> 10;
  362. }
  363. break;
  364. case 5:
  365. u32ClkFreq = 4162;
  366. if ( u32NumUs > ((SYSTICK_MAX_TICKS / 4162)*1024) )
  367. {
  368. u32nLoops = (u32NumUs / ((SYSTICK_MAX_TICKS / 4162)*1024)) + 1;
  369. u32NumUs /= u32nLoops;
  370. }
  371. if ( u32NumUs > (MAX_U32 / 4162) )
  372. {
  373. u32Ticks = (u32NumUs >> 10) * u32ClkFreq;
  374. }
  375. else
  376. {
  377. u32Ticks = (u32NumUs * u32ClkFreq) >> 10;
  378. }
  379. break;
  380. case 6:
  381. u32ClkFreq = 3567;
  382. if ( u32NumUs > ((SYSTICK_MAX_TICKS / 3567)*1024) )
  383. {
  384. u32nLoops = (u32NumUs / ((SYSTICK_MAX_TICKS / 3567)*1024)) + 1;
  385. u32NumUs /= u32nLoops;
  386. }
  387. if ( u32NumUs > (MAX_U32 / 3567) )
  388. {
  389. u32Ticks = (u32NumUs >> 10) * u32ClkFreq;
  390. }
  391. else
  392. {
  393. u32Ticks = (u32NumUs * u32ClkFreq) >> 10;
  394. }
  395. break;
  396. case 7:
  397. u32ClkFreq = 3121;
  398. if ( u32NumUs > ((SYSTICK_MAX_TICKS / 3121)*1024) )
  399. {
  400. u32nLoops = (u32NumUs / ((SYSTICK_MAX_TICKS / 3121)*1024)) + 1;
  401. u32NumUs /= u32nLoops;
  402. }
  403. if ( u32NumUs > (MAX_U32 / 3121) )
  404. {
  405. u32Ticks = (u32NumUs >> 10) * u32ClkFreq;
  406. }
  407. else
  408. {
  409. u32Ticks = (u32NumUs * u32ClkFreq) >> 10;
  410. }
  411. break;
  412. default:
  413. u32Ticks = 1;
  414. break;
  415. } // switch()
  416. uRet = u32Ticks * u32nLoops;
  417. while ( u32nLoops-- )
  418. {
  419. am_hal_systick_wait_ticks(u32Ticks);
  420. }
  421. return uRet;
  422. }
  423. //*****************************************************************************
  424. //
  425. // End Doxygen group.
  426. //! @}
  427. //
  428. //*****************************************************************************