1 //*****************************************************************************
2 //
3 //! @file am_hal_tpiu.c
4 //!
5 //! @brief Support functions for the ARM TPIU module
6 //!
7 //! Provides support functions for configuring the ARM TPIU module
8 //!
9 //! @addtogroup tpiu3 TPIU - Trace Port Interface Unit
10 //! @ingroup apollo3_hal
11 //! @{
12 //
13 //*****************************************************************************
14
15 //*****************************************************************************
16 //
17 // Copyright (c) 2024, Ambiq Micro, Inc.
18 // All rights reserved.
19 //
20 // Redistribution and use in source and binary forms, with or without
21 // modification, are permitted provided that the following conditions are met:
22 //
23 // 1. Redistributions of source code must retain the above copyright notice,
24 // this list of conditions and the following disclaimer.
25 //
26 // 2. Redistributions in binary form must reproduce the above copyright
27 // notice, this list of conditions and the following disclaimer in the
28 // documentation and/or other materials provided with the distribution.
29 //
30 // 3. Neither the name of the copyright holder nor the names of its
31 // contributors may be used to endorse or promote products derived from this
32 // software without specific prior written permission.
33 //
34 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
35 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
36 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
37 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
38 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
39 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
40 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
41 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
42 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
43 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
44 // POSSIBILITY OF SUCH DAMAGE.
45 //
46 // This is part of revision release_sdk_3_2_0-dd5f40c14b of the AmbiqSuite Development Package.
47 //
48 //*****************************************************************************
49
50 #include <stdint.h>
51 #include <stdbool.h>
52 #include "am_mcu_apollo.h"
53
54 //*****************************************************************************
55 //
56 // @brief Enable the clock to the TPIU module.
57 //
58 // This function enables the clock to the TPIU module.
59 //
60 //*****************************************************************************
61 void
am_hal_tpiu_clock_enable(void)62 am_hal_tpiu_clock_enable(void)
63 {
64 //
65 // Enable the TPIU clock
66 //
67 MCUCTRL->TPIUCTRL |= MCUCTRL_TPIUCTRL_ENABLE_Msk;
68 }
69
70 //*****************************************************************************
71 //
72 // @brief Disable the clock to the TPIU module.
73 //
74 // This function disables the clock to the TPIU module.
75 //
76 //*****************************************************************************
77 void
am_hal_tpiu_clock_disable(void)78 am_hal_tpiu_clock_disable(void)
79 {
80 //
81 // Disable the TPIU clock
82 //
83 MCUCTRL->TPIUCTRL &= ~MCUCTRL_TPIUCTRL_ENABLE_Msk;
84 }
85
86 //*****************************************************************************
87 //
88 // @brief Set the output port width of the TPIU
89 //
90 // @param ui32PortWidth - The desired port width (in bits)
91 //
92 // This function uses the TPIU_CSPSR register to set the desired output port
93 // width of the TPIU.
94 //
95 //*****************************************************************************
96 void
am_hal_tpiu_port_width_set(uint32_t ui32PortWidth)97 am_hal_tpiu_port_width_set(uint32_t ui32PortWidth)
98 {
99 TPI->CSPSR = 1 << (ui32PortWidth - 1);
100 }
101
102 //*****************************************************************************
103 //
104 // @brief Read the supported_output port width of the TPIU
105 //
106 // This function uses the \e TPIU_SSPSR register to set the supported output
107 // port widths of the TPIU.
108 //
109 // @return Current width of the TPIU output port
110 //
111 //*****************************************************************************
112 uint32_t
am_hal_tpiu_supported_port_width_get(void)113 am_hal_tpiu_supported_port_width_get(void)
114 {
115 uint32_t i, ui32WidthValue;
116
117 //
118 // Read the supported width register.
119 //
120 ui32WidthValue = TPI->SSPSR;
121
122 //
123 // The register value is encoded in a one-hot format, so the position of
124 // the single set bit determines the actual width of the port.
125 //
126 for (i = 1; i < 32; i++)
127 {
128 //
129 // Check each bit for a '1'. When we find it, our current loop index
130 // will be equal to the port width.
131 //
132 if (ui32WidthValue == (0x1 << (i - 1)))
133 {
134 return i;
135 }
136 }
137
138 //
139 // We should never get here, but if we do, just return the smallest
140 // possible value for a supported trace port width.
141 //
142 return 1;
143 }
144
145 //*****************************************************************************
146 //
147 // @brief Read the output port width of the TPIU
148 //
149 // This function uses the \e TPIU_CSPSR register to set the desired output
150 // port width of the TPIU.
151 //
152 // @return Current width of the TPIU output port
153 //
154 //*****************************************************************************
155 uint32_t
am_hal_tpiu_port_width_get(void)156 am_hal_tpiu_port_width_get(void)
157 {
158 uint32_t ui32Temp;
159 uint32_t ui32Width;
160
161 ui32Width = 1;
162 ui32Temp = TPI->CSPSR;
163
164 while ( !(ui32Temp & 1) )
165 {
166 ui32Temp = ui32Temp >> 1;
167 ui32Width++;
168
169 if (ui32Width > 32)
170 {
171 ui32Width = 0;
172 break;
173 }
174 }
175
176 //
177 // Current width of the TPIU output port.
178 //
179 return ui32Width;
180 }
181
182 //*****************************************************************************
183 //
184 // @brief Configure the TPIU based on the values in the configuration struct.
185 //
186 // @param psConfig - pointer to an am_hal_tpiu_config_t structure containing
187 // the desired configuration information.
188 //
189 // This function reads the provided configuration structure, and sets the
190 // relevant TPIU registers to achieve the desired configuration.
191 //
192 //*****************************************************************************
193 void
am_hal_tpiu_configure(am_hal_tpiu_config_t * psConfig)194 am_hal_tpiu_configure(am_hal_tpiu_config_t *psConfig)
195 {
196 //
197 // Set the clock freq in the MCUCTRL register.
198 //
199 MCUCTRL->TPIUCTRL |= psConfig->ui32TraceClkIn;
200
201 //
202 // Set the desired protocol.
203 //
204 TPI->SPPR = psConfig->ui32PinProtocol;
205
206 //
207 // Set the parallel port width. This may be redundant if the user has
208 // selected a serial protocol, but we'll set it anyway.
209 //
210 TPI->CSPSR = (1 << (psConfig->ui32ParallelPortSize - 1));
211
212 //
213 // Set the clock prescaler.
214 //
215 TPI->ACPR = psConfig->ui32ClockPrescaler;
216 }
217
218 //*****************************************************************************
219 //
220 // @brief Enables the TPIU
221 //
222 // This function enables the ARM TPIU by setting the TPIU registers and then
223 // enabling the TPIU clock source in MCU control register.
224 //
225 // @param psConfig - structure for configuration.
226 // If ui32SetItmBaud, the other structure members are used to set the
227 // TPIU configuration.
228 // But for simplicity, ui32SetItmBaud can be set to one of the
229 // following, in which case all other structure members are ignored.
230 // In this case, the given BAUD rate is based on a div-by-8 HFRC clock.
231 // AM_HAL_TPIU_BAUD_57600
232 // AM_HAL_TPIU_BAUD_115200
233 // AM_HAL_TPIU_BAUD_230400
234 // AM_HAL_TPIU_BAUD_460800
235 // AM_HAL_TPIU_BAUD_500000
236 // AM_HAL_TPIU_BAUD_1M
237 //
238 //*****************************************************************************
239 void
am_hal_tpiu_enable(am_hal_tpiu_config_t * psConfig)240 am_hal_tpiu_enable(am_hal_tpiu_config_t *psConfig)
241 {
242 am_hal_clkgen_status_t sClkGenStatus;
243 uint32_t ui32HFRC, ui32SWOscaler, ui32ITMbitrate;
244
245 ui32ITMbitrate = psConfig->ui32SetItmBaud;
246
247 //
248 // TPIU formatter & flush control register.
249 //
250 TPI->FFCR = 0;
251
252 if ( ui32ITMbitrate )
253 {
254 //
255 // Set the Current Parallel Port Size (note - only 1 bit can be set).
256 //
257 TPI->CSPSR = TPI_CSPSR_CWIDTH_1BIT;
258
259 //
260 // Use some default assumptions to set the ITM frequency.
261 //
262 if ( (ui32ITMbitrate < AM_HAL_TPIU_BAUD_57600 ) ||
263 (ui32ITMbitrate > AM_HAL_TPIU_BAUD_2M ) )
264 {
265 ui32ITMbitrate = AM_HAL_TPIU_BAUD_DEFAULT;
266 }
267
268 //
269 // Get the current HFRC frequency.
270 //
271 am_hal_clkgen_status_get(&sClkGenStatus);
272 ui32HFRC = sClkGenStatus.ui32SysclkFreq;
273
274 //
275 // Compute the SWO scaler value.
276 //
277 if ( ui32HFRC != 0xFFFFFFFF )
278 {
279 ui32SWOscaler = ((ui32HFRC / 8) / ui32ITMbitrate) - 1;
280 }
281 else
282 {
283 ui32SWOscaler = ( (AM_HAL_CLKGEN_FREQ_MAX_HZ / 8) /
284 AM_HAL_TPIU_BAUD_DEFAULT ) - 1;
285 }
286
287 //
288 // Set the scaler value.
289 //
290 TPI->ACPR = _VAL2FLD(TPI_ACPR_SWOSCALER, ui32SWOscaler);
291
292 //
293 // Set for UART mode
294 //
295 TPI->SPPR = _VAL2FLD( TPI_SPPR_TXMODE, TPI_SPPR_TXMODE_UART);
296
297 //
298 // Make sure we are not in test mode (important for proper deep sleep
299 // operation).
300 //
301 TPI->ITCTRL = _VAL2FLD(TPI_ITCTRL_Mode, TPI_ITCTRL_Mode_NORMAL);
302
303 //
304 // Enable the TPIU clock source in MCU control.
305 // Set TPIU clock for HFRC/8 (6MHz) operation.
306 //
307 MCUCTRL->TPIUCTRL =
308 _VAL2FLD(MCUCTRL_TPIUCTRL_CLKSEL, MCUCTRL_TPIUCTRL_CLKSEL_HFRCDIV8) |
309 _VAL2FLD(MCUCTRL_TPIUCTRL_ENABLE, MCUCTRL_TPIUCTRL_ENABLE_EN);
310 }
311 else
312 {
313 //
314 // Set the configuration according to the structure values.
315 //
316
317 //
318 // Set the Asynchronous Clock Prescaler Register.
319 //
320 TPI->ACPR = psConfig->ui32ClockPrescaler;
321
322 //
323 // Set the Selected Pin Protocol Register.
324 // e.g. AM_REG_TPIU_SPPR_TXMODE_UART
325 //
326 TPI->SPPR = psConfig->ui32PinProtocol;
327
328 //
329 // Set the Current Parallel Port Size (note - only 1 bit can be set).
330 // This may be redundant if the user has selected a serial protocol,
331 // but we'll set it anyway.
332 //
333 TPI->CSPSR = (1 << (psConfig->ui32ParallelPortSize - 1));
334
335 //
336 // Make sure we are not in test mode (important for proper deep sleep
337 // operation).
338 //
339 TPI->ITCTRL = _VAL2FLD(TPI_ITCTRL_Mode, TPI_ITCTRL_Mode_NORMAL);
340
341 //
342 // Set the clock freq and enable fields in the MCUCTRL register.
343 //
344 MCUCTRL->TPIUCTRL = psConfig->ui32TraceClkIn;
345 }
346
347 //
348 // Wait for 50us for the data to flush out.
349 //
350 am_hal_flash_delay(FLASH_CYCLES_US(50));
351 }
352
353 //*****************************************************************************
354 //
355 // @brief Disables the TPIU
356 //
357 // This function disables the ARM TPIU by disabling the TPIU clock source
358 //
359 //*****************************************************************************
360 void
am_hal_tpiu_disable(void)361 am_hal_tpiu_disable(void)
362 {
363 //
364 // Disable the TPIU clock source in MCU control.
365 //
366 MCUCTRL->TPIUCTRL =
367 _VAL2FLD(MCUCTRL_TPIUCTRL_CLKSEL, MCUCTRL_TPIUCTRL_CLKSEL_LOWPWR) |
368 _VAL2FLD(MCUCTRL_TPIUCTRL_ENABLE, MCUCTRL_TPIUCTRL_ENABLE_DIS);
369 }
370
371 //*****************************************************************************
372 //
373 // End Doxygen group.
374 //! @}
375 //
376 //*****************************************************************************
377