1 /*******************************************************************************
\r
2 * Tracealyzer v2.7.0 Recorder Library
\r
3 * Percepio AB, www.percepio.com
\r
7 * Contains together with trcHardwarePort.h all hardware portability issues of
\r
8 * the trace recorder library.
\r
11 * This software is copyright Percepio AB. The recorder library is free for
\r
12 * use together with Percepio products. You may distribute the recorder library
\r
13 * in its original form, including modifications in trcPort.c and trcPort.h
\r
14 * given that these modification are clearly marked as your own modifications
\r
15 * and documented in the initial comment section of these source files.
\r
16 * This software is the intellectual property of Percepio AB and may not be
\r
17 * sold or in other ways commercially redistributed without explicit written
\r
18 * permission by Percepio AB.
\r
21 * The trace tool and recorder library is being delivered to you AS IS and
\r
22 * Percepio AB makes no warranty as to its use or performance. Percepio AB does
\r
23 * not and cannot warrant the performance or results you may obtain by using the
\r
24 * software or documentation. Percepio AB make no warranties, express or
\r
25 * implied, as to noninfringement of third party rights, merchantability, or
\r
26 * fitness for any particular purpose. In no event will Percepio AB, its
\r
27 * technology partners, or distributors be liable to you for any consequential,
\r
28 * incidental or special damages, including any lost profits or lost savings,
\r
29 * even if a representative of Percepio AB has been advised of the possibility
\r
30 * of such damages, or for any claim by any third party. Some jurisdictions do
\r
31 * not allow the exclusion or limitation of incidental, consequential or special
\r
32 * damages, or the exclusion of implied warranties or limitations on how long an
\r
33 * implied warranty may last, so the above limitations may not apply to you.
\r
35 * Tabs are used for indent in this file (1 tab = 4 spaces)
\r
37 * Copyright Percepio AB, 2014.
\r
39 ******************************************************************************/
\r
41 #include "trcHardwarePort.h"
\r
42 #include "trcKernelPort.h"
\r
44 #if (USE_TRACEALYZER_RECORDER == 1)
\r
48 uint32_t trace_disable_timestamp = 0;
\r
49 uint32_t last_timestamp = 0;
\r
51 /*******************************************************************************
\r
54 * This variable is should be updated by the Kernel tick interrupt. This does
\r
55 * not need to be modified when developing a new timer port. It is preferred to
\r
56 * keep any timer port changes in the HWTC macro definitions, which typically
\r
57 * give sufficient flexibility.
\r
58 ******************************************************************************/
\r
59 uint32_t uiTraceTickCount = 0;
\r
61 uint32_t DWT_CYCLES_ADDED = 0; /* Used on ARM Cortex-M only */
\r
63 #if (SELECTED_PORT == PORT_ARM_CortexM)
\r
65 void prvTraceInitCortexM()
\r
67 /* Make sure DWT is enabled is enabled, if supported */
\r
68 REG_DEMCR |= DEMCR_TRCENA;
\r
71 /* Verify that DWT is supported */
\r
74 vTraceError("DWT not supported by this chip!");
\r
78 /* Verify that DWT_CYCCNT is supported */
\r
79 if (REG_DWT_CTRL & DWT_CTRL_NOCYCCNT)
\r
81 vTraceError("DWT_CYCCNT not supported by this chip!");
\r
85 /* Reset the cycle counter */
\r
88 /* Enable the cycle counter */
\r
89 REG_DWT_CTRL |= DWT_CTRL_CYCCNTENA;
\r
91 }while(0); /* breaks above jump here */
\r
93 if (RecorderDataPtr->frequency == 0)
\r
95 RecorderDataPtr->frequency = TRACE_CPU_CLOCK_HZ / HWTC_DIVISOR;
\r
101 /******************************************************************************
\r
102 * vTracePortGetTimeStamp
\r
104 * Returns the current time based on the HWTC macros which provide a hardware
\r
105 * isolation layer towards the hardware timer/counter.
\r
107 * The HWTC macros and vTracePortGetTimeStamp is the main porting issue
\r
108 * or the trace recorder library. Typically you should not need to change
\r
109 * the code of vTracePortGetTimeStamp if using the HWTC macros.
\r
111 ******************************************************************************/
\r
112 void vTracePortGetTimeStamp(uint32_t *pTimestamp)
\r
114 static uint32_t last_traceTickCount = 0;
\r
115 static uint32_t last_hwtc_count = 0;
\r
116 uint32_t traceTickCount = 0;
\r
117 uint32_t hwtc_count = 0;
\r
119 if (trace_disable_timestamp == 1)
\r
122 *pTimestamp = last_timestamp;
\r
126 /* Retrieve HWTC_COUNT only once since the same value should be used all throughout this function. */
\r
127 #if (HWTC_COUNT_DIRECTION == DIRECTION_INCREMENTING)
\r
128 hwtc_count = HWTC_COUNT;
\r
129 #elif (HWTC_COUNT_DIRECTION == DIRECTION_DECREMENTING)
\r
130 hwtc_count = HWTC_PERIOD - HWTC_COUNT;
\r
132 Junk text to cause compiler error - HWTC_COUNT_DIRECTION is not set correctly!
\r
133 Should be DIRECTION_INCREMENTING or DIRECTION_DECREMENTING
\r
136 #if (SELECTED_PORT == PORT_Win32)
\r
137 /* The Win32 port uses ulGetRunTimeCounterValue for timestamping, which in turn
\r
138 uses QueryPerformanceCounter. That function is not always reliable when used over
\r
139 multiple threads. We must therefore handle rare cases where the timestamp is less
\r
140 than the previous. In practice, the Win32 should "never" roll over since the
\r
141 performance counter is 64 bit wide. */
\r
143 if (last_hwtc_count > hwtc_count)
\r
145 hwtc_count = last_hwtc_count;
\r
149 if (last_traceTickCount - uiTraceTickCount - 1 < 0x80000000)
\r
151 /* This means last_traceTickCount is higher than uiTraceTickCount,
\r
152 so we have previously compensated for a missed tick.
\r
153 Therefore we use the last stored value because that is more accurate. */
\r
154 traceTickCount = last_traceTickCount;
\r
158 /* Business as usual */
\r
159 traceTickCount = uiTraceTickCount;
\r
162 /* Check for overflow. May occur if the update of uiTraceTickCount has been
\r
163 delayed due to disabled interrupts. */
\r
164 if (traceTickCount == last_traceTickCount && hwtc_count < last_hwtc_count)
\r
166 /* A trace tick has occurred but not been executed by the kernel, so we compensate manually. */
\r
170 /* Check if the return address is OK, then we perform the calculation. */
\r
173 /* Get timestamp from trace ticks. Scale down the period to avoid unwanted overflows. */
\r
174 *pTimestamp = traceTickCount * (HWTC_PERIOD / HWTC_DIVISOR);
\r
175 /* Increase timestamp by (hwtc_count + "lost hardware ticks from scaling down period") / HWTC_DIVISOR. */
\r
176 *pTimestamp += (hwtc_count + traceTickCount * (HWTC_PERIOD % HWTC_DIVISOR)) / HWTC_DIVISOR;
\r
178 last_timestamp = *pTimestamp;
\r
181 /* Store the previous values. */
\r
182 last_traceTickCount = traceTickCount;
\r
183 last_hwtc_count = hwtc_count;
\r