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