1 //*****************************************************************************
2 //
3 //! @file am_hal_itm.c
4 //!
5 //! @brief Functions for Operating the Instrumentation Trace Macrocell
6 //!
7 //! @addtogroup itm3p ITM - Instrumentation Trace Macrocell
8 //! @ingroup apollo3p_hal
9 //! @{
10 //
11 //*****************************************************************************
12 
13 //*****************************************************************************
14 //
15 // Copyright (c) 2024, Ambiq Micro, Inc.
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 release_sdk_3_2_0-dd5f40c14b of the AmbiqSuite Development Package.
45 //
46 //*****************************************************************************
47 
48 #include <stdint.h>
49 #include <stdbool.h>
50 #include "am_mcu_apollo.h"
51 
52 //*****************************************************************************
53 //
54 // Global Variables
55 //
56 //*****************************************************************************
57 
58 //*****************************************************************************
59 //
60 // @brief Enables the ITM
61 //
62 // This function enables the ARM ITM by setting the TRCENA bit in the DEMCR
63 // register.
64 //
65 //*****************************************************************************
66 void
am_hal_itm_enable(void)67 am_hal_itm_enable(void)
68 {
69     //
70     // To be able to access ITM registers, set the Trace Enable bit
71     // in the Debug Exception and Monitor Control Register (DEMCR).
72     //
73     CoreDebug->DEMCR |= _VAL2FLD(CoreDebug_DEMCR_TRCENA, 1);
74     while ( !(CoreDebug->DEMCR & _VAL2FLD(CoreDebug_DEMCR_TRCENA, 1)) );
75 
76     //
77     // Write the key to the ITM Lock Access register to unlock the ITM_TCR.
78     //
79     ITM->LAR = ITM_LAR_KEYVAL;
80 
81     //
82     // Set the enable bits in the ITM trace enable register, and the ITM
83     // control registers to enable trace data output.
84     //
85     ITM->TPR = 0x0000000F;
86     ITM->TER = 0xFFFFFFFF;
87 
88     //
89     // Write to the ITM control and status register.
90     //
91     ITM->TCR =
92         _VAL2FLD(ITM_TCR_TraceBusID, 0x15)      |
93         _VAL2FLD(ITM_TCR_GTSFREQ, 1)            |
94         _VAL2FLD(ITM_TCR_TSPrescale, 1)         |
95         _VAL2FLD(ITM_TCR_SWOENA, 1)             |
96         _VAL2FLD(ITM_TCR_DWTENA, 0)             |
97         _VAL2FLD(ITM_TCR_SYNCENA, 0)            |
98         _VAL2FLD(ITM_TCR_TSENA, 0)              |
99         _VAL2FLD(ITM_TCR_ITMENA, 1);
100 
101 
102 
103 }
104 
105 //*****************************************************************************
106 //
107 // @brief Disables the ITM
108 //
109 // This function completely disables the ARM ITM by resetting the TRCENA bit
110 // in the DEMCR register.
111 //
112 //*****************************************************************************
113 void
am_hal_itm_disable(void)114 am_hal_itm_disable(void)
115 {
116 
117     if ( MCUCTRL->TPIUCTRL == 0 )
118     {
119         //
120         // This is a disable without enable, which could be the case with some
121         // earlier versions of SBL. To avoid a hang, ITM (particularly TPIU
122         // clock) must first be enabled.
123         //
124         am_hal_itm_enable();
125     }
126 
127     //
128     // Make sure the ITM/TPIU is not busy.
129     //
130     am_hal_itm_not_busy();
131 
132     //
133     // Make sure the ITM_TCR is unlocked.
134     //
135     ITM->LAR = ITM_LAR_KEYVAL;
136 
137     //
138     // Disable the ITM.
139     //
140     for (int ix = 0; ix < 100; ix++)
141     {
142         ITM->TCR &= ~_VAL2FLD(ITM_TCR_ITMENA, 1);
143         while ( ITM->TCR  & (_VAL2FLD(ITM_TCR_ITMENA, 1)  |  _VAL2FLD(ITM_TCR_BUSY, 1)) );
144     }
145 
146     //
147     // Reset the TRCENA bit in the DEMCR register, which should disable the ITM
148     // for operation.
149     //
150     CoreDebug->DEMCR &= ~_VAL2FLD(CoreDebug_DEMCR_TRCENA, 1);
151     while ( CoreDebug->DEMCR & _VAL2FLD(CoreDebug_DEMCR_TRCENA, 1) );
152 
153     //
154     // Disable the TPIU clock source in MCU control.
155     //
156     MCUCTRL->TPIUCTRL =
157         _VAL2FLD(MCUCTRL_TPIUCTRL_CLKSEL, MCUCTRL_TPIUCTRL_CLKSEL_LOWPWR) |
158         _VAL2FLD(MCUCTRL_TPIUCTRL_ENABLE, MCUCTRL_TPIUCTRL_ENABLE_DIS);
159     while (MCUCTRL->TPIUCTRL);
160 
161 }
162 
163 //*****************************************************************************
164 //
165 // @brief Checks if itm is busy and provides a delay to flush the fifo
166 //
167 // This function disables the ARM ITM by resetting the TRCENA bit in the DEMCR
168 // register.
169 //
170 //*****************************************************************************
171 void
am_hal_itm_not_busy(void)172 am_hal_itm_not_busy(void)
173 {
174     //
175     // Make sure the ITM/TPIU is not busy.
176     //
177     while (ITM->TCR & _VAL2FLD(ITM_TCR_BUSY, 1));
178 
179     //
180     // wait for 50us for the data to flush out
181     //
182     am_hal_flash_delay(FLASH_CYCLES_US(50));
183 }
184 
185 //*****************************************************************************
186 //
187 // @brief Enables tracing on a given set of ITM ports
188 //
189 // @param ui8portNum - Set ports to be enabled
190 //
191 // Enables tracing on the ports referred to by \e ui8portNum by writing the
192 // associated bit in the Trace Privilege Register in the ITM. The value for
193 // ui8portNum should be the logical OR one or more of the following values:
194 //
195 // \e ITM_PRIVMASK_0_7 - enable ports 0 through 7
196 // \e ITM_PRIVMASK_8_15 - enable ports 8 through 15
197 // \e ITM_PRIVMASK_16_23 - enable ports 16 through 23
198 // \e ITM_PRIVMASK_24_31 - enable ports 24 through 31
199 //
200 //*****************************************************************************
201 void
am_hal_itm_trace_port_enable(uint8_t ui8portNum)202 am_hal_itm_trace_port_enable(uint8_t ui8portNum)
203 {
204     ITM->TPR |= (0x00000001 << (ui8portNum>>3));
205 }
206 
207 //*****************************************************************************
208 //
209 // @brief Disable tracing on the given ITM stimulus port.
210 //
211 // @param ui8portNum
212 //
213 // Disables tracing on the ports referred to by \e ui8portNum by writing the
214 // associated bit in the Trace Privilege Register in the ITM. The value for
215 // ui8portNum should be the logical OR one or more of the following values:
216 //
217 // \e ITM_PRIVMASK_0_7 - disable ports 0 through 7
218 // \e ITM_PRIVMASK_8_15 - disable ports 8 through 15
219 // \e ITM_PRIVMASK_16_23 - disable ports 16 through 23
220 // \e ITM_PRIVMASK_24_31 - disable ports 24 through 31
221 //
222 //*****************************************************************************
223 void
am_hal_itm_trace_port_disable(uint8_t ui8portNum)224 am_hal_itm_trace_port_disable(uint8_t ui8portNum)
225 {
226     ITM->TPR &= ~(0x00000001 << (ui8portNum >> 3));
227 }
228 
229 //*****************************************************************************
230 //
231 // @brief Poll the given ITM stimulus register until not busy.
232 //
233 // @param ui32StimReg - stimulus register
234 //
235 // @return true if not busy, false if busy (timed out or other error).
236 //
237 //*****************************************************************************
238 bool
am_hal_itm_stimulus_not_busy(uint32_t ui32StimReg)239 am_hal_itm_stimulus_not_busy(uint32_t ui32StimReg)
240 {
241     uint32_t ui32StimAddr = (uint32_t)&ITM->PORT[0] + (4 * ui32StimReg);
242 
243     //
244     // Busy waiting until it is available, non-zero means ready.
245     //
246     while ( !AM_REGVAL(ui32StimAddr) );
247 
248     return true;
249 }
250 
251 //*****************************************************************************
252 //
253 // @brief Writes a 32-bit value to the given ITM stimulus register.
254 //
255 // @param ui32StimReg - stimulus register
256 // @param ui32Value - value to be written.
257 //
258 // Write a word to the desired stimulus register.
259 //
260 //*****************************************************************************
261 void
am_hal_itm_stimulus_reg_word_write(uint32_t ui32StimReg,uint32_t ui32Value)262 am_hal_itm_stimulus_reg_word_write(uint32_t ui32StimReg, uint32_t ui32Value)
263 {
264     uint32_t ui32StimAddr = (uint32_t)&ITM->PORT[0] + (4 * ui32StimReg);
265 
266 
267     //
268     // Busy waiting until it is available, non-zero means ready
269     //
270     while (!AM_REGVAL(ui32StimAddr));
271 
272     //
273     // Write the register.
274     //
275     AM_REGVAL(ui32StimAddr) = ui32Value;
276 }
277 
278 //*****************************************************************************
279 //
280 // @brief Writes a short to the given ITM stimulus register.
281 //
282 // @param ui32StimReg - stimulus register
283 // @param ui16Value - short to be written.
284 //
285 // Write a short to the desired stimulus register.
286 //
287 //*****************************************************************************
288 void
am_hal_itm_stimulus_reg_short_write(uint32_t ui32StimReg,uint16_t ui16Value)289 am_hal_itm_stimulus_reg_short_write(uint32_t ui32StimReg, uint16_t ui16Value)
290 {
291     uint32_t ui32StimAddr = (uint32_t)&ITM->PORT[0] + (4 * ui32StimReg);
292 
293     //
294     // Busy waiting until it is available non-zero means ready
295     //
296     while ( !AM_REGVAL(ui32StimAddr) );
297 
298     //
299     // Write the register.
300     //
301     *((volatile uint16_t *) ui32StimAddr) = ui16Value;
302 }
303 
304 //*****************************************************************************
305 //
306 // @brief Writes a byte to the given ITM stimulus register.
307 //
308 // @param ui32StimReg - stimulus register
309 // @param ui8Value - byte to be written.
310 //
311 // Write a byte to the desired stimulus register.
312 //
313 //*****************************************************************************
314 void
am_hal_itm_stimulus_reg_byte_write(uint32_t ui32StimReg,uint8_t ui8Value)315 am_hal_itm_stimulus_reg_byte_write(uint32_t ui32StimReg, uint8_t ui8Value)
316 {
317     uint32_t ui32StimAddr = (uint32_t)&ITM->PORT[0] + (4 * ui32StimReg);
318 
319     //
320     // Busy waiting until it is available (non-zero means ready)
321     //
322     while (!AM_REGVAL(ui32StimAddr));
323 
324     //
325     // Write the register.
326     //
327     *((volatile uint8_t *) ui32StimAddr) = ui8Value;
328 }
329 
330 //*****************************************************************************
331 //
332 // @brief Sends a Sync Packet.
333 //
334 // Sends a sync packet. This can be useful for external software should it
335 // become out of sync with the ITM stream.
336 //
337 //*****************************************************************************
338 void
am_hal_itm_sync_send(void)339 am_hal_itm_sync_send(void)
340 {
341     //
342     // Write the register.
343     //
344     am_hal_itm_stimulus_reg_word_write(AM_HAL_ITM_SYNC_REG,
345                                        AM_HAL_ITM_SYNC_VAL);
346 }
347 
348 //*****************************************************************************
349 //
350 // @brief Poll the print stimulus registers until not busy.
351 //
352 // @return true if not busy, false if busy (timed out or other error).
353 //
354 //*****************************************************************************
355 bool
am_hal_itm_print_not_busy(void)356 am_hal_itm_print_not_busy(void)
357 {
358     //
359     // Poll stimulus register allocated for printing.
360     //
361     am_hal_itm_stimulus_not_busy(0);
362 
363 
364     return true;
365 }
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 //*****************************************************************************
376 void
am_hal_itm_print(char * pcString)377 am_hal_itm_print(char *pcString)
378 {
379     uint32_t ui32Length = 0;
380 
381     //
382     // Determine the length of the string.
383     //
384     while (*(pcString + ui32Length))
385     {
386         ui32Length++;
387     }
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             //
400             // Subtract from length.
401             //
402             ui32Length--;
403     }
404 }
405 //*****************************************************************************
406 //
407 // End Doxygen group.
408 //! @}
409 //
410 //*****************************************************************************
411