感谢硬汉哥做的ThreadX和GUIX的工程,这周末心血来潮研究了一下TraceX的使用方法,ThreadX事件跟踪功能主要设计为事后分析工具,用于分析应用程序中的最后“ n”个活动。通过此信息,开发人员可以发现问题和/或优化的潜在目标。本次教程使用的是硬汉哥提供的:V6-2002_ThreadX +GUIX 的RGB565格式模板(支持MDK,IAR和GCC )
首先贴上官方教程的地址:
https://docs.microsoft.com/en-us/azure/rtos/tracex/chapter5
主要看第5章:如何生成事件跟踪缓冲区和附录D:转存跟踪缓冲区的数据
现在说下流程:
第一步:定义使能 TX_ENABLE_EVENT_TRACE,只有使能了它才能编译trace相关的代码,我将其放在了tx_port.h文件中,如图所示:
使能代码的下方代码为trace功能所用的时间戳标记,不同的芯片可能会不同,此处未做修改。
第二步:定义缓存区的名称、内存大小、要保留在跟踪注册表中的应用程序ThreadX对象的数量:main.c中将其定义未全局变量
/* Tracex使用 */
#define TRC_BUF_SIZE (500*32) /* Buffer size 500 events */
#define TRC_MAX_OBJ_COUNT (40) /* Max number of ThreadX objects */
UCHAR myBuf[TRC_BUF_SIZE];
第三步:调用tx_trace_enable函数启用ThreadX内部的事件跟踪。
不知道论坛有没有使用过Tracealyzer的朋友,Tracealyzer应该也是和TracecX这个软件有点关联的,Tracealyzer在Freertos中使用时只要在port文件中使能后,在程序运行内核代码前开启跟踪就可以了
我刚开始使用tx_trace_enable这个函数的时候就有了先入为主的观念,将其调用在 tx_kernel_enter(); /* 进入ThreadX内核 */ 这段代码前面一直监测不到数据,摸索了几个小时才发现,这个函数只需要放在任一个ThreadX的任务中循环调用就行了。
贴上代码:
UINT status;
status = tx_trace_enable(&myBuf, TRC_BUF_SIZE, TRC_MAX_OBJ_COUNT); //Tracex
定义变量status的目的是为了查看tx_trace_enable()是否调用成功,status的返回值如下:
TX_SUCCESS(0x00)成功的事件跟踪启用。
TX_SIZE_ERROR(0x05)指定的跟踪缓冲区大小太小。它必须足够大以容纳跟踪头,对象注册表和至少一个跟踪条目。
TX_NOT_DONE(0x20)事件跟踪已启用。
TX_FEATURE_NOT_ENABLED(0xFF)系统未在启用跟踪的情况下进行编译。
大家在线调试的时候可以单步跟进去看看运行过程。上图演示了在AppTaskStart()任务中调用tx_trace_enable()函数,我自己在测试时分别在AppTaskMsgPro()和AppTaskUserIF()任务中都单独调用过并查看跟踪缓冲区地址,发现数据基本一致,所以最后我将其放在了AppTaskStart()中,因为这个函数的运行间隔是ms级别的,当然了TraceX监测出来的结果也是ms级别的,但是看官方demo的时候,他们的监测结果有us级别的,所以后期我会根据情况适当改进这个函数的调用。
第四步:将保存到缓存区myBuf[TRC_BUF_SIZE]中的数据保存为bin、hex、trx中的一种即可加载到TraceX中查看。
强调一点:ThreadX事件跟踪功能主要设计为事后分析工具,所以不像systemview和uc-probe那样可以在线以stream流方式实时查看数据、内存、程序运行状态等等,只能先运行一段时间以后停止,然后再从缓存区保存数据出来进行分析。
1.IAR保存缓存区数据的方法:有两种一种手动,一种通过宏的方式自动保存
1.1先说手动保存数据:
首先下载程序并在线调试,断点单步跟进去查看status的返回值是否为0x00(succuss);
对了,首次运行成功会返回0x00,再次运行这个函数的话会返回0x20(跟踪已启用);如果返回0x00是的话去掉断点然后全速运行,运行一段时间以后暂停,打开View——memory——memory1(或2、3、4均可)窗口,
在go to一栏填入&myBuf[0]找到缓存区首地址,然后在首地址42上右键——memory save——打开存储窗口,
首地址已经自动填写好,末尾地址咱们需要根据实际情况算,刚才定义的时候myBuf的空间大小为500*32,转换为十六进制加在首地址上:0x20000a34 + 3E80 = 0x200048B4;
填入末尾地址,然后设置一下存储地址及后缀名,hex、trx、bin均可,最后点击保存,下方debug long栏出现保存成功即可,接下来打开TraceX软件,打开刚才保存的缓存区的数据即可分析查看。
1.2通过宏文件自动保存数据
新建一个宏文件保存为.mac格式并添加到工程中来(我的是save_trace_buffer.mac),在宏文件中添加如下内容并保存:
__var start;
__var end;
save_trace_buffer()
{
start = __smessage "Memory:0x",&myBuf:%x;
end = __smessage "Memory:0x",(myBuf + sizeof(myBuf)-1):%x;
__memorySave(start,end,"intel-extended", "$PROJ_DIR$\\trace.trx");
return 0;
}
然后在工程名上右键——options——debugger,勾选使用宏文件,选中刚才的宏最后点确定。
回到工程中下载程序重复之前操作1.1动作暂停仿真后,工具栏上点击View——Macros——Debugger Macros,打开Debugger Macros窗口,向下拉找到刚才宏文件的动作函数save_trace_buffer(),右键该函数选择添加到quicklaunch窗口,在quicklaunch窗口中,蓝色的是人为添加的用户宏
当需要保存当前的数据到缓存区时。暂停程序的运行并双击蓝色的按钮即可,如果保存成功,此时debug log窗口中会显示信息
此时数据就保存到了工程文件夹下,将其添加到TraceX中进行查看,贴上一张两种保存方式的对比图:
至此,IAR的已经完毕,其实可以更智能点,通过TOOL工具将TraceX添加为插件并添加表达式,再更改程序让缓存区里面的数据实时更新,达到一种伪stream流的状态,就可以变事后分析为实时分析,岂不快哉,此处有兴趣的可以试试,我后面有空弄好以后再开帖子讲述这种方法。
2.SES和keil保存缓存区数据的方法
这里就不再讲述程序修改这些了,开门见山,debug到程序运行一段时间并暂停以后:
SES:打开View——memory——memory1窗口,Address处填入&myBuf[0],size处根据之前申请的,填入 500 * 32 = 16000,回车后就只会单独显示myBuf里面的数据了,然后选择所有数据右键保存数据或保存选择的数据,格式为二进制文件或者intel-hex格式,设置文件名保存。
Keil:同理,打开memory1,填入&myBuf[0],可以右键选择保存,或者在command窗口使用save命令行保存,格式为 SAVE filepath startAddr, endAddr
示例:save C:\Users\Administrator\Desktop\V6-2002_ThreadX\Project\MDK-ARM(AC6)\memory.trx 0x20000a34,0x200048B4 (此处地址是会变的,大家根据实际情况,填好起始地址即可)
当然,SES和Keil也可以用添加插件和宏等骚操作来保存缓存区地址,可我不怎么会,论坛的朋友们可以自己试一试。
从源码来看TraceX还有一些其他的API供选择调用:
tx_trace_enable:启用事件跟踪 tx_trace_event_filter:过滤指定的事件 tx_trace_event_unfilter:取消过滤指定的事件 tx_trace_disable:禁用事件跟踪 tx_trace_isr_enter_insert:插入ISR输入跟踪事件 tx_trace_isr_exit_insert:插入ISR退出跟踪事件 tx_trace_buffer_full_notify:注册跟踪缓冲区完整的应用程序回调 tx_trace_user_event_insert:插入用户事件 大家最好能实际动手试一试,也欢迎大家踊跃发言,集思广益来互相进步,好了,今天就到这里,最后再说一句,编译一次真的久,做完这个教程后,整个文件夹大小为8G多……头大!!!
V6-2002_ThreadX_TraceX.rar
(5.51 MB, 下载次数: 169)
|