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 //
16 // Copyright (c) 2017, Ambiq Micro
17 // All rights reserved.
18 //
19 // Redistribution and use in source and binary forms, with or without
20 // modification, are permitted provided that the following conditions are met:
21 //
22 // 1. Redistributions of source code must retain the above copyright notice,
23 // this list of conditions and the following disclaimer.
24 //
25 // 2. Redistributions in binary form must reproduce the above copyright
26 // notice, this list of conditions and the following disclaimer in the
27 // documentation and/or other materials provided with the distribution.
28 //
29 // 3. Neither the name of the copyright holder nor the names of its
30 // contributors may be used to endorse or promote products derived from this
31 // software without specific prior written permission.
32 //
33 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
34 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
35 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
36 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
37 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
38 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
39 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
40 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
41 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
42 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
43 // POSSIBILITY OF SUCH DAMAGE.
44 //
45 // This is part of revision 1.2.11 of the AmbiqSuite Development Package.
46 //
47 //*****************************************************************************
48
49 #include <stdint.h>
50 #include <stdbool.h>
51 #include "am_mcu_apollo.h"
52
53 //*****************************************************************************
54 //
55 // Global Variables
56 //
57 //*****************************************************************************
58
59 //*****************************************************************************
60 //
61 //! @brief Enables the ITM
62 //!
63 //! This function enables the ARM ITM by setting the TRCENA bit in the DEMCR
64 //! register.
65 //!
66 //! @return None.
67 //
68 //*****************************************************************************
69 void
am_hal_itm_enable(void)70 am_hal_itm_enable(void)
71 {
72 if (g_ui32HALflags & AM_HAL_FLAGS_ITMSKIPENABLEDISABLE_M)
73 {
74 return;
75 }
76
77 //
78 // To be able to access ITM registers, set the Trace Enable bit
79 // in the Debug Exception and Monitor Control Register (DEMCR).
80 //
81 AM_REG(SYSCTRL, DEMCR) |= AM_REG_SYSCTRL_DEMCR_TRCENA(1);
82 while ( !(AM_REG(SYSCTRL, DEMCR) & AM_REG_SYSCTRL_DEMCR_TRCENA(1)) );
83
84 //
85 // Write the key to the ITM Lock Access register to unlock the ITM_TCR.
86 //
87 AM_REGVAL(AM_REG_ITM_LOCKAREG_O) = AM_REG_ITM_LOCKAREG_KEYVAL;
88
89 //
90 // Set the enable bits in the ITM trace enable register, and the ITM
91 // control registers to enable trace data output.
92 //
93 AM_REGVAL(AM_REG_ITM_TPR_O) = 0x0000000f;
94 AM_REGVAL(AM_REG_ITM_TER_O) = 0xffffffff;
95
96 //
97 // Write to the ITM control and status register.
98 //
99 AM_REGVAL(AM_REG_ITM_TCR_O) =
100 AM_WRITE_SM(AM_REG_ITM_TCR_ATB_ID, 0x15) |
101 AM_WRITE_SM(AM_REG_ITM_TCR_TS_FREQ, 1) |
102 AM_WRITE_SM(AM_REG_ITM_TCR_TS_PRESCALE, 1) |
103 AM_WRITE_SM(AM_REG_ITM_TCR_SWV_ENABLE, 1) |
104 AM_WRITE_SM(AM_REG_ITM_TCR_DWT_ENABLE, 0) |
105 AM_WRITE_SM(AM_REG_ITM_TCR_SYNC_ENABLE, 0) |
106 AM_WRITE_SM(AM_REG_ITM_TCR_TS_ENABLE, 0) |
107 AM_WRITE_SM(AM_REG_ITM_TCR_ITM_ENABLE, 1);
108
109 }
110
111 //*****************************************************************************
112 //
113 //! @brief Disables the ITM
114 //!
115 //! This function completely disables the ARM ITM by resetting the TRCENA bit
116 //! in the DEMCR register.
117 //!
118 //! @return None.
119 //
120 //*****************************************************************************
121 void
am_hal_itm_disable(void)122 am_hal_itm_disable(void)
123 {
124
125 if (g_ui32HALflags & AM_HAL_FLAGS_ITMSKIPENABLEDISABLE_M)
126 {
127 return;
128 }
129
130 //
131 // Make sure the ITM_TCR is unlocked.
132 //
133 AM_REGVAL(AM_REG_ITM_LOCKAREG_O) = AM_REG_ITM_LOCKAREG_KEYVAL;
134
135 //
136 // Make sure the ITM/TPIU is not busy.
137 //
138 while ( AM_REG(ITM, TCR) & AM_REG_ITM_TCR_BUSY(1) );
139
140 //
141 // Disable the ITM.
142 //
143 for (int ix = 0; ix < 100; ix++)
144 {
145 AM_REG(ITM, TCR) &= ~AM_REG_ITM_TCR_ITM_ENABLE(1);
146 while ( AM_REG(ITM, TCR) & (AM_REG_ITM_TCR_ITM_ENABLE(1) | AM_REG_ITM_TCR_BUSY(1)) );
147 }
148
149 //
150 // Reset the TRCENA bit in the DEMCR register, which should disable the ITM
151 // for operation.
152 //
153 AM_REG(SYSCTRL, DEMCR) &= ~AM_REG_SYSCTRL_DEMCR_TRCENA(1);
154
155 //
156 // Disable the TPIU clock source in MCU control.
157 //
158 AM_REG(MCUCTRL, TPIUCTRL) = AM_REG_MCUCTRL_TPIUCTRL_CLKSEL_0MHz |
159 AM_REG_MCUCTRL_TPIUCTRL_ENABLE_DIS;
160 }
161
162 //*****************************************************************************
163 //
164 //! @brief Checks if itm is busy and provides a delay to flush the fifo
165 //!
166 //! This function disables the ARM ITM by resetting the TRCENA bit in the DEMCR
167 //! register.
168 //!
169 //! @return None.
170 //
171 //*****************************************************************************
172 void
am_hal_itm_not_busy(void)173 am_hal_itm_not_busy(void)
174 {
175 //
176 // Make sure the ITM/TPIU is not busy.
177 //
178 while (AM_REG(ITM, TCR) & AM_REG_ITM_TCR_BUSY(1));
179
180 //
181 // wait for 50us for the data to flush out
182 //
183 am_hal_flash_delay(FLASH_CYCLES_US(50));
184 }
185
186 //*****************************************************************************
187 //
188 //! @brief Enables tracing on a given set of ITM ports
189 //!
190 //! @param ui8portNum - Set ports to be enabled
191 //!
192 //! Enables tracing on the ports referred to by \e ui8portNum by writing the
193 //! associated bit in the Trace Privilege Register in the ITM. The value for
194 //! ui8portNum should be the logical OR one or more of the following values:
195 //!
196 //! \e ITM_PRIVMASK_0_7 - enable ports 0 through 7
197 //! \e ITM_PRIVMASK_8_15 - enable ports 8 through 15
198 //! \e ITM_PRIVMASK_16_23 - enable ports 16 through 23
199 //! \e ITM_PRIVMASK_24_31 - enable ports 24 through 31
200 //!
201 //! @return None.
202 //
203 //*****************************************************************************
204 void
am_hal_itm_trace_port_enable(uint8_t ui8portNum)205 am_hal_itm_trace_port_enable(uint8_t ui8portNum)
206 {
207 AM_REGVAL(AM_REG_ITM_TPR_O) |= (0x00000001 << (ui8portNum>>3));
208 }
209
210 //*****************************************************************************
211 //
212 //! @brief Disable tracing on the given ITM stimulus port.
213 //!
214 //! @param ui8portNum
215 //!
216 //! Disables tracing on the ports referred to by \e ui8portNum by writing the
217 //! associated bit in the Trace Privilege Register in the ITM. The value for
218 //! ui8portNum should be the logical OR one or more of the following values:
219 //!
220 //! \e ITM_PRIVMASK_0_7 - disable ports 0 through 7
221 //! \e ITM_PRIVMASK_8_15 - disable ports 8 through 15
222 //! \e ITM_PRIVMASK_16_23 - disable ports 16 through 23
223 //! \e ITM_PRIVMASK_24_31 - disable ports 24 through 31
224 //!
225 //! @return None.
226 //
227 //*****************************************************************************
228 void
am_hal_itm_trace_port_disable(uint8_t ui8portNum)229 am_hal_itm_trace_port_disable(uint8_t ui8portNum)
230 {
231 AM_REGVAL(AM_REG_ITM_TPR_O) &= ~(0x00000001 << (ui8portNum >> 3));
232 }
233
234 //*****************************************************************************
235 //
236 //! @brief Poll the given ITM stimulus register until not busy.
237 //!
238 //! @param ui32StimReg - stimulus register
239 //!
240 //! @return true if not busy, false if busy (timed out or other error).
241 //
242 //*****************************************************************************
243 bool
am_hal_itm_stimulus_not_busy(uint32_t ui32StimReg)244 am_hal_itm_stimulus_not_busy(uint32_t ui32StimReg)
245 {
246 uint32_t ui32StimAddr = (AM_REG_ITM_STIM0_O + (4 * ui32StimReg));
247
248 //
249 // Busy waiting until it is available, non-zero means ready.
250 //
251 while (!AM_REGVAL(ui32StimAddr));
252
253 return true;
254 }
255
256 //*****************************************************************************
257 //
258 //! @brief Writes a 32-bit value to the given ITM stimulus register.
259 //!
260 //! @param ui32StimReg - stimulus register
261 //! @param ui32Value - value to be written.
262 //!
263 //! Write a word to the desired stimulus register.
264 //!
265 //! @return None.
266 //
267 //*****************************************************************************
268 void
am_hal_itm_stimulus_reg_word_write(uint32_t ui32StimReg,uint32_t ui32Value)269 am_hal_itm_stimulus_reg_word_write(uint32_t ui32StimReg, uint32_t ui32Value)
270 {
271 uint32_t ui32StimAddr;
272
273 ui32StimAddr = (AM_REG_ITM_STIM0_O + (4 * ui32StimReg));
274
275 //
276 // Busy waiting until it is available, non-zero means ready
277 //
278 while (!AM_REGVAL(ui32StimAddr));
279
280 //
281 // Write the register.
282 //
283 AM_REGVAL(ui32StimAddr) = ui32Value;
284 }
285
286 //*****************************************************************************
287 //
288 //! @brief Writes a short to the given ITM stimulus register.
289 //!
290 //! @param ui32StimReg - stimulus register
291 //! @param ui16Value - short to be written.
292 //!
293 //! Write a short to the desired stimulus register.
294 //!
295 //! @return None.
296 //
297 //*****************************************************************************
298 void
am_hal_itm_stimulus_reg_short_write(uint32_t ui32StimReg,uint16_t ui16Value)299 am_hal_itm_stimulus_reg_short_write(uint32_t ui32StimReg, uint16_t ui16Value)
300 {
301 uint32_t ui32StimAddr;
302
303 ui32StimAddr = (AM_REG_ITM_STIM0_O + (4 * ui32StimReg));
304
305 //
306 // Busy waiting until it is available non-zero means ready
307 //
308 while (!AM_REGVAL(ui32StimAddr));
309
310 //
311 // Write the register.
312 //
313 *((volatile uint16_t *) ui32StimAddr) = ui16Value;
314 }
315
316 //*****************************************************************************
317 //
318 //! @brief Writes a byte to the given ITM stimulus register.
319 //!
320 //! @param ui32StimReg - stimulus register
321 //! @param ui8Value - byte to be written.
322 //!
323 //! Write a byte to the desired stimulus register.
324 //!
325 //! @return None.
326 //
327 //*****************************************************************************
328 void
am_hal_itm_stimulus_reg_byte_write(uint32_t ui32StimReg,uint8_t ui8Value)329 am_hal_itm_stimulus_reg_byte_write(uint32_t ui32StimReg, uint8_t ui8Value)
330 {
331 uint32_t ui32StimAddr;
332
333 ui32StimAddr = (AM_REG_ITM_STIM0_O + (4 * ui32StimReg));
334
335 //
336 // Busy waiting until it is available (non-zero means ready)
337 //
338 while (!AM_REGVAL(ui32StimAddr));
339
340 //
341 // Write the register.
342 //
343 *((volatile uint8_t *) ui32StimAddr) = ui8Value;
344 }
345
346 //*****************************************************************************
347 //
348 //! @brief Sends a Sync Packet.
349 //!
350 //! Sends a sync packet. This can be useful for external software should it
351 //! become out of sync with the ITM stream.
352 //!
353 //! @return None.
354 //
355 //*****************************************************************************
356 void
am_hal_itm_sync_send(void)357 am_hal_itm_sync_send(void)
358 {
359 //
360 // Write the register.
361 //
362 am_hal_itm_stimulus_reg_word_write(AM_HAL_ITM_SYNC_REG,
363 AM_HAL_ITM_SYNC_VAL);
364 }
365
366 //*****************************************************************************
367 //
368 //! @brief Poll the print stimulus registers until not busy.
369 //!
370 //! @return true if not busy, false if busy (timed out or other error).
371 //
372 //*****************************************************************************
373 bool
am_hal_itm_print_not_busy(void)374 am_hal_itm_print_not_busy(void)
375 {
376 //
377 // Poll stimulus register allocated for printing.
378 //
379 am_hal_itm_stimulus_not_busy(0);
380
381
382 return true;
383 }
384
385 //*****************************************************************************
386 //
387 //! @brief Prints a char string out of the ITM.
388 //!
389 //! @param pcString pointer to the character sting
390 //!
391 //! This function prints a sting out of the ITM.
392 //!
393 //! @return None.
394 //
395 //*****************************************************************************
396 void
am_hal_itm_print(char * pcString)397 am_hal_itm_print(char *pcString)
398 {
399 uint32_t ui32Length = 0;
400
401 //
402 // Determine the length of the string.
403 //
404 while (*(pcString + ui32Length))
405 {
406 ui32Length++;
407 }
408
409 //
410 // If there is no longer a word left, empty out the remaining characters.
411 //
412 while (ui32Length)
413 {
414 //
415 // Print string out the ITM.
416 //
417 am_hal_itm_stimulus_reg_byte_write(0, (uint8_t)*pcString++);
418
419 //
420 // Subtract from length.
421 //
422 ui32Length--;
423 }
424 }
425 //*****************************************************************************
426 //
427 // End Doxygen group.
428 //! @}
429 //
430 //*****************************************************************************
431