1 /*
2 * Trace Recorder for Tracealyzer v4.9.2
3 * Copyright 2023 Percepio AB
4 * www.percepio.com
5 *
6 * SPDX-License-Identifier: Apache-2.0
7 *
8 * Supporting functions for trace streaming, used by the "stream ports"
9 * for reading and writing data to the interface.
10 * Existing ports can easily be modified to fit another setup, e.g., a
11 * different TCP/IP stack, or to define your own stream port.
12 *
13 * This stream port is for ITM streaming on Arm Cortex-M devices.
14 *
15 * To setup Keil uVision for ITM tracing with a Keil ULINKpro (or ULINKplus),
16 * see Percepio Application Note PA-021, available at
17 * https://percepio.com/2018/05/04/keil-itm-support/
18 *
19 * To setup IAR Embedded Workbench for ITM tracing with an IAR I-Jet,
20 * see Percepio Application Note PA-023, https://percepio.com/iar
21 *
22 * NOTE: This stream port may block the application in case the ITM port
23 * is not ready for more data (the TPIU FIFO has become full). This is
24 * necessary to avoid data loss, as the TPIU FIFO is often quite small.
25 *
26 * --- Direct vs. Indirect ITM streaming ---
27 * Direct streaming: By default, this stream port writes directly to the ITM
28 * register mode without any RAM buffer. This assumes you have a fast debug
29 * probe, like aKeil ULINKpro or IAR I-Jet, to avoid excessive blocking.
30 * In case the ITM blocking appears to disturb your application, make sure your
31 * debugger is configured for maximum performance, as described in the above
32 * Application Nodes.
33 *
34 * Indirect streaming: If direct streaming gives too much overhead, you may
35 * instead try indirect ITM streaming. This is done by enabling the internal
36 * RAM buffer, like below. This reconfigures the recorder to store the events
37 * in the internal RAM buffer instead of writing them directly to the ITM port.
38 *
39 * Set TRC_STREAM_PORT_USE_INTERNAL_BUFFER to 1 to use the indirect mode.
40 *
41 * This increases RAM usage but eliminates peaks in the trace data rate.
42 * Moreover, the ITM writes are then performed in a separate task (TzCtrl).
43 * You find relevant settings (buffer size etc.) in trcStreamingConfig.h.
44 *
45 * See also https://percepio.com/2018/10/11/tuning-your-custom-trace-streaming
46 *
47 * --- One-way vs. Two-way Communication ---
48 * The ITM port only provides one-way communication, from target to host.
49 * This is sufficient if you start the tracing from the target application,
50 * using vTraceEnable(TRC_START). Just make sure to start the Tracealyzer
51 * recording before you start the target system.
52 *
53 * In case you prefer to interactively start and stop the tracing from the host
54 * computer, you need two-way communication to send commands to the recorder.
55 * This is possible by writing such "start" and "stop" commands to a special
56 * buffer, monitored by the recorder library, using the debugger IDE.
57 * See trcStreamingPort.c and also the example macro for Keil uVision
58 * (Keil-uVision-Tracealyzer-ITM-Exporter.ini).
59 */
60
61 #include <trcRecorder.h>
62
63 #if (TRC_USE_TRACEALYZER_RECORDER == 1)
64
65 #if (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING)
66
67 static TraceStreamPortBuffer_t* pxStreamPortITM TRC_CFG_RECORDER_DATA_ATTRIBUTE;
68
69 /* This will be set by the debugger when there is data to be read */
70 volatile int32_t tz_host_command_bytes_to_read = 0;
71
72 /* This will be filled with data from the debugger */
73 volatile char tz_host_command_data[32];
74
75 /* These variables are used for reading commands from the host, using read_from_host().
76 * This is not required if using vTraceEnable(TRC_START).
77 * A debugger IDE may write to these functions using a macro.
78 * An example for Keil is included (Keil-uVision-Tracealyzer-ITM-Exporter.ini). */
79
80 #define itm_write_32(__data) \
81 {\
82 while (ITM->PORT[TRC_CFG_STREAM_PORT_ITM_PORT].u32 == 0) { /* Do nothing */ } /* Block until room in ITM FIFO - This stream port is always in "blocking mode", since intended for high-speed ITM! */ \
83 ITM->PORT[TRC_CFG_STREAM_PORT_ITM_PORT].u32 = __data; /* Write the data */ \
84 }
85
86 /* This is assumed to execute from within the recorder, with interrupts disabled */
prvTraceItmWrite(void * ptrData,uint32_t size,int32_t * ptrBytesWritten)87 traceResult prvTraceItmWrite(void* ptrData, uint32_t size, int32_t* ptrBytesWritten)
88 {
89 uint32_t* ptr32 = (uint32_t*)ptrData;
90
91 TRC_ASSERT(size % 4 == 0);
92 TRC_ASSERT(ptrBytesWritten != 0);
93
94 *ptrBytesWritten = 0;
95
96 if ((CoreDebug->DEMCR & CoreDebug_DEMCR_TRCENA_Msk) && /* Trace enabled? */ \
97 (ITM->TCR & ITM_TCR_ITMENA_Msk) && /* ITM enabled? */ \
98 (ITM->TER & (1UL << (TRC_CFG_STREAM_PORT_ITM_PORT)))) /* ITM port enabled? */
99 {
100 while (*ptrBytesWritten < (int32_t)size)
101 {
102 itm_write_32(*ptr32);
103 ptr32++;
104 *ptrBytesWritten += 4;
105 }
106 }
107
108 return TRC_SUCCESS;
109 }
110
111 /* This reads "command" data from a RAM buffer, written by a host macro in the debugger */
prvTraceItmRead(void * ptrData,uint32_t uiSize,int32_t * piBytesRead)112 traceResult prvTraceItmRead(void* ptrData, uint32_t uiSize, int32_t* piBytesRead)
113 {
114 int32_t i;
115 uint8_t* bytesBuffer = (uint8_t*)ptrData;
116
117 TRC_ASSERT(piBytesRead != 0);
118
119 /* Check if the debugger has updated tz_host_command_bytes_to_read */
120 if (tz_host_command_bytes_to_read > 0)
121 {
122 if (tz_host_command_bytes_to_read != (int32_t)uiSize)
123 {
124 /* Sanity check. */
125 return TRC_FAIL;
126 }
127
128 *piBytesRead = (int32_t)tz_host_command_bytes_to_read;
129
130 /* Read the bytes */
131 for (i = 0; i < tz_host_command_bytes_to_read; i++)
132 {
133 bytesBuffer[i] = tz_host_command_data[i];
134 }
135
136 /* Reset */
137 tz_host_command_bytes_to_read = 0;
138 }
139
140 return TRC_SUCCESS;
141 }
142
xTraceStreamPortInitialize(TraceStreamPortBuffer_t * pxBuffer)143 traceResult xTraceStreamPortInitialize(TraceStreamPortBuffer_t* pxBuffer)
144 {
145 TRC_ASSERT_EQUAL_SIZE(TraceStreamPortBuffer_t, TraceStreamPortITM_t);
146
147 TRC_ASSERT(pxBuffer != 0);
148
149 pxStreamPortITM = (TraceStreamPortBuffer_t*)pxBuffer;
150
151 #if (TRC_USE_INTERNAL_BUFFER == 1)
152 return xTraceInternalEventBufferInitialize(pxStreamPortITM->bufferInternal, sizeof(pxStreamPortITM->bufferInternal));
153 #else
154 /* Prevents a warning for set but not used when internal buffer
155 * isn't used. */
156 (void)pxStreamPortITM;
157
158 return TRC_SUCCESS;
159 #endif
160 }
161
162 #endif
163
164 #endif
165