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