qinyunti 发表于 2024-6-23 16:06

《嵌入式软件的时间分析》从书中到实践-使用Tracealyzer进行RTOS调试分析

<div class='showpostmsg'><p>书中分享了很多理论,方法和案例,</p>

<p>基于本书,本人在此基础上再分享一些更贴近实战的案例分享。</p>

<p>本人公众号(嵌入式软硬件技术:RTOS,GUI,FS,协议栈,ARM,总线,嵌入式C,开发环境 and blablaba....多年经验分享,非硬货不发,带你扒开每一个技术背后的根本原理。)</p>

<p> &nbsp;</p>

<p>&nbsp;</p>

<h1>一.&nbsp;<strong>前言</strong></h1>

<p>本文来介绍RTOS调试利器,可视化Trace工具,常见的有以下几个</p>

<p>Percepio的Tracealyzer;</p>

<p>SEGGER的SystemView;</p>

<p>Micrium的&mu;C/Probe。</p>

<p>l&mu;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&nbsp;和&nbsp;Zephyr&nbsp;,上位机和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>二.&nbsp;<strong>安装Tracealyzer</strong></h1>

<p>注意:安装软件仅供学习使用,请支持正版软件。</p>

<p>双击打开Tracealyzer-4.6.5-windows64.exe,弹出用户账户控制,点击是</p>

<p>&nbsp;</p>

<div style="text-align: center;"></div>

<p>&nbsp;</p>

<p>点击Next</p>

<p>&nbsp;</p>

<div style="text-align: center;"></div>

<p>&nbsp;</p>

<p>选择安装路径,点击Install</p>

<p>&nbsp;</p>

<div style="text-align: center;"></div>

<p>&nbsp;</p>

<p>点击Finish</p>

<p>&nbsp;</p>

<div style="text-align: center;"></div>

<p>&nbsp;</p>

<p>使用Tracealyzer.exe, Tracealyzer.exe.config替换安装目录D:\Program Files\Percepio\Tracealyzer 4下的文件.</p>

<p>打开Tracealyzer.exe</p>

<p>&nbsp;</p>

<div style="text-align: center;"></div>

<p>&nbsp;</p>

<p>解压I_LOVE_DVT.rar<br />
打开TracealyzerKeyfileMaker.exe,点击Generate!生成license文件</p>

<p>弹出对话框点击确认,点击Exit退出。把license文件保存在某个地方,我这里放在安装路径D:\Program Files\Percepio\Tracealyzer 4下。</p>

<p>&nbsp;</p>

<div style="text-align: center;"></div>

<p>&nbsp;</p>

<p>运行Tracealyzer,指定刚生成的license文件</p>

<p>&nbsp;</p>

<div style="text-align: center;"></div>

<p>&nbsp;</p>

<p>&nbsp;</p>

<div style="text-align: center;"></div>

<p>&nbsp;</p>

<p>&nbsp;</p>

<div style="text-align: center;"></div>

<p>&nbsp;</p>

<p>&nbsp;</p>

<div style="text-align: center;"></div>

<p>&nbsp;</p>

<p>&nbsp;</p>

<div style="text-align: center;"></div>

<p>&nbsp;</p>

<p>&nbsp;</p>

<div style="text-align: center;"></div>

<p>&nbsp;</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>&nbsp;</p>

<div style="text-align: center;"></div>

<p>&nbsp;</p>

<p>&nbsp;</p>

<p>查看工具版本,我这里是4.6.5</p>

<p>Help-&gt;About Percepio Tracealyzer</p>

<p>&nbsp;</p>

<div style="text-align: center;"></div>

<p>&nbsp;</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&nbsp;TRC_CFG_FREERTOS_VERSION FREERTOS_VERSION_NOT_SET</p>

<p>为</p>

<p>#define&nbsp;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 &quot;Trace Recorder: Please include your processor&#39;s header file here and remove this line.&quot;</p>

<p>添加</p>

<p>#include&nbsp;&quot;FreeRTOS.h&quot;</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 &quot;trcRecorder.h&quot;</p>

<p>portmacro.h中</p>

<p>#define&nbsp;portBASE_TYPE &nbsp; int32_t</p>

<p>改为</p>

<p>#define&nbsp;portBASE_TYPE &nbsp; 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">&nbsp;</div>
</section>

<p>&nbsp;</p>

<p>如果你的硬件在上面中存在,则在文件TraceRecorderSource/config/trcConfig.h中定义宏TRC_CFG_HARDWARE_PORT为上述指定值。</p>

<p>我这里将</p>

<p>#define&nbsp;TRC_CFG_HARDWARE_PORT TRC_HARDWARE_PORT_NOT_SET</p>

<p>改为上述指定的值,我这里改为TRC_HARDWARE_PORT_APPLICATION_DEFINED即自行实现</p>

<p>#define&nbsp;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&nbsp;(TRC_CFG_HARDWARE_PORT == TRC_HARDWARE_PORT_APPLICATION_DEFINED)</p>

<p>&nbsp;&nbsp;#if&nbsp;!( defined (TRC_HWTC_TYPE)&nbsp;&amp;&amp;&nbsp;defined (TRC_HWTC_COUNT)&nbsp;&amp;&amp;&nbsp;defined (TRC_HWTC_PERIOD)&nbsp;&amp;&amp;&nbsp;defined (TRC_HWTC_FREQ_HZ)&nbsp;&amp;&amp;&nbsp;defined (TRC_IRQ_PRIORITY_ORDER) )</p>

<p>&nbsp; &nbsp; &nbsp;&nbsp;#error&nbsp;&quot;The hardware port is not completely defined!&quot;</p>

<p>&nbsp; #endif</p>

<p>则需要在上述位置实现以下接口</p>

<p><strong>TRC_HWTC_TYPE</strong></p>

<p>可配置为如下值</p>

<p>#define TRC_FREE_RUNNING_32BIT_INCR 1&nbsp;&nbsp;/*&nbsp;从0计数到0xFFFFFFFF */</p>

<p>#define TRC_FREE_RUNNING_32BIT_DECR 2&nbsp;&nbsp;/*&nbsp;从0xFFFFFFFF计数到0 */</p>

<p>#define TRC_OS_TIMER_INCR 3&nbsp;&nbsp;&nbsp;/*以OS TICK为单位&nbsp;0&nbsp;计数到(TRC_HWTC_PERIOD-1)*/</p>

<p>#define TRC_OS_TIMER_DECR 4&nbsp;&nbsp;/*以OS TICK为单位&nbsp;(TRC_HWTC_PERIOD-1)计数到0*/</p>

<p>#define TRC_CUSTOM_TIMER_INCR 5&nbsp;&nbsp;/*&nbsp;从0计数到TRC_HWTC_PERIOD-1 */</p>

<p>#define TRC_CUSTOM_TIMER_DECR 6&nbsp;/*从TRC_HWTC_PERIOD-1&nbsp;计数到&nbsp;0*/</p>

<p><strong>TRC_HWTC_COUNT</strong></p>

<p>获取当前的时间戳,原型为TraceUnsignedBaseType_t&nbsp;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) &amp;&amp; defined (TRC_HWTC_COUNT) &amp;&amp; defined (TRC_HWTC_PERIOD) &amp;&amp; defined (TRC_HWTC_FREQ_HZ) &amp;&amp; defined (TRC_IRQ_PRIORITY_ORDER) )
      #error "The hardware port is not completely defined!"
    #endif</code></pre>

<div contenteditable="false" tabindex="-1">&nbsp;</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">&nbsp;</div>
</section>

<p>&nbsp;</p>

<h2><strong>3.5&nbsp;适配通讯接口</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">&nbsp;</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&amp;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">&nbsp;</div>
</section>

<p>&nbsp;</p>

<p>以下几个可以使用内部Buffer,使用宏</p>

<p>#define TRC_USE_INTERNAL_BUFFER 1</p>

<p>&nbsp;</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">&nbsp;</div>
</section>

<p>TraceRecorderSource/streamports/MY_STREAM/trcStreamPort.c如下</p>

<section>
<p>&nbsp;</p>

<pre>
<code>#include &lt;trcRecorder.h&gt;

#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-&gt;buffer,sizeof(pxBuffer-&gt;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 &lt;trcTypes.h&gt;
#include &lt;trcStreamPortConfig.h&gt;

#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>&nbsp;</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 (&quot;stream ports&quot;).
*/

#ifndef TRC_STREAM_PORT_CONFIG_H
#define TRC_STREAM_PORT_CONFIG_H

#ifdef __cplusplus
extern &quot;C&quot; {
#endif

/**
* <a href="home.php?mod=space&amp;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>&nbsp;</p>
</section>

<p>&nbsp;</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">&nbsp;</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">&nbsp;</div>
</section>

<p>&nbsp;</p>

<h2><strong>3.6初始化</strong></h2>

<p>在&nbsp;vStartScheduler();前 调用如下接口初始化</p>

<section>
<pre>
<code>#include &lt;trcRecorder.h&gt;

    /* First initialize */
    xTraceInitialize();
    /*启动kernel*/
    /* Start tracing */
    xTraceEnable(TRC_START);或者xTraceEnable(TRC_START_FROM_HOST);</code></pre>

<p>&nbsp;</p>

<p>&nbsp;</p>

<div contenteditable="false" tabindex="-1">&nbsp;</div>
</section>

<h2><strong>3.7&nbsp;中断栈 任务栈 堆</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&nbsp;TRC_CFG_STREAM_PORT_INTERNAL_BUFFER_SIZE&nbsp;10240</p>

<p>系统使用堆大小,FreeRTOSConfig.h中</p>

<p>#define&nbsp;configTOTAL_HEAP_SIZE &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ((size_t)((unsigned char&nbsp;*)&amp;_heap_size))</p>

<p>&nbsp;</p>

<h1><strong>四.创建Tracealyzer工程测试</strong></h1>

<p>打开Tracealyzer软件</p>

<p>创建流trace,对应源码</p>

<p>TRC_USE_TRACEALYZER_RECORDER配置为1&nbsp;使能trace</p>

<p>TRC_CFG_RECORDER_MODE&nbsp;配置为TRC_RECORDER_MODE_STREAMING&nbsp;流模式</p>

<p>&nbsp;</p>

<div style="text-align: center;"></div>

<p>&nbsp;</p>

<p>配置通讯接口我这里使用CDC,和串口一样,点击OK</p>

<p>&nbsp;</p>

<div style="text-align: center;"></div>

<p>&nbsp;</p>

<p>点击Start Session,启动。</p>

<p>&nbsp;</p>

<div style="text-align: center;"></div>

<p>&nbsp;</p>

<p>抓取到数据后,各窗口显示相应的图表</p>

<p>&nbsp;</p>

<div style="text-align: center;"></div>

<p>&nbsp;</p>

<p>比如事件窗口可以清晰的看到任务的调度过程</p>

<p>&nbsp;</p>

<div style="text-align: center;"></div>

<p>&nbsp;</p>

<p>比如CPU负载</p>

<p>&nbsp;</p>

<div style="text-align: center;"></div>

<p>&nbsp;</p>

<p>&nbsp;</p>

<h1><strong>五.总结</strong></h1>

<p>我们这里搭建了基于FreeRTOS的Tracealyzer环境,后续我们再分享一系列文章,分享下Tracealyzer的原理,然后分享一些典型的案例。</p>

<p>注意代码和Tracealyzer工具的版本要匹配,否则会提示错误</p>

<p>比如如下提示代码版本高于工具</p>

<p>&nbsp;</p>

<div style="text-align: center;"></div>

<p>&nbsp;</p>

<p>另外就是注意堆栈的设置,以及数据收发接口,最好是使用fifo方式。</p>

<p>&nbsp;</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>

学学学学学学学 发表于 2024-6-25 11:51

<p>大佬好厉害!学到了</p>

<p>&nbsp;</p>
页: [1]
查看完整版本: 《嵌入式软件的时间分析》从书中到实践-使用Tracealyzer进行RTOS调试分析