ARM架构怎样设计才能在指令执行性能上超越X86架构?
在不考虑功耗的情况下,同样时钟频率的ARM架构CPU的极限性能不如X86架构,是什么模块的瓶颈限制了ARM架构的性能?
今天给大家介绍的是在串口波特率识别实例里逐步展示i.MXRT上提升代码执行性能的十八般武艺。
此前恩智浦 MCU SE 团队一直在加班加点赶 SBL 项目(解决客户产品 OTA 需求),这个项目里集成了 ISP 本地升级(UART/USB)功能。其中 UART 口下载升级实现里加入了自动波特率识别支持,这一套 ISP 代码其实是移植于 i.MXRT Flashloader(更早期的时候叫 KBOOT)。
ISP 代码放在 SBL 工程里会出现高波特率(比如115200)无法识别的问题,但在低波特率的情况下(比如9600,19200),ISP 代码是功能正常的,说明代码本身并不存在逻辑缺陷,但高波特率下就异常了,大概率是遇到了代码执行性能瓶颈。今天就尝试在 i.MXRT 上使用各种方法去提升性能,以此解决这个高波特率无法识别问题。
一、SBL项目里ISP串口高波特率识别问题
SBL 项目是支持全系列 i.MXRT 平台的,为了具体化问题,我们就选取 i.MXRT1062 型号为例,官方配套 MIMXRT1060-EVK 板子上搭配了一颗四线串行 NOR Flash(芯成IS25WP064A)用于存放代码。
SBL 程序主体是 XIP 执行的,仅部分涉及 IAP 操作的代码被分散加载到了 RAM 里。SBL 中 ISP 功能代码主体当然也是 XIP 为主,且在 SBL 程序里是最先执行的(本地升级超时后才进入 SBL 主体),SBL 工程里跟串口波特率识别相关的源文件一共如下三个:
MIMXRT1060-EVK 板子上串口是 GPIO1[13:12],其中 RXD – GPIO1[13] 是核心的用于波特率识别的引脚,为了便于直观地感受代码执行性能,我们用另一个 GPIO1[12] 来辅助,将其配置为 GPIO 输出模式,初值为高电平,在 GPIO 中断处理函数里保持低电平来标示执行总时间:Note :下述代码里中断处理函数实际上有点小缺陷,《中断处理函数(IRQHandler)的标准流程》 一文里给出了改进方法,但这里为了观察中断处理代码是否能在下一次中断来临前执行完毕特意舍弃了文中 2.2.2 小节里的改进)
现在我们用示波器同时抓取 GPIO1[13:12] 信号,分别测试 9600 低波特率(下图一)和 115200 高波特率(下图二)下实际波形。
根据测量第一次 GPIO 中断处理执行时间大概是 32.8us(7 次中断因代码分支执行不同略有区别),这个时间对于 9600 波特率下单 bit 传输耗时约 104us 的情况来说是足够快的,但对于 115200 波特率下单 bit 传输耗时约 8.68us 的情况来说,就显得有点慢了(最小的下降沿之间间隔是 2bit 传输耗时 17.36us ),这也是 115200 无法被识别的原因,因为有 4 个下降沿中断被漏掉了。
Note: ISP 功能代码里配置的系统环境是:396MHz CPU 主频、不使能 L1 Cache、100MHz Flash 工作频率,普通 SPI 下 Fast Read Quad I/O SDR Non-Continuous 工作模式,并且使能了 FlexSPI 的 Prefetch 特性(AHB RX Buffer 为 1KB)。
文章下方附学习资源,自助领取。
3年嵌入式物联网学习资源整理分享:C语言、Linux开发、数据结构;软件开发,STM32单片机、ARM硬件开发、物联网通信开发、综合项目开发教程资料;笔试面试真题。点击下方插件免费领取↓↓↓点击领取
二、提升代码性能的多种方法
既然代码执行性能不够,那就努力提升性能,文章标题叫“十八般武艺”,这只是一种夸张说法,不过我确实收集了如下六种提升性能的方法,让我们一一尝试吧!
注意:下述结果都是叠加前面方法而得的(所有测试均是在 115200 波特率下进行)。
Level 1:提升CPU主频
ISP 功能代码里配置的 CPU 主频是 396MHz,实际上这是根据 BootROM 默认运行配置而来的,而 i.MXRT1062 是可以跑到 600MHz 主频的,将 SDK 代码里 armPllConfig_BOARD_BootClockRUN.loopDivider 由 66 调大到 100 即可。
CPU 主频提升后第一次 GPIO 中断处理执行时间从 32.8us 下降到了 32.2us,性能仅有微小提升,看来此时主要性能瓶颈不在 CPU 主频上,应该是 Flash 访问性能在拖后腿。
Level 2:提升Flash访问速度
SBL 工程里启动头 FDCB 配置的是 100MHz Flash 工作频率,但 MIMXRT1060-EVK 板载 Flash(芯成IS25WP064A)最大工作频率是 133MHz,所以我们可以提升 Flash 工作频率。
修改 qspiflash_config.memConfig.serialClkFreq 为 kFlexSpiSerialClk_133MHz 即可。不了解 FDCB 结构体工作机制的,可以查看这篇文章《从头开始认识i.MXRT启动头FDCB里的lookupTable》 。
Flash 工作频率提升后第一次 GPIO 中断处理执行时间从 32.2us 下降到了 27.8us,这次的性能提升算有点明显了,但是还是不够,解决不了问题。
Level 3:配置FlexSPI至最优模式
让我们继续从 Flash 传输模式上做文章,ISP 功能代码里配置的是普通 SPI 下 Fast Read Quad I/O SDR Non-Continuous 工作模式,这个模式已经算是非常高效的传输模式了,如果还想改进,要么是切换到 QPI 模式(将 CMD 子序列也从一线变到四线),要么是使能 Continuous Read(除了第一个 CMD 子序列,其后 CMD 子序列全部省掉)。
综合考虑,应该是使能 Continuous Read 性能提升更大一些,具体方法参考 《在i.MXRT启动头FDCB里使能串行NOR Flash的Continuous read模式》。
使能 Flash Continuous Read 后第一次 GPIO 中断处理执行时间从 27.8us 下降到了 27.4us,性能仅有微小提升,这应该跟我们使能了 FlexSPI prefetch 特性有关,1KB AHB RX Buffer 的存在导致 CMD 子序列在总传输时序中占比不明显。不过,有点收获的是漏掉的下降沿中断从 4 个减少到了 3 个。
Level 4:打开L1 Cache
对于 XIP 工程来说,不开 L1 I-Cache 加速性能是非常吃亏的一件事,i.MXRT1062 内部有 32KB I-Cache,不把这个 Cache 用起来简直是暴殄天物。虽然工程 SystemInit() 函数里会执行一次 SCB_EnableICache(),但这只是一个 Cache 总开关,要想 Cache 对 Flash 映射地址(0x60000000 之后)产生作用还得借助 BOARD_ConfigMPU() 函数来具体配置 MPU。
关于 Cache 对 Flash 读取的性能提升,可以参考 《实抓Flash信号波形来看i.MXRT的FlexSPI外设下AHB读访问情形(全加速)》 。
使能 Cache 后第一次 GPIO 中断处理执行时间从 27.4us 下降到了 19us,后面的 GPIO 中断执行耗时更是大大缩短(原因是中断处理函数相关代码在第一次中断触发执行时被顺便放到 Cache 里了),这时候 115200 高波特率已经能够被正常识别了。
到这里问题已经解决了,但我们还没有榨干 MCU 最后一滴血,优化继续。上图波形里第一次 GPIO 中断处理执行时间相比其后面的 6 次中断执行耗时要明显长,这还是有风险的,比如再高的波特率 256000 还是无法正常识别(至少第一次识别会失败,后面上位机再重复发暗号做第二次识别就可以了)。
为了让第一次 GPIO 中断处理时间也大大缩短,我们可以在系统初始化的时候故意调用一下这些中断处理相关函数,将这些代码事先装载到 I-Cache里。
将中断处理函数相关代码预装载到 I-Cache 后第一次 GPIO 中断处理执行时间从 19us 锐降到了 2.12us,跟其他中断处理执行差不多的耗时,现在即使是 256000 高波特率也能一次识别成功。
Level 5:拷贝到TCM里
靠 Cache 这种无法精准控制的优化策略始终让我们无法放心,还是将中断处理相关代码直接放到 TCM 里更可靠,我们在工程链接文件(MIMXRT1062xxxxx_flexspi_nor.icf)里做如下修改将第一节里列出了三个源文件全部弄到 RAM 区里执行(对于 XIP 工程来说,RAM 区是 DTCM, 当然对于代码来说 ITCM 效率要更高,不过 DTCM 也够用了)。
将中断处理函数相关代码重定位到 DTCM 执行后第一次 GPIO 中断处理执行时间从 2.12us 再降到了 520ns,这下 1M 超高波特率也能被识别了。
Level 6:指定函数地址以八字节对齐
性能提升结束了吗?不,还有一招,参见 《链接函数到8字节对齐地址或可进一步提升i.MXRT1xxx内核执行性能》 一文,将中断处理相关函数全部链接到八字节对齐地址还可以再利用 Cortex-M7 内核指令双发射特性。
我们查看下工程映射文件(sbl.map),三个相关函数仅有计时函数 microseconds_get_ticks() 被自动分配到了八字节对齐的地址,其他两个函数不是,所以还有提升空间。
将非八字节地址对齐的中断处理相关函数调整到八字节地址对齐后(具体方法这里就不展开介绍了),第一次 GPIO 中断处理执行时间从 520ns 降到了 480ns,这几乎是性能极限了。
至此,在串口波特率识别实例里逐步展示i.MXRT上提升代码执行性能的十八般武艺,便介绍完毕了,掌声在哪里
原文链接:https://mp.weixin.sigusoft.com/s/hd9hPFovDqPHaVu9k9hG2Q转载自:嵌入式微处理器原文链接:提升MCU代码执行性能的十八般武艺
本文来源网络,免费传达知识,版权归原作者所有。如涉及作品版权问题,请联系我进行删除。
2024最新激活全家桶教程,稳定运行到2099年,请移步至置顶文章:https://sigusoft.com/99576.html
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。 文章由激活谷谷主-小谷整理,转载请注明出处:https://sigusoft.com/94516.html