《嵌入式软件的时间分析》从书中到实践-使用Tracealyzer进行RTOS调试分析
<div class='showpostmsg'><p>书中分享了很多理论,方法和案例,</p><p>基于本书,本人在此基础上再分享一些更贴近实战的案例分享。</p>
<p>本人公众号(嵌入式软硬件技术:RTOS,GUI,FS,协议栈,ARM,总线,嵌入式C,开发环境 and blablaba....多年经验分享,非硬货不发,带你扒开每一个技术背后的根本原理。)</p>
<p> </p>
<p> </p>
<h1>一. <strong>前言</strong></h1>
<p>本文来介绍RTOS调试利器,可视化Trace工具,常见的有以下几个</p>
<p>Percepio的Tracealyzer;</p>
<p>SEGGER的SystemView;</p>
<p>Micrium的μC/Probe。</p>
<p>lμC/Probe是元老级别工具,相信很多人最开始接触RTOS Trace的技术就是从它开始的,它也是伴随着uC/OS而知名,甚至很早前还流出过其上位机源码,是配合uCOS调试的最佳利器。当然也可以调试其他RTOS甚至NO OS,其特点是上位机GUI灵活的配置,可以拖拽GUI显示不同的界面,类似GUIBuild。Target源码可以从以下地址下载</p>
<p><a href="https://github.com/weston-embedded/uC-Probe-Target" target="_blank">https://github.com/weston-embedded/uC-Probe-Target</a>。</p>
<p>分享上位机工具下载</p>
<p>链接:<a href="https://pan.baidu.com/s/1s60qEaSoFEmGBxm3sFb-dA?pwd=mzy7" target="_blank">https://pan.baidu.com/s/1s60qEaSoFEmGBxm3sFb-dA?pwd=mzy7</a></p>
<p>提取码:mzy7</p>
<p>lSystemView是SEGGER开发,原配自家RTOS embOS,当然也支持其他主流RTOS比如uC/OS-III, Micrium OS Kernel, FreeRTOS, NuttX 和 Zephyr ,上位机和Target源码可从如下地址下载<a href="https://www.segger.com/downloads/systemview/" target="_blank">https://www.segger.com/downloads/systemview/</a></p>
<p>lPercepio则是目前最亮眼之星,丰富的事件,信号等图表,使用简单,UI个人感觉更适合时序分析。分享上位机工具如下:</p>
<p>链接:<a href="https://pan.baidu.com/s/1agHqqQ0M-Yo9wv30Ft-C3g?pwd=kzcq" target="_blank">https://pan.baidu.com/s/1agHqqQ0M-Yo9wv30Ft-C3g?pwd=kzcq</a></p>
<p>提取码:kzcq</p>
<h1>二. <strong>安装Tracealyzer</strong></h1>
<p>注意:安装软件仅供学习使用,请支持正版软件。</p>
<p>双击打开Tracealyzer-4.6.5-windows64.exe,弹出用户账户控制,点击是</p>
<p> </p>
<div style="text-align: center;"></div>
<p> </p>
<p>点击Next</p>
<p> </p>
<div style="text-align: center;"></div>
<p> </p>
<p>选择安装路径,点击Install</p>
<p> </p>
<div style="text-align: center;"></div>
<p> </p>
<p>点击Finish</p>
<p> </p>
<div style="text-align: center;"></div>
<p> </p>
<p>使用Tracealyzer.exe, Tracealyzer.exe.config替换安装目录D:\Program Files\Percepio\Tracealyzer 4下的文件.</p>
<p>打开Tracealyzer.exe</p>
<p> </p>
<div style="text-align: center;"></div>
<p> </p>
<p>解压I_LOVE_DVT.rar<br />
打开TracealyzerKeyfileMaker.exe,点击Generate!生成license文件</p>
<p>弹出对话框点击确认,点击Exit退出。把license文件保存在某个地方,我这里放在安装路径D:\Program Files\Percepio\Tracealyzer 4下。</p>
<p> </p>
<div style="text-align: center;"></div>
<p> </p>
<p>运行Tracealyzer,指定刚生成的license文件</p>
<p> </p>
<div style="text-align: center;"></div>
<p> </p>
<p> </p>
<div style="text-align: center;"></div>
<p> </p>
<p> </p>
<div style="text-align: center;"></div>
<p> </p>
<p> </p>
<div style="text-align: center;"></div>
<p> </p>
<p> </p>
<div style="text-align: center;"></div>
<p> </p>
<p> </p>
<div style="text-align: center;"></div>
<p> </p>
<h1><strong>三.工程中添加Tracealyzer源码</strong></h1>
<h2><strong>3.1下载源码</strong></h2>
<p><a href="https://github.com/percepio/TraceRecorderSource/tags" target="_blank">https://github.com/percepio/TraceRecorderSource/tags</a></p>
<p>选择对应版本</p>
<p> </p>
<div style="text-align: center;"></div>
<p> </p>
<p> </p>
<p>查看工具版本,我这里是4.6.5</p>
<p>Help->About Percepio Tracealyzer</p>
<p> </p>
<div style="text-align: center;"></div>
<p> </p>
<p>git clone --branch Tz4/4.6/v4.6.5 <a href="https://github.com/percepio/TraceRecorderSource.git" target="_blank">https://github.com/percepio/TraceRecorderSource.git</a></p>
<h2><strong>3.2添加源码到自己的工程</strong></h2>
<p>需要以下源码</p>
<p>以下源码无需任何修改</p>
<p>|-- trcAssert.c</p>
<p>|-- trcCounter.c</p>
<p>|-- trcDiagnostics.c</p>
<p>|-- trcEntryTable.c</p>
<p>|-- trcError.c</p>
<p>|-- trcEvent.c</p>
<p>|-- trcEventBuffer.c</p>
<p>|-- trcExtension.c</p>
<p>|-- trcHardwarePort.c</p>
<p>|-- trcHeap.c</p>
<p>|-- trcISR.c</p>
<p>|-- trcInternalEventBuffer.c</p>
<p>|-- trcInterval.c</p>
<p>|-- trcMultiCoreEventBuffer.c</p>
<p>|-- trcObject.c</p>
<p>|-- trcPrint.c</p>
<p>|-- trcSnapshotRecorder.c</p>
<p>|-- trcStackMonitor.c</p>
<p>|-- trcStateMachine.c</p>
<p>|-- trcStaticBuffer.c</p>
<p>|-- trcStreamingRecorder.c</p>
<p>|-- trcString.c</p>
<p>|-- trcTask.c</p>
<p>`-- trcTimestamp.c</p>
<p>配置如下头文件包含路径</p>
<p>TraceRecorderSource/include</p>
<p>TraceRecorderSource/config</p>
<h2><strong>3.3平台适配</strong></h2>
<h3><strong>3.3.1头文件包含路径</strong></h3>
<p>配置头文件包含路径,这里以FreeRTOS为例,其他平台参考kernelports对应目录</p>
<p>TraceRecorderSource/kernelports/FreeRTOS/config</p>
<p>TraceRecorderSource/kernelports/FreeRTOS/include</p>
<h3><strong>3.3.2配置FREERTOS版本</strong></h3>
<p>TraceRecorderSource/kernelports/FreeRTOS/config/trcKernelPortConfig.h下修改</p>
<p>#define TRC_CFG_FREERTOS_VERSION FREERTOS_VERSION_NOT_SET</p>
<p>为</p>
<p>#define TRC_CFG_FREERTOS_VERSION TRC_FREERTOS_VERSION_10_2_1</p>
<p>我这里使用的是10.2.1版本。</p>
<h3><strong>3.3.3配置头文件</strong></h3>
<p>TraceRecorderSource/config/trcConfig.h中</p>
<p>注释掉</p>
<p>#error "Trace Recorder: Please include your processor's header file here and remove this line."</p>
<p>添加</p>
<p>#include "FreeRTOS.h"</p>
<h3><strong>3.3.4 Kernel port</strong></h3>
<p>我这里直接使用</p>
<p>TraceRecorderSource/kernelports/FreeRTOS/,其他平台可以根据模板修改,实现对应的接口。</p>
<p>添加头文件包含路径</p>
<p>TraceRecorderSource/kernelports/FreeRTOS/config</p>
<p>TraceRecorderSource/kernelports/FreeRTOS/include</p>
<p>和源码</p>
<p>TraceRecorderSource/kernelports/FreeRTOS/trcKernelPort.c</p>
<p>该源码需要实现</p>
<p>xTraceKernelPortEnable</p>
<p>xTraceKernelPortInitialize</p>
<h3><strong>3.3.5 trace宏接口</strong></h3>
<p>在FreeRTOSConfig.h的最后#include "trcRecorder.h"</p>
<p>portmacro.h中</p>
<p>#define portBASE_TYPE int32_t</p>
<p>改为</p>
<p>#define portBASE_TYPE int</p>
<h2><strong>3.4适配时间相关硬件接口</strong></h2>
<p>TraceRecorderSource/include/trcDefines.h下定义了支持的port,</p>
<section>
<pre>
<code>/****** Port Name ************************************* Code ** Official ** OS Platform *********/
#define TRC_HARDWARE_PORT_APPLICATION_DEFINED 98/*- - */
#define TRC_HARDWARE_PORT_NOT_SET 99/*- - */
#define TRC_HARDWARE_PORT_HWIndependent 0 /*Yes Any */
#define TRC_HARDWARE_PORT_Win32 1 /*Yes FreeRTOS on Win32 */
#define TRC_HARDWARE_PORT_Atmel_AT91SAM7 2 /*No Any */
#define TRC_HARDWARE_PORT_Atmel_UC3A0 3 /*No Any */
#define TRC_HARDWARE_PORT_ARM_Cortex_M 4 /*Yes Any */
#define TRC_HARDWARE_PORT_Renesas_RX600 6 /*Yes Any */
#define TRC_HARDWARE_PORT_MICROCHIP_PIC24_PIC32 7 /*Yes Any */
#define TRC_HARDWARE_PORT_TEXAS_INSTRUMENTS_TMS570_RM48 8 /*Yes Any */
#define TRC_HARDWARE_PORT_TEXAS_INSTRUMENTS_MSP430 9 /*No Any */
#define TRC_HARDWARE_PORT_XILINX_PPC405 11/*No FreeRTOS */
#define TRC_HARDWARE_PORT_XILINX_PPC440 12/*No FreeRTOS */
#define TRC_HARDWARE_PORT_XILINX_MICROBLAZE 13/*No Any */
#define TRC_HARDWARE_PORT_XILINX_ZyncUltraScaleR5 14/*No FreeRTOS */
#define TRC_HARDWARE_PORT_NXP_LPC210X 15/*No Any */
#define TRC_HARDWARE_PORT_ARM_CORTEX_A9 16/*Yes Any */
#define TRC_HARDWARE_PORT_POWERPC_Z4 17/*No FreeRTOS */
#define TRC_HARDWARE_PORT_Altera_NiosII 18/*Yes Any (Tested with FreeRTOS) */
#define TRC_HARDWARE_PORT_ZEPHYR 19/*Yes Zephyr */
#define TRC_HARDWARE_PORT_XTensa_LX6 20/*Yes ESP-IDF FreeRTOS */
#define TRC_HARDWARE_PORT_XTensa_LX7 21/*Yes ESP-IDF FreeRTOS */
#define TRC_HARDWARE_PORT_Win64 22/*Yes FreeRTOS on Win64 */
#define TRC_HARDWARE_PORT_XMOS_XCOREAI 23/*Yes FreeRTOS SMP */
#define TRC_HARDWARE_PORT_RISCV_RV32I 24/*Yes FreeRTOS */
#define TRC_HARDWARE_PORT_CYCLONE_V_HPS 25/*Yes </code></pre>
<div contenteditable="false" tabindex="-1"> </div>
</section>
<p> </p>
<p>如果你的硬件在上面中存在,则在文件TraceRecorderSource/config/trcConfig.h中定义宏TRC_CFG_HARDWARE_PORT为上述指定值。</p>
<p>我这里将</p>
<p>#define TRC_CFG_HARDWARE_PORT TRC_HARDWARE_PORT_NOT_SET</p>
<p>改为上述指定的值,我这里改为TRC_HARDWARE_PORT_APPLICATION_DEFINED即自行实现</p>
<p>#define TRC_CFG_HARDWARE_PORT TRC_HARDWARE_PORT_APPLICATION_DEFINED</p>
<p>可以看到TraceRecorderSource/include/trcHardwarePort.h中根据配置宏TRC_CFG_HARDWARE_PORT实现的接口</p>
<p>比如配置为TRC_HARDWARE_PORT_APPLICATION_DEFINED如下</p>
<p>#elif (TRC_CFG_HARDWARE_PORT == TRC_HARDWARE_PORT_APPLICATION_DEFINED)</p>
<p> #if !( defined (TRC_HWTC_TYPE) && defined (TRC_HWTC_COUNT) && defined (TRC_HWTC_PERIOD) && defined (TRC_HWTC_FREQ_HZ) && defined (TRC_IRQ_PRIORITY_ORDER) )</p>
<p> #error "The hardware port is not completely defined!"</p>
<p> #endif</p>
<p>则需要在上述位置实现以下接口</p>
<p><strong>TRC_HWTC_TYPE</strong></p>
<p>可配置为如下值</p>
<p>#define TRC_FREE_RUNNING_32BIT_INCR 1 /* 从0计数到0xFFFFFFFF */</p>
<p>#define TRC_FREE_RUNNING_32BIT_DECR 2 /* 从0xFFFFFFFF计数到0 */</p>
<p>#define TRC_OS_TIMER_INCR 3 /*以OS TICK为单位 0 计数到(TRC_HWTC_PERIOD-1)*/</p>
<p>#define TRC_OS_TIMER_DECR 4 /*以OS TICK为单位 (TRC_HWTC_PERIOD-1)计数到0*/</p>
<p>#define TRC_CUSTOM_TIMER_INCR 5 /* 从0计数到TRC_HWTC_PERIOD-1 */</p>
<p>#define TRC_CUSTOM_TIMER_DECR 6 /*从TRC_HWTC_PERIOD-1 计数到 0*/</p>
<p><strong>TRC_HWTC_COUNT</strong></p>
<p>获取当前的时间戳,原型为TraceUnsignedBaseType_t TRC_HWTC_COUNT(void)</p>
<p>TRC_HWTC_PERIOD</p>
<p>HWTC_COUNT获取的时间戳的范围</p>
<p>如果前面TRC_HWTC_TYPE使用TRC_FREE_RUNNING_32BIT_INCR/DECR则必须配置为0</p>
<p>TRC_HWTC_FREQ_HZ</p>
<p>HWTC_COUNT获取的时间戳的频率</p>
<p>TRC_IRQ_PRIORITY_ORDER</p>
<p>配置为1表示高优先级任务的优先级数越大,配置为0则反之。FREERTOS配置为1。</p>
<p>我这里最终实现如下</p>
<section>
<pre>
<code>#elif (TRC_CFG_HARDWARE_PORT == TRC_HARDWARE_PORT_APPLICATION_DEFINED)
extern uint32_t my_stream_get_tick(void);
#define TRC_HWTC_TYPE TRC_FREE_RUNNING_32BIT_INCR
#define TRC_HWTC_COUNT my_stream_get_tick()
#define TRC_HWTC_FREQ_HZ 1000000
#define TRC_HWTC_PERIOD 0
#define TRC_IRQ_PRIORITY_ORDER 1
#if !( defined (TRC_HWTC_TYPE) && defined (TRC_HWTC_COUNT) && defined (TRC_HWTC_PERIOD) && defined (TRC_HWTC_FREQ_HZ) && defined (TRC_IRQ_PRIORITY_ORDER) )
#error "The hardware port is not completely defined!"
#endif</code></pre>
<div contenteditable="false" tabindex="-1"> </div>
</section>
<p>需要实现获取时间戳接口</p>
<p>我这里xx_timer_get_time是获取的1uS为单位的定时器的时间</p>
<section>
<pre>
<code>uint32_t my_stream_get_tick(void)
{
return xx_timer_get_time();
}</code></pre>
<div contenteditable="false" tabindex="-1"> </div>
</section>
<p> </p>
<h2><strong>3.5 适配通讯接口</strong></h2>
<p>streamports下有模板,需要和模板实现一样的目录和文件名</p>
<p>我这里新建一个文件夹MY_STREAM,内容如下,可以直接从其他模板复制。</p>
<p>|-- config</p>
<p>| `-- trcStreamPortConfig.h</p>
<p>|-- include</p>
<p>| `-- trcStreamPort.h</p>
<p>`-- trcStreamPort.c需要将上述trcStreamPortConfig.h,trcStreamPort.h添加到头文件包含路径</p>
<pre>
<code>TraceRecorderSource/streamports/MY_STREAM/include
TraceRecorderSource/streamports/MY_STREAM/config</code></pre>
<section>
<div contenteditable="false" tabindex="-1"> </div>
</section>
<p>TraceRecorderSource/streamports/MY_STREAM/trcStreamPort.c添加到工程源码中。</p>
<p>该文件下需要实现以下接口</p>
<p>其中以下几个是必须需要实现的</p>
<section>
<pre>
<code>
/**
* @internal Stream port initialize callback.
*
* This function is called by the recorder as part of its initialization phase.
*
* @param pxBuffer Buffer
*
* @retval TRC_FAIL Initialization failed
* @retval TRC_SUCCESS Success
*/
traceResult xTraceStreamPortInitialize(TraceStreamPortBuffer_t* pxBuffer);
/**
* <a href="home.php?mod=space&uid=159083" target="_blank">@brief </a> Reads data through the stream port interface.
*
* @param pvData Destination data buffer
* @param uiSize Destination data buffer size
* @param piBytesRead Bytes read
*
* @retval TRC_FAIL Read failed
* @retval TRC_SUCCESS Success
*/
traceResult xTraceStreamPortReadData(void* pvData, uint32_t uiSize, int32_t* piBytesRead);
/**
* @brief Writes data through the stream port interface.
*
* @param pvData Data to write
* @param uiSize Data to write size
* @param piBytesWritten Bytes written
*
* @retval TRC_FAIL Write failed
* @retval TRC_SUCCESS Success
*/
traceResult xTraceStreamPortWriteData(void* pvData, uint32_t uiSize, int32_t* piBytesWritten);
</code></pre>
<div contenteditable="false" tabindex="-1"> </div>
</section>
<p> </p>
<p>以下几个可以使用内部Buffer,使用宏</p>
<p>#define TRC_USE_INTERNAL_BUFFER 1</p>
<p> </p>
<pre>
<code>/**
* @brief Allocates data from the stream port.
*
* @param uiSize Allocation size
* @param ppvData Allocation data pointer
*
* @retval TRC_FAIL Allocate failed
* @retval TRC_SUCCESS Success
*/
#define xTraceStreamPortAllocate xTraceInternalEventBufferAlloc
/**
* @brief Commits data to the stream port, depending on the implementation/configuration of the
* stream port this data might be directly written to the stream port interface, buffered, or
* something else.
*
* @param pvData Data to commit
* @param uiSize Data to commit size
* @param piBytesCommitted Bytes committed
*
* @retval TRC_FAIL Commit failed
* @retval TRC_SUCCESS Success
*/
#define xTraceStreamPortCommit xTraceInternalEventBufferAllocCommit
#define xTraceStreamPortOnEnable(uiStartOption) ((void)(uiStartOption), TRC_SUCCESS)
#define xTraceStreamPortOnDisable() (TRC_SUCCESS)
#define xTraceStreamPortOnTraceBegin() (TRC_SUCCESS)
#define xTraceStreamPortOnTraceEnd() (TRC_SUCCESS)</code></pre>
<section>
<div contenteditable="false" tabindex="-1"> </div>
</section>
<p>TraceRecorderSource/streamports/MY_STREAM/trcStreamPort.c如下</p>
<section>
<p> </p>
<pre>
<code>#include <trcRecorder.h>
#if (TRC_USE_TRACEALYZER_RECORDER == 1)
#if (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING)
/**
* @brief Reads data through the stream port interface.
*
* @param pvData Destination data buffer
* @param uiSize Destination data buffer size
* @param piBytesRead Bytes read
*
* @retval TRC_FAIL Read failed
* @retval TRC_SUCCESS Success
*/
traceResult xTraceStreamPortReadData(void* pvData, uint32_t uiSize, int32_t* piBytesRead)
{
(void)pvData;
(void)uiSize;
(void)piBytesRead;
return TRC_SUCCESS;
}
traceResult xTraceStreamPortWriteData(void* pvData, uint32_t uiSize, int32_t* piBytesWritten)
{
(void)pvData;
(void)uiSize;
(void)piBytesWritten;
return TRC_SUCCESS;
}
traceResult xTraceStreamPortInitialize(TraceStreamPortBuffer_t* pxBuffer)
{
TRC_ASSERT_EQUAL_SIZE(TraceStreamPortBuffer_t, TraceStreamPortRTT_t);
if (pxBuffer == 0)
{
return TRC_FAIL;
}
#if (TRC_USE_INTERNAL_BUFFER == 1)
return xTraceInternalEventBufferInitialize(pxBuffer->buffer,sizeof(pxBuffer->buffer));
#else
return TRC_SUCCESS;
#endif
}
#endif/*(TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING)*/
#endif/*(TRC_USE_TRACEALYZER_RECORDER == 1)*/
TraceRecorderSource/streamports/MY_STREAM/include/trcStreamPort.h内容如下
#ifndef TRC_STREAM_PORT_H
#define TRC_STREAM_PORT_H
#include <trcTypes.h>
#include <trcStreamPortConfig.h>
#ifdef __cplusplus
extern "C" {
#endif
#define TRC_USE_INTERNAL_BUFFER 1
#define TRC_INTERNAL_EVENT_BUFFER_WRITE_MODE (TRC_CFG_STREAM_PORT_INTERNAL_BUFFER_WRITE_MODE)
#define TRC_INTERNAL_EVENT_BUFFER_TRANSFER_MODE (TRC_CFG_STREAM_PORT_INTERNAL_BUFFER_TRANSFER_MODE)
#define TRC_INTERNAL_BUFFER_CHUNK_SIZE (TRC_CFG_STREAM_PORT_INTERNAL_BUFFER_CHUNK_SIZE)
#define TRC_INTERNAL_BUFFER_CHUNK_TRANSFER_AGAIN_SIZE_LIMIT (TRC_CFG_STREAM_PORT_INTERNAL_BUFFER_CHUNK_TRANSFER_AGAIN_SIZE_LIMIT)
#define TRC_INTERNAL_BUFFER_CHUNK_TRANSFER_AGAIN_COUNT_LIMIT (TRC_CFG_STREAM_PORT_INTERNAL_BUFFER_CHUNK_TRANSFER_AGAIN_COUNT_LIMIT)
#define TRC_STREAM_PORT_USB_BUFFER_SIZE ((((TRC_CFG_STREAM_PORT_USB_BUFFER_SIZE) + sizeof(TraceUnsignedBaseType_t) - 1) / sizeof(TraceUnsignedBaseType_t)) * sizeof(TraceUnsignedBaseType_t))
#define TRC_STREAM_PORT_INTERNAL_BUFFER_SIZE ((((TRC_CFG_STREAM_PORT_INTERNAL_BUFFER_SIZE) + sizeof(TraceUnsignedBaseType_t) - 1) / sizeof(TraceUnsignedBaseType_t)) * sizeof(TraceUnsignedBaseType_t))
typedef struct TraceStreamPortBuffer /* Aligned */
{
uint8_t buffer[(TRC_STREAM_PORT_USB_BUFFER_SIZE) + (TRC_STREAM_PORT_INTERNAL_BUFFER_SIZE) + sizeof(TraceUnsignedBaseType_t)];
} TraceStreamPortBuffer_t;
/**
* @internal Stream port initialize callback.
*
* This function is called by the recorder as part of its initialization phase.
*
* @param pxBuffer Buffer
*
* @retval TRC_FAIL Initialization failed
* @retval TRC_SUCCESS Success
*/
traceResult xTraceStreamPortInitialize(TraceStreamPortBuffer_t* pxBuffer);
/**
* @brief Reads data through the stream port interface.
*
* @param pvData Destination data buffer
* @param uiSize Destination data buffer size
* @param piBytesRead Bytes read
*
* @retval TRC_FAIL Read failed
* @retval TRC_SUCCESS Success
*/
traceResult xTraceStreamPortReadData(void* pvData, uint32_t uiSize, int32_t* piBytesRead);
/**
* @brief Writes data through the stream port interface.
*
* @param pvData Data to write
* @param uiSize Data to write size
* @param piBytesWritten Bytes written
*
* @retval TRC_FAIL Write failed
* @retval TRC_SUCCESS Success
*/
traceResult xTraceStreamPortWriteData(void* pvData, uint32_t uiSize, int32_t* piBytesWritten);
/**
* @brief Allocates data from the stream port.
*
* @param uiSize Allocation size
* @param ppvData Allocation data pointer
*
* @retval TRC_FAIL Allocate failed
* @retval TRC_SUCCESS Success
*/
#define xTraceStreamPortAllocate xTraceInternalEventBufferAlloc
/**
* @brief Commits data to the stream port, depending on the implementation/configuration of the
* stream port this data might be directly written to the stream port interface, buffered, or
* something else.
*
* @param pvData Data to commit
* @param uiSize Data to commit size
* @param piBytesCommitted Bytes committed
*
* @retval TRC_FAIL Commit failed
* @retval TRC_SUCCESS Success
*/
#define xTraceStreamPortCommit xTraceInternalEventBufferAllocCommit
#define xTraceStreamPortOnEnable(uiStartOption) ((void)(uiStartOption), TRC_SUCCESS)
#define xTraceStreamPortOnDisable() (TRC_SUCCESS)
#define xTraceStreamPortOnTraceBegin() (TRC_SUCCESS)
#define xTraceStreamPortOnTraceEnd() (TRC_SUCCESS)
#ifdef __cplusplus
}
#endif
#endif /* TRC_STREAM_PORT_H */</code></pre>
<p> </p>
</section>
<p>TraceRecorderSource/streamports/MY_STREAM/config/trcStreamPortConfig.h内容如下</p>
<section>
<pre>
<code>
/*
* Trace Recorder for Tracealyzer v4.8.2
* Copyright 2023 Percepio AB
* www.percepio.com
*
* SPDX-License-Identifier: Apache-2.0
*
* The configuration for trace streaming ("stream ports").
*/
#ifndef TRC_STREAM_PORT_CONFIG_H
#define TRC_STREAM_PORT_CONFIG_H
#ifdef __cplusplus
extern "C" {
#endif
/**
* <a href="home.php?mod=space&uid=567129" target="_blank">@def </a> TRC_CFG_STREAM_PORT_DELAY_ON_BUSY
*
* @brief The time to wait if the USB interface is busy.
*/
#define TRC_CFG_STREAM_PORT_DELAY_ON_BUSY 1
/**
* @def TRC_CFG_STREAM_PORT_USB_BUFFER_SIZE
*
* @brief Specifies the size of the usb buffer.
*/
#define TRC_CFG_STREAM_PORT_USB_BUFFER_SIZE 64
/**
* @def TRC_CFG_STREAM_PORT_INTERNAL_BUFFER_SIZE
*
* @brief Configures the size of the internal buffer if used.
*/
#define TRC_CFG_STREAM_PORT_INTERNAL_BUFFER_SIZE 10240
/**
* @def TRC_CFG_STREAM_PORT_INTERNAL_BUFFER_WRITE_MODE
*
* @brief This should be set to TRC_INTERNAL_EVENT_BUFFER_OPTION_WRITE_MODE_DIRECT for best performance.
*/
#define TRC_CFG_STREAM_PORT_INTERNAL_BUFFER_WRITE_MODE TRC_INTERNAL_EVENT_BUFFER_OPTION_WRITE_MODE_DIRECT
/**
* @def TRC_CFG_STREAM_PORT_INTERNAL_BUFFER_TRANSFER_MODE
*
* @brief Defines if the internal buffer will attempt to transfer all data each time or limit it to a chunk size.
*/
#define TRC_CFG_STREAM_PORT_INTERNAL_BUFFER_TRANSFER_MODE TRC_INTERNAL_EVENT_BUFFER_OPTION_TRANSFER_MODE_ALL
/**
* @def TRC_CFG_STREAM_PORT_INTERNAL_BUFFER_CHUNK_SIZE
*
* @brief Defines the maximum chunk size when transferring
* internal buffer events in chunks.
*/
#define TRC_CFG_STREAM_PORT_INTERNAL_BUFFER_CHUNK_SIZE 64
/**
* @def TRC_CFG_STREAM_PORT_INTERNAL_BUFFER_CHUNK_TRANSFER_AGAIN_SIZE_LIMIT
*
* @brief Defines the number of transferred bytes needed to trigger another transfer.
* It also depends on TRC_CFG_STREAM_PORT_INTERNAL_BUFFER_CHUNK_TRANSFER_AGAIN_COUNT_LIMIT to set a maximum number
* of additional transfers this loop.
* This will increase throughput by immediately doing a transfer and not wait for another xTraceTzCtrl() loop.
*/
#define TRC_CFG_STREAM_PORT_INTERNAL_BUFFER_CHUNK_TRANSFER_AGAIN_SIZE_LIMIT 64
/**
* @def TRC_CFG_STREAM_PORT_INTERNAL_BUFFER_CHUNK_TRANSFER_AGAIN_COUNT_LIMIT
*
* @brief Defines the maximum number of times to trigger another transfer before returning to xTraceTzCtrl().
* It also depends on TRC_CFG_STREAM_PORT_INTERNAL_BUFFER_CHUNK_TRANSFER_AGAIN_SIZE_LIMIT to see if a meaningful amount of data was
* transferred in the last loop.
* This will increase throughput by immediately doing a transfer and not wait for another xTraceTzCtrl() loop.
*/
#define TRC_CFG_STREAM_PORT_INTERNAL_BUFFER_CHUNK_TRANSFER_AGAIN_COUNT_LIMIT 5
#ifdef __cplusplus
}
#endif
#endif /* TRC_STREAM_PORT_CONFIG_H */
</code></pre>
<p> </p>
</section>
<p> </p>
<p>需要注意的是,使用TRC_USE_INTERNAL_BUFFER=1时</p>
<p>TraceRecorderSource/streamports/MY_STREAM/config/trcStreamPortConfig.h中</p>
<section>
<pre>
<code>#define TRC_CFG_STREAM_PORT_INTERNAL_BUFFER_SIZE 35000</code></pre>
<div contenteditable="false" tabindex="-1"> </div>
</section>
<p>可能太大导致RAM不够,可以改小该内部存储。</p>
<section>
<pre>
<code>typedef struct TraceStreamPortBuffer
{
uint8_t buffer[(TRC_STREAM_PORT_USB_BUFFER_SIZE) + (TRC_STREAM_PORT_INTERNAL_BUFFER_SIZE) + sizeof(TraceUnsignedBaseType_t)];
} TraceStreamPortBuffer_t;</code></pre>
<div contenteditable="false" tabindex="-1"> </div>
</section>
<p> </p>
<h2><strong>3.6初始化</strong></h2>
<p>在 vStartScheduler();前 调用如下接口初始化</p>
<section>
<pre>
<code>#include <trcRecorder.h>
/* First initialize */
xTraceInitialize();
/*启动kernel*/
/* Start tracing */
xTraceEnable(TRC_START);或者xTraceEnable(TRC_START_FROM_HOST);</code></pre>
<p> </p>
<p> </p>
<div contenteditable="false" tabindex="-1"> </div>
</section>
<h2><strong>3.7 中断栈 任务栈 堆</strong></h2>
<p>由于中断中回调执行一些trace回调函数,所以中断栈注意要加大一点。</p>
<p>注意设置任务栈大小要合适</p>
<p>TraceRecorderSource/config/trcConfig.h</p>
<p>#define TRC_CFG_CTRL_TASK_STACK_SIZE 2048</p>
<p>注意内部堆大小设置</p>
<p>/streamports/MY_STREAM/config/trcStreamPortConfig.h</p>
<p>#define TRC_CFG_STREAM_PORT_INTERNAL_BUFFER_SIZE 10240</p>
<p>系统使用堆大小,FreeRTOSConfig.h中</p>
<p>#define configTOTAL_HEAP_SIZE ((size_t)((unsigned char *)&_heap_size))</p>
<p> </p>
<h1><strong>四.创建Tracealyzer工程测试</strong></h1>
<p>打开Tracealyzer软件</p>
<p>创建流trace,对应源码</p>
<p>TRC_USE_TRACEALYZER_RECORDER配置为1 使能trace</p>
<p>TRC_CFG_RECORDER_MODE 配置为TRC_RECORDER_MODE_STREAMING 流模式</p>
<p> </p>
<div style="text-align: center;"></div>
<p> </p>
<p>配置通讯接口我这里使用CDC,和串口一样,点击OK</p>
<p> </p>
<div style="text-align: center;"></div>
<p> </p>
<p>点击Start Session,启动。</p>
<p> </p>
<div style="text-align: center;"></div>
<p> </p>
<p>抓取到数据后,各窗口显示相应的图表</p>
<p> </p>
<div style="text-align: center;"></div>
<p> </p>
<p>比如事件窗口可以清晰的看到任务的调度过程</p>
<p> </p>
<div style="text-align: center;"></div>
<p> </p>
<p>比如CPU负载</p>
<p> </p>
<div style="text-align: center;"></div>
<p> </p>
<p> </p>
<h1><strong>五.总结</strong></h1>
<p>我们这里搭建了基于FreeRTOS的Tracealyzer环境,后续我们再分享一系列文章,分享下Tracealyzer的原理,然后分享一些典型的案例。</p>
<p>注意代码和Tracealyzer工具的版本要匹配,否则会提示错误</p>
<p>比如如下提示代码版本高于工具</p>
<p> </p>
<div style="text-align: center;"></div>
<p> </p>
<p>另外就是注意堆栈的设置,以及数据收发接口,最好是使用fifo方式。</p>
<p> </p>
</div><script> var loginstr = '<div class="locked">查看本帖全部内容,请<a href="javascript:;" style="color:#e60000" class="loginf">登录</a>或者<a href="https://bbs.eeworld.com.cn/member.php?mod=register_eeworld.php&action=wechat" style="color:#e60000" target="_blank">注册</a></div>';
if(parseInt(discuz_uid)==0){
(function($){
var postHeight = getTextHeight(400);
$(".showpostmsg").html($(".showpostmsg").html());
$(".showpostmsg").after(loginstr);
$(".showpostmsg").css({height:postHeight,overflow:"hidden"});
})(jQuery);
} </script><script type="text/javascript">(function(d,c){var a=d.createElement("script"),m=d.getElementsByTagName("script"),eewurl="//counter.eeworld.com.cn/pv/count/";a.src=eewurl+c;m.parentNode.insertBefore(a,m)})(document,523)</script> <p>大佬好厉害!学到了</p>
<p> </p>
页:
[1]