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