完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
完整教程下载地址:http://forum.armfly.com/forum.php?mod=viewthread&tid=86980
第8章 STM32H7的终极调试组件Event Recorder 本章节为大家介绍终极调试方案Event Recoder,之所以叫终极解决方案,是因为所有Link通吃,支持时间测量,功耗测量,printf打印,RTX5及其所有中间件调试信息展示。 8.1 重要提示(必读) 8.2 Event Recorder简介 8.3 创建工程模板和注意事项 8.4 Event Recorder事件记录的实现 8.5 Event Recoder 实现printf重定向 8.6 Event Statistics 时间测量功能的实现 8.7 Event Statistics 功耗测量功能的实现 8.8 Event Recoder对RTX5及其所有中间件的支持 8.9 JLINK配置说明 8.10 STLINK配置说明 8.11 CMSIS-DAP配置说明 8.12 ULINK配置说明 8.13 配套例子 8.14 总结 8.1 重要提示(必读)
前面的专题教程中为大家讲解了使用SEGGER的RTT功能来替代串口打印,比较方便。只是这种方法限制用户必须使用JLINK才可以。而使用Event Recorder的话,无此限制,各种LINK通吃。只要是MDK支持的即可。 Event Recorder是MDK在5.22版本的时增加的功能,到了5.25版本后,这个功能就更加完善了,增加了时间测量和功耗测量的功能。 此调试组件不需要用到SWO引脚,使用标准的下载接口即可。以我们的开发板为例,用到VCC,GND,SWDIO,SWCLK和NRST。大家使用三线JLINK-OB也是没问题的,仅需用到GND,SWDIO和SWCLK。
Event Recorder的特色主要有以下几点:
首先来看下面这张图: 在截图的左下角有个Memory内存区,在这个内存区里面有一个缓冲Event Buffer,其实就是一个大数组。MDK通过访问这个数组实现消息的图形化展示。为了正确的图形化展示,数组缓冲里面的数据就得有一定的数据格式。而这个数据格式就是通过左侧截图里面的Event Recorder和Event Filter来实现的。Event Recorder的API实现数据记录和整理,Event Filter的API实现数据的筛选,从而可以选择哪些数据可以在MDK的Event Recorder调试组件里面展示出来。 这就是Event Recorder的基本工作流程。 8.2.3 Event Statistics时间测量功能 Event Statistics提供的时间测量功能简单易用,在测试代码前后加上测量函数即可: 在本章教程程的8.6小节为大家详细进行了讲解。通过这个时间测量功能,用户可以方便测试代码的执行时间,从而根据需要,进行合理的优化,提高代码执行效率。 8.2.4 Event Statistics功耗测量功能 Event Statistics提供的功耗测量功能,当前只有KEIL的ULINKplus支持此功能,由于ULINKplus价格不便宜,一套5000多,大家作为了解即可,实际效果如下: 8.2.5 Event Recorder的实现原理 每条Event Recorder消息是由16字节的数据组成,32位的ID,32位的时间戳,两个32位的数据,共计16个字节。其中32位ID最重要,格式如下: Level指定消息分类,主要用于消息筛选: Component number指定事件消息所属的软件组件,也可用于过滤: 看了下Event Recorder的源码,每条消息大体是一样的: typedef struct { uint32_t ts; // Timestamp (32-bit, Toggle bit instead of MSB) uint32_t val1; // Value 1 (32-bit, Toggle bit instead of MSB) uint32_t val2; // Value 2 (32-bit, Toggle bit instead of MSB) uint32_t info; // Record Information // [ 7.. 0]: Message ID (8-bit) // [15.. 8]: Component ID (8-bit) // [18..16]: Data Length (1..8) / Event Context // [19]: IRQ Flag // [23..20]: Sequence Number // [24]: First Record // [25]: Last Record // [26]: Locked Record // [27]: Valid Record // [28]: Timestamp MSB // [29]: Value 1 MSB // [30]: Value 2 MSB // [31]: Toggle bit} EventRecord_t; 其中参数成员info最重要,也就是前面说的32位ID,这里的说明与前面的说明稍有不同。这里是经过处理后,实际存储到Event Recorder缓冲里面的数据。 对于Event Recorder,大家了解了这些知识点基本就够用了。 8.3 创建工程模板和注意事项 Event Recorder工程的创建比较简单,这里分步为大家做个介绍。 第1步:准备好一个使用MDK5.25或以上版本创建的工程模板。 第2步:安装ARM_Compiler V1.4.0或以上版本(如果有最新版,直接安装最新的),详情见帖子: http://forum.armfly.com/forum.php?mod=viewthread&tid=87175 。 第3步:打开MDK5.25或以上版本创建的RTE环境。 第4步:通过RTE环境,为工程添加Event Recorder功能。 第5步:为了实现printf重定向,我们需要将STDOUT的输出方式改为Event Recorder,即选项里面的EVR。 第6步:打开通过RTE环境为工程添加的文件EventRecorderConf.h,配置如下: 这里主要设置方框里面的两个参数。 Number of Records:表示Event Recorder缓冲可以记录的消息条数。 Time Stamp Source:表示时间戳来源,有如下四种可以选择,我们这里使用DWT时钟周期计数器。 由于选择的是DWT,因此EventRecorderCong.h文件中的Systick Configuration配置就不用管了。 ========================== 通过上面的6步就完成了Event Recorder功能的添加,效果如下: 添加完成后,还有非常重要的两点要特别注意:
下载并导入到MDK后,需要大家更新自己现有工程CMSIS文件里面的头文件,可以直接将CMSIS文件夹中Include文件里面的所有文件全部删掉,替换为MDK安装目录如下路径里面的所有头文件: ARMPACKARMCMSIS5.4.0CMSISInclude。保证头文件都是最新的5.4.0版本。
注意这两点后,就可以使用Event Recorder的功能了。 8.4 Event Recorder事件记录的实现 Event Recorder的使用也比较省事,这里也分步为大家进行说明: 第1步:初始化,仅需添加如下两行代码即可。 /* 初始化EventRecorder并开启 */EventRecorderInitialize(EventRecordAll, 1U);EventRecorderStart(); 第2步:调用Event Recorder的API就可以使用了,主要有以下三个API: EventRecord2:可以发送两个32位数据。 EventRecord4:可以发送四个32位数据。 EventRecordData:可以发送字符串。 显然这三个函数没有printf使用方便,所以对于这三个函数,大家做个简单的了解即可。教程配套例子里面有调用到这三个函数,可以操作熟悉下。这三个API的说明是在对应的help文档中,即MDK安装目录路径:/ARM/PACK/Keil/ARM_Compiler/1.6.0/Doc/General/html/index.html。 第3步:进入调试状态,选上周期更新: 点击全速运行: 然后将Event Recorder调试组件展示出来: 效果如下: 另外,这里有个知识点需要大家了解下,如果程序里面也调用了Event Statistics时间测量函数,那么也会在这个界面里面展示消息的,如何才能仅展示大家想看的功能呢?这就需要用到Event Recorder支持的筛选功能。使用这个功能需要大家先暂停全速运行,然后点击下面这个选项: 弹出的界面里面可以设置哪些选项显示,哪些选项不显示(勾上表示显示),我们这里取消Event Statistics的显示,设置完毕后记得点击OK按钮。 这就不展示Event Statistics的内容了。再次启动全速运行前,下面这个选项的对勾别忘了勾上。 8.5 Event Recorder实现printf重定向 实现printf输出需要用到MDK调试组件中的Debug(printf) Viewer,输出效果就跟大家使用串口调试软件一样,可以输出中文和英文。 MDK的printf调试组件使用方法跟本章8.4小节中的说明一样,点击调试,选中周期运行,然后显示Debug(printf) Viewer调试组件: 效果如下: 另外,还有一个知识点需要给大家做个补充,使用SWD接口的SWO引脚也是可以做串口打印的,并且也是通过这个调试组件Debug(printf) Viewer进行输出。只是这种方式的性能没有Event Viewer强,而且要多占用一个SWO引脚。 关于SWO输出方式可以看此贴:http://forum.armfly.com/forum.php?mod=viewthread&tid=526 。 8.6 Event Statistics 时间测量功能的实现 时间测量功能简单易用,仅需一个起始函数,一个停止函数即可。当前支持4组,每组支持16路测量,也就是可以同时测量64路。 时间测量的API函数支持多任务和中断里面随意调用。 1、 测量起始函数:EventStartG (slot) 或者EventStartGv (slot, val1, val2)
这里也分步为大家说明Event Statistics时间测量功能的使用方法。 第1步:初始化,仅需添加如下两行代码即可。 /* 初始化EventRecorder并开启 */EventRecorderInitialize(EventRecordAll, 1U);EventRecorderStart(); 第2步:在要测量的代码前后加上起始和结束时间。 EventStartA(0);测量的代码部分EventStopA(0); 这里是用分组A的测量通道0。 第3步:跟本章8.4小节讲解的一样,点击调试,选择周期更新选项,然后全速运行。 第4步:全速运行后,显示Event Statistics调试组件。 比如我这里简单的测试了一个5ms的延迟函数,效果如下(测量时间是动态更新的): 另外要注意一点,微秒的时间单位us可能无法正常显示,这个是没有关系的: 8.7 Event Statistics 功耗测量功能的实现 当前仅KEIL自家的ULINKplus支持功耗测量功能,这款下载器不便宜,一套5000多,大家有个了解即可,我们这里就不做讲解了。 8.8 Event Recorder对RTX5及其所有中间件的支持 后面做RTX5及其所有中间件的教程时会为大家做讲解,这里让大家看下效果:
8.9 JLINK配置说明 为了帮助大家更好的使用JLINK,这里将JLINK配置中关键的几个地方做个说明。
注:如果大家调试状态弹出SWD配置时钟超出范围的问题,可以考虑将上面截图中的Enable选项的对勾取消掉即可,但内核时钟一定要修改为芯片的主频。 另外,进入调试状态后,右下角的时间是否正常更新都没有关系:
8.10 STLINK配置说明 为了帮助大家更好的使用STLINK,这里将STLINK配置中关键的几个地方做个说明。
另外注意,进入调试状态后,右下角的时间是否正常更新都没有关系:
8.11 CMSIS-DAP配置说明 为了帮助大家更好的使用CMSIS-DAP,这里将CMSIS-DAP配置中关键的几个地方做个说明。
另外注意,进入调试状态后,右下角的时间是否正常更新都没有关系:
8.12 ULINK配置说明 由于手头没有ULINK,这里就不做讲解了。如果大家需要相关配置,按照前面小节三款LINK的配置照葫芦画瓢搞一下即可,或者在MDK安装目录的路径ARMHlp下有对应的文档说明: 8.13 配套例子 本章节教程配套了如下例程,仅MDK版本。
具体代码实现也比较简单,以V6开发板为例,定义一个TIM6的中断,中断频率是500Hz,通过Event Statistics测量中断的执行频率。代码如下: #include "bsp.h"#include "EventRecorder.h" /* 定时器频率,500Hz */#define timerINTERRUPT_FREQUENCY 500 /* 中断优先级 */#define timerHIGHEST_PRIORITY 10 /*********************************************************************************************************** 函 数 名: vEventRecorderTest* 功能说明: 创建定时器* 形 参: 无* 返 回 值: 无**********************************************************************************************************/void vEventRecorderTest(void){ bsp_SetTIMforInt(TIM6, timerINTERRUPT_FREQUENCY, timerHIGHEST_PRIORITY, 0); EventStartB(0); } /*********************************************************************************************************** 函 数 名: TIM6_DAC_IRQHandler* 功能说明: TIM6中断服务程序。* 形 参: 无* 返 回 值: 无**********************************************************************************************************/void TIM6_DAC_IRQHandler( void ){ if((TIM6->SR & TIM_FLAG_UPDATE) != RESET) { EventStopB(0); EventStartB(0); /* 清除更新标志 */ TIM6->SR = ~ TIM_FLAG_UPDATE; }} 效果如下,测量的平均频率是1.98ms,与我们设计的500Hz基本符合: 应用程序的设计如下: #include "bsp.h" /* 底层硬件驱动 */#include "EventRecorder.h" /*********************************************************************************************************** 函数和变量**********************************************************************************************************/extern void vEventRecorderTest(void);uint8_t s_ucBuf[10] = "armfly"; /*********************************************************************************************************** 函 数 名: main* 功能说明: c程序入口* 形 参:无* 返 回 值: 错误代码(无需处理)**********************************************************************************************************/int main(void){ uint8_t ucKeyCode; /* 按键代码 */ uint32_t t0 = 0, t1 = 0, t2 = 0, t3 = 0, t4 = 0; /* 初始化EventRecorder并开启 */ EventRecorderInitialize(EventRecordAll, 1U); EventRecorderStart(); bsp_Init(); /* 硬件初始化 */ bsp_StartAutoTimer(0, 200); /* 启动1个200ms的自动重装的定时器 */ /* 测量中断周期 */ vEventRecorderTest(); /* 进入主程序循环体 */ while (1) { bsp_Idle(); /* 这个函数在bsp.c文件。用户可以修改这个函数实现CPU休眠和喂狗 */ /* 判断定时器超时时间 */ if (bsp_CheckTimer(0)) { EventStartA(0); EventStopA(0); EventStartA(1); bsp_DelayMS(5); EventStopA(1); EventStartA(2); bsp_DelayMS(30); EventStopA(2); t0++; EventStartAv(3, t0, t0); bsp_DelayMS(30); EventStopAv(3, t0, t0); } /* 按键滤波和检测由后台systick中断服务程序实现,我们只需要调用bsp_GetKey读取键值即可。 */ ucKeyCode = bsp_GetKey(); /* 读取键值, 无键按下时返回 KEY_NONE = 0 */ if (ucKeyCode != KEY_NONE) { switch (ucKeyCode) { case KEY_DOWN_K1: /* K1键按下 */ t1 += 1; t2 += 2; EventRecord2(1+EventLevelAPI, t1, t2); t3 += 3; t4 += 4; EventRecord4(2+EventLevelOp, t1, t2, t3, t4); EventRecordData(3+EventLevelOp, s_ucBuf, sizeof(s_ucBuf)); break; case KEY_DOWN_K2: /* K2键按下 */ printf("K2按键按下rn"); break; case KEY_DOWN_K3: /* K3键按下 */ printf("K3按键按下rn"); break; default: /* 其它的键值不处理 */ break; } } }} 应用程序里面主要实现了三个功能: 1、利用测量分组A实现4路时间的测量(第1路什么也没有测量,可以用来表示这两个函数本身执行占用的时间)。每100ms测量一次时间,效果如下: 2、利用函数EventRecord2,EventRecord4和EventRecordData发送消息事件。按下按键K1进行更新,效果如下: 3、基于Event Recorder的printf重定向。按下按键K2或者K3会打印消息,效果如下: 8.14 总结 Event Recoder还是非常实用的,建议大家多使用几次,熟练掌握。基本用上几次就上瘾,离不开了,的确是工程调试的利器。 转载于:https://www.cnblogs.com/armfly/p/10757582.html |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1627 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1550 浏览 1 评论
984 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
688 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1601 浏览 2 评论
1869浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
652浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
520浏览 3评论
539浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
508浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-25 05:08 , Processed in 0.862374 second(s), Total 79, Slave 62 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号