am_hal_itm.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453
  1. //*****************************************************************************
  2. //
  3. // am_hal_itm.c
  4. //! @file
  5. //!
  6. //! @brief Functions for operating the instrumentation trace macrocell
  7. //!
  8. //! @addtogroup itm2 Instrumentation Trace Macrocell (ITM)
  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.9 of the AmbiqSuite Development Package.
  45. //
  46. //*****************************************************************************
  47. #include <stdint.h>
  48. #include <stdbool.h>
  49. #include "am_mcu_apollo.h"
  50. //*****************************************************************************
  51. //
  52. // Global Variables
  53. //
  54. //*****************************************************************************
  55. //*****************************************************************************
  56. //
  57. //! @brief Delays for a desired amount of microseconds.
  58. //!
  59. //! @note - This function is based on the similar function in am_util_delay.c,
  60. //! please see that module for implementation details. It was necessary to
  61. //! duplicate it here to avoid having to update every example to include the
  62. //! am_util_delay.c module in its build.
  63. //!
  64. //! @returns None
  65. //
  66. //*****************************************************************************
  67. void
  68. am_hal_itm_delay_us(uint32_t ui32MicroSeconds)
  69. {
  70. uint32_t ui32Iterations = ui32MicroSeconds *
  71. (am_hal_clkgen_sysclk_get() / 3000000);
  72. //
  73. // Call the BOOTROM cycle delay function
  74. //
  75. am_hal_flash_delay(ui32Iterations);
  76. }
  77. //*****************************************************************************
  78. //
  79. //! @brief Enables the ITM
  80. //!
  81. //! This function enables the ARM ITM by setting the TRCENA bit in the DEMCR
  82. //! register.
  83. //!
  84. //! @return None.
  85. //
  86. //*****************************************************************************
  87. void
  88. am_hal_itm_enable(void)
  89. {
  90. if (g_ui32HALflags & AM_HAL_FLAGS_ITMSKIPENABLEDISABLE_M)
  91. {
  92. return;
  93. }
  94. //
  95. // To be able to access ITM registers, set the Trace Enable bit
  96. // in the Debug Exception and Monitor Control Register (DEMCR).
  97. //
  98. AM_REG(SYSCTRL, DEMCR) |= AM_REG_SYSCTRL_DEMCR_TRCENA(1);
  99. while ( !(AM_REG(SYSCTRL, DEMCR) & AM_REG_SYSCTRL_DEMCR_TRCENA(1)) );
  100. //
  101. // Write the key to the ITM Lock Access register to unlock the ITM_TCR.
  102. //
  103. AM_REGVAL(AM_REG_ITM_LOCKAREG_O) = AM_REG_ITM_LOCKAREG_KEYVAL;
  104. //
  105. // Set the enable bits in the ITM trace enable register, and the ITM
  106. // control registers to enable trace data output.
  107. //
  108. AM_REGVAL(AM_REG_ITM_TPR_O) = 0x0000000f;
  109. AM_REGVAL(AM_REG_ITM_TER_O) = 0xffffffff;
  110. //
  111. // Write to the ITM control and status register (don't enable yet).
  112. //
  113. AM_REGVAL(AM_REG_ITM_TCR_O) =
  114. AM_WRITE_SM(AM_REG_ITM_TCR_ATB_ID, 0x15) |
  115. AM_WRITE_SM(AM_REG_ITM_TCR_TS_FREQ, 1) |
  116. AM_WRITE_SM(AM_REG_ITM_TCR_TS_PRESCALE, 1) |
  117. AM_WRITE_SM(AM_REG_ITM_TCR_SWV_ENABLE, 1) |
  118. AM_WRITE_SM(AM_REG_ITM_TCR_DWT_ENABLE, 0) |
  119. AM_WRITE_SM(AM_REG_ITM_TCR_SYNC_ENABLE, 0) |
  120. AM_WRITE_SM(AM_REG_ITM_TCR_TS_ENABLE, 0) |
  121. AM_WRITE_SM(AM_REG_ITM_TCR_ITM_ENABLE, 1);
  122. }
  123. //*****************************************************************************
  124. //
  125. //! @brief Disables the ITM
  126. //!
  127. //! This function completely disables the ARM ITM by resetting the TRCENA bit
  128. //! in the DEMCR register.
  129. //!
  130. //! @return None.
  131. //
  132. //*****************************************************************************
  133. void
  134. am_hal_itm_disable(void)
  135. {
  136. if (g_ui32HALflags & AM_HAL_FLAGS_ITMSKIPENABLEDISABLE_M)
  137. {
  138. return;
  139. }
  140. //
  141. // Make sure the ITM_TCR is unlocked.
  142. //
  143. AM_REGVAL(AM_REG_ITM_LOCKAREG_O) = AM_REG_ITM_LOCKAREG_KEYVAL;
  144. //
  145. // Make sure the ITM/TPIU is not busy.
  146. //
  147. while ( AM_REG(ITM, TCR) & AM_REG_ITM_TCR_BUSY(1) );
  148. //
  149. // Disable the ITM.
  150. //
  151. for (int ix = 0; ix < 100; ix++)
  152. {
  153. AM_REG(ITM, TCR) &= ~AM_REG_ITM_TCR_ITM_ENABLE(1);
  154. while ( AM_REG(ITM, TCR) & (AM_REG_ITM_TCR_ITM_ENABLE(1) | AM_REG_ITM_TCR_BUSY(1)) );
  155. }
  156. //
  157. // Reset the TRCENA bit in the DEMCR register, which should disable the ITM
  158. // for operation.
  159. //
  160. AM_REG(SYSCTRL, DEMCR) &= ~AM_REG_SYSCTRL_DEMCR_TRCENA(1);
  161. //
  162. // Disable the TPIU clock source in MCU control.
  163. //
  164. AM_REG(MCUCTRL, TPIUCTRL) = AM_REG_MCUCTRL_TPIUCTRL_CLKSEL_0MHz |
  165. AM_REG_MCUCTRL_TPIUCTRL_ENABLE_DIS;
  166. }
  167. //*****************************************************************************
  168. //
  169. //! @brief Checks if itm is busy and provides a delay to flush the fifo
  170. //!
  171. //! This function disables the ARM ITM by resetting the TRCENA bit in the DEMCR
  172. //! register.
  173. //!
  174. //! @return None.
  175. //
  176. //*****************************************************************************
  177. void
  178. am_hal_itm_not_busy(void)
  179. {
  180. //
  181. // Make sure the ITM/TPIU is not busy.
  182. //
  183. while (AM_REG(ITM, TCR) & AM_REG_ITM_TCR_BUSY(1));
  184. //
  185. // wait for 50us for the data to flush out
  186. //
  187. am_hal_itm_delay_us(50);
  188. }
  189. //*****************************************************************************
  190. //
  191. //! @brief Enables tracing on a given set of ITM ports
  192. //!
  193. //! @param ui8portNum - Set ports to be enabled
  194. //!
  195. //! Enables tracing on the ports referred to by \e ui8portNum by writing the
  196. //! associated bit in the Trace Privilege Register in the ITM. The value for
  197. //! ui8portNum should be the logical OR one or more of the following values:
  198. //!
  199. //! \e ITM_PRIVMASK_0_7 - enable ports 0 through 7
  200. //! \e ITM_PRIVMASK_8_15 - enable ports 8 through 15
  201. //! \e ITM_PRIVMASK_16_23 - enable ports 16 through 23
  202. //! \e ITM_PRIVMASK_24_31 - enable ports 24 through 31
  203. //!
  204. //! @return None.
  205. //
  206. //*****************************************************************************
  207. void
  208. am_hal_itm_trace_port_enable(uint8_t ui8portNum)
  209. {
  210. AM_REGVAL(AM_REG_ITM_TPR_O) |= (0x00000001 << (ui8portNum>>3));
  211. }
  212. //*****************************************************************************
  213. //
  214. //! @brief Disable tracing on the given ITM stimulus port.
  215. //!
  216. //! @param ui8portNum
  217. //!
  218. //! Disables tracing on the ports referred to by \e ui8portNum by writing the
  219. //! associated bit in the Trace Privilege Register in the ITM. The value for
  220. //! ui8portNum should be the logical OR one or more of the following values:
  221. //!
  222. //! \e ITM_PRIVMASK_0_7 - disable ports 0 through 7
  223. //! \e ITM_PRIVMASK_8_15 - disable ports 8 through 15
  224. //! \e ITM_PRIVMASK_16_23 - disable ports 16 through 23
  225. //! \e ITM_PRIVMASK_24_31 - disable ports 24 through 31
  226. //!
  227. //! @return None.
  228. //
  229. //*****************************************************************************
  230. void
  231. am_hal_itm_trace_port_disable(uint8_t ui8portNum)
  232. {
  233. AM_REGVAL(AM_REG_ITM_TPR_O) &= ~(0x00000001 << (ui8portNum >> 3));
  234. }
  235. //*****************************************************************************
  236. //
  237. //! @brief Poll the given ITM stimulus register until not busy.
  238. //!
  239. //! @param ui32StimReg - stimulus register
  240. //!
  241. //! @return true if not busy, false if busy (timed out or other error).
  242. //
  243. //*****************************************************************************
  244. bool
  245. am_hal_itm_stimulus_not_busy(uint32_t ui32StimReg)
  246. {
  247. uint32_t ui32StimAddr = (AM_REG_ITM_STIM0_O + (4 * ui32StimReg));
  248. //
  249. // Busy waiting until it is available, non-zero means ready.
  250. //
  251. while (!AM_REGVAL(ui32StimAddr));
  252. return true;
  253. }
  254. //*****************************************************************************
  255. //
  256. //! @brief Writes a 32-bit value to the given ITM stimulus register.
  257. //!
  258. //! @param ui32StimReg - stimulus register
  259. //! @param ui32Value - value to be written.
  260. //!
  261. //! Write a word to the desired stimulus register.
  262. //!
  263. //! @return None.
  264. //
  265. //*****************************************************************************
  266. void
  267. am_hal_itm_stimulus_reg_word_write(uint32_t ui32StimReg, uint32_t ui32Value)
  268. {
  269. uint32_t ui32StimAddr;
  270. ui32StimAddr = (AM_REG_ITM_STIM0_O + (4 * ui32StimReg));
  271. //
  272. // Busy waiting until it is available, non-zero means ready
  273. //
  274. while (!AM_REGVAL(ui32StimAddr));
  275. //
  276. // Write the register.
  277. //
  278. AM_REGVAL(ui32StimAddr) = ui32Value;
  279. }
  280. //*****************************************************************************
  281. //
  282. //! @brief Writes a short to the given ITM stimulus register.
  283. //!
  284. //! @param ui32StimReg - stimulus register
  285. //! @param ui16Value - short to be written.
  286. //!
  287. //! Write a short to the desired stimulus register.
  288. //!
  289. //! @return None.
  290. //
  291. //*****************************************************************************
  292. void
  293. am_hal_itm_stimulus_reg_short_write(uint32_t ui32StimReg, uint16_t ui16Value)
  294. {
  295. uint32_t ui32StimAddr;
  296. ui32StimAddr = (AM_REG_ITM_STIM0_O + (4 * ui32StimReg));
  297. //
  298. // Busy waiting until it is available non-zero means ready
  299. //
  300. while (!AM_REGVAL(ui32StimAddr));
  301. //
  302. // Write the register.
  303. //
  304. *((volatile uint16_t *) ui32StimAddr) = ui16Value;
  305. }
  306. //*****************************************************************************
  307. //
  308. //! @brief Writes a byte to the given ITM stimulus register.
  309. //!
  310. //! @param ui32StimReg - stimulus register
  311. //! @param ui8Value - byte to be written.
  312. //!
  313. //! Write a byte to the desired stimulus register.
  314. //!
  315. //! @return None.
  316. //
  317. //*****************************************************************************
  318. void
  319. am_hal_itm_stimulus_reg_byte_write(uint32_t ui32StimReg, uint8_t ui8Value)
  320. {
  321. uint32_t ui32StimAddr;
  322. ui32StimAddr = (AM_REG_ITM_STIM0_O + (4 * ui32StimReg));
  323. //
  324. // Busy waiting until it is available (non-zero means ready)
  325. //
  326. while (!AM_REGVAL(ui32StimAddr));
  327. //
  328. // Write the register.
  329. //
  330. *((volatile uint8_t *) ui32StimAddr) = ui8Value;
  331. }
  332. //*****************************************************************************
  333. //
  334. //! @brief Sends a Sync Packet.
  335. //!
  336. //! Sends a sync packet. This can be useful for external software should it
  337. //! become out of sync with the ITM stream.
  338. //!
  339. //! @return None.
  340. //
  341. //*****************************************************************************
  342. void
  343. am_hal_itm_sync_send(void)
  344. {
  345. //
  346. // Write the register.
  347. //
  348. am_hal_itm_stimulus_reg_word_write(AM_HAL_ITM_SYNC_REG,
  349. AM_HAL_ITM_SYNC_VAL);
  350. }
  351. //*****************************************************************************
  352. //
  353. //! @brief Poll the print stimulus registers until not busy.
  354. //!
  355. //! @return true if not busy, false if busy (timed out or other error).
  356. //
  357. //*****************************************************************************
  358. bool
  359. am_hal_itm_print_not_busy(void)
  360. {
  361. //
  362. // Poll stimulus register allocated for printing.
  363. //
  364. am_hal_itm_stimulus_not_busy(0);
  365. return true;
  366. }
  367. //*****************************************************************************
  368. //
  369. //! @brief Prints a char string out of the ITM.
  370. //!
  371. //! @param pcString pointer to the character sting
  372. //!
  373. //! This function prints a sting out of the ITM.
  374. //!
  375. //! @return None.
  376. //
  377. //*****************************************************************************
  378. void
  379. am_hal_itm_print(char *pcString)
  380. {
  381. uint32_t ui32Length = 0;
  382. //
  383. // Determine the length of the string.
  384. //
  385. while (*(pcString + ui32Length))
  386. {
  387. ui32Length++;
  388. }
  389. //
  390. // If there is no longer a word left, empty out the remaining characters.
  391. //
  392. while (ui32Length)
  393. {
  394. //
  395. // Print string out the ITM.
  396. //
  397. am_hal_itm_stimulus_reg_byte_write(0, (uint8_t)*pcString++);
  398. //
  399. // Subtract from length.
  400. //
  401. ui32Length--;
  402. }
  403. }
  404. //*****************************************************************************
  405. //
  406. // End Doxygen group.
  407. //! @}
  408. //
  409. //*****************************************************************************