打印
[资源分享]

【杰发科技AC7802x测评】3 Cortex-M 系统专用的性能计数器

[复制链接]
433|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 6552918 于 2023-7-2 08:28 编辑

[url=home.php?mod=space&uid=760190]@21小跑堂 #申请原创#[/url] #技术资源#

在ARM内核的程序中实际使用中会用到各种延时程序,实现延时的方式也有很多种,有人会直接用软件方法堆积NOP()来实现,这种方**收到主频和编译器的优化影响,经常会出现不稳定情况。有人会用硬件定时器来实现,这种方法可以有效规避编译器优化的影响,但这种方法的移植性不好,换芯片可能就要重新调试。还有一种小众的用法是使用DWT来实现,但这是一种系统外设,专门用来为Cortex-M3及其以上芯片提供调试和追踪的硬件辅助功能,但在Cortex-M0/m0+上是没有的,也限制的使用条件。综合来看使用systick是比较理想的选择,但systick也有被OS占用的场景。
难道就无解了吗?NO! 现在为大家分享一种依赖systick但又不影响systick,还能实现各种延时的库---perf_counter(Cortex-M 系统专用的性能计数器)。它与用户原有的SysTick功能共享SysTick,且不干扰用户原有的SysTick功能。该库将带来新的功能,例如time.h中定义的性能计数器、delay_us和clock()服务
源码地址如下:
https://github.com/GorgonMeducer/perf_counter

但因为github在国内访问,基本就没稳定的时候,所有我擦用gitee导入的方式下载源码


导入成功后就可在gitee上看到perf_counter的内容了

然后再进行源码下载就不会有问题了


解压后的源码包内容如下

今天为大家介绍的使用方法是CMSIS-Pack方式,可以在MDK环境中实现傻瓜式的部署
相关文件路径和安装方法如下:



为什么要用CMSIS-Pack方式呢,因为AC7802X的库也都是采用的CMSIS-Pack方式提供了,为了统一配置方式,就介绍CMSIS-Pack方式。

在AC7802X的库中提供了由systick实现的各种常用延时函数,但这些延时函数都是采用systick阻塞式的延时,在并不适合systick被用于其它应用的场景,下面我们来使用perf_counter替换相关的延时函数,解决限制应用的问题。

具体操作如下,打开RTE配置窗口:
在列表的末端出现了一个Utilities条目,依次展开后勾选perf_counter—Core—Variant项选择Library,系统会选择以库的形式来实现模块的部署

单击OK按钮后,我们会发现Utilities已经被加入到了工程管理器中,而perf_counter.lib也已经成功的部署到了目标工程中:

因为厂家例程默认使用的是AC5编译器

应该同时勾选C99 Mode和GNU extensions两个选项

如果是用AC6,需要打开对GNU扩展和C99(极其以上)语言标准的支持,具体方法如下图所示:在Language C标准下拉列表中选择带有gnu前缀的选项——如果没有什么特别的顾虑,推荐直接拉满——使用gnu11即可。


在使用perf_counter的C语言源文件中,我们需要首先加入对头文件的引用:
需要注意的是,通过RTE方式部署的perf_counter并不会在工程管理器中引入 perf_counter.h 以供用户查看。想要查看perf_counter.h查找可用API的小伙伴,可以“简单的”在上述代码行上单击右键,从弹出菜单中选择“Open document 'perf_counter'” 来实现对头文件的访问。


perf_counter.h 内展示了所有perf_counter内实现的功能函数

在使用前需要添加perf_counter初始化函数,这里需要注意传递的参数,如果自己的程序已经使用systick,如果已经使用需要传参为ture,如果没有使用需要传参fales

编译后
用户自己的应用里完全没有使用SysTick。此时,在编译时,我们多半会看到类似如下的错误提示:

对于这种情况,我们需要在任意的C文件中添加一个SysTick中断处理程序:

添加完,错误报告就会消失。

需要特别注意的是:由于用户并没有自己初始化 SysTick,因此我们需要将这一情况告知 perf_counter 库——由它来完成对 SysTick 的初始化——这里传递 false 给函数 init_cycle_counter() 就是这个功能。如果由perf_counter 库自己来初始化SysTick,它会为了自己功能更可靠将 SysTick的溢出值(LOAD寄存器)设置为最大值(0x00FFFFFF)。
用户自己的应用里使用了SysTick,拥有自己的初始化过程。对于这种情况,我们需要确保一件事情:即,SysTick的CTRL寄存器的 BIT2(SysTick_CTRL_CLKSOURCE_Msk)是否被置位了——如果其值是1,说明SysTick使用了跟CPU一样的工作频率,那么SysTick的测量结果就是CPU的周期数;如果其值是0,说明SysTick使用了来自于别处的时钟源,这个时钟源具体频率是多少就只能看芯片手册了(比如STM32就喜欢将系统频率做 1/8 分频后提供给SysTick作为时钟源),此时SysTick测量出来的结果就不是CPU的周期数。
在确保了 CTRL 寄存器的 BIT2 被正确置位,并且SysTick中断被使能(置位 BIT1,SysTick_CTRL_TICKINT_Msk )后,我们可以简单的通过 init_cycle_counter() 函数告诉perf_counter模块:SysTick 被用户占用了——这里传递 true 就实现这一功能。
关于Library的匹配问题
perf_counter.lib 库在编译的时候,开启了 Short enums/wchar(分别对应命令行的 -fshort-enums -fshort-wchar)。这么做其实没什么特别的原因,但如果你的工程使用了不同的配置,例如:
下图的工程配置中,没有勾选 "Short enums/wchar"


解决方发是,在工程配置中勾选上这一选项


至此,perf_counter的部署工作就完成了,可以使用相关的API进行操作了。
微秒级阻塞延时
perf_counter提供了一个us级阻塞延时函数 delay_us(),它的函数原型如下:
externvoiddelay_us(int32_t iUs);
实际上,由于函数调用的开销,delay_us在时间判断上会存在一个“不积累”的误差——根据优化等级的不同,其具体CPU周期数存在差异,如果我们以Library方式进行部署时,这一误差大约在+/-25个CPU周期左右——这一信息实际上告诉我们:
在使用Library的情况下,当你的CPU频率超过50MHz时,delay_us() 可以提供最小<1us的延时误差;
当你的系统频率不满足上述条件时,以系统频率 12MHz为参考,则可以认为delay_us误差为不积累的 +/- 2us。
接下来我们看一下延时效果如何,
先看看us延时


再看看ms延时


这些延时函数都是perf_counter的最基本函数,perf_counter还有能多高级**,比如 查看程序运行的多少个机器周期等,下面是以查看10ms延时的机器周期为例

本帖只是个入门贴,还有很多高级功能需要大家自己去研究和使用。
perf_counter源码包: perf_counter-CMSIS-Pack.zip (2.38 MB)

使用特权

评论回复

相关帖子

发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

认证:北京汇冠触摸技术有限公司/电子工程师
简介:电子工程师,嵌入式应用爱好者。

102

主题

1235

帖子

6

粉丝