你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】RMW(Read-Modify-Write)对 STM32F7xx内核运行速度的影响

[复制链接]
STMCU小助手 发布时间:2022-2-26 16:17
前言
在客户使用 STM32F7xx(Cortex-M7 内核)实际测试中,会发现同等主频下 STM32F4xx(Cortex-M4)执行同样一段简单程序在时间上要快于 STM32F7xx,这个会影响到客户切换到 STM32F7xx 的信心,也对 ST 以及 ARM 宣传上 Cortex-M7 内核执行时间远快于 Cortex-M4 内核的说法提出质疑,本文将针对具体案例说明这一情况的产生以及解决办法。


问题描述
客户测试复杂程序运行时间,比如同样 180MHz 主频下,STM32F7xx 执行 Coremark 测试程序时间远小于 STM32F4xx 的执行时间;也就是 STM32F7xx 的性能更佳,运算执行效率更好。但当客户程序顺序执行程序,尤其是简单程序时发现STM32F7xx 执行时间大于 STM32F4xx 的执行时间,比如运行下面的同样的测试代码,就有明显差距:
  1. volatile uint16_t i;
  2. static volatile uint16_t j = 0;
  3. i = 0;
  4. while(i<300)
  5. {
  6. i++;
  7. }
  8. if(j < 100)
  9. {
  10. j ++;
  11. }
  12. else
  13. {
  14. j = 0;
  15. }
复制代码
为方便量化时间,使用 Timer2 计数方式对这段时间进行计数,Timer2 运行在 90MHz,向上计数,Test_Counter 数据用于输出计数数值,增加后代码如下:

  1. volatile uint16_t i;
  2. static volatile uint16_t j = 0;
  3. TIM2->CNT = 0;
  4. __HAL_TIM_ENABLE(&htim2);
  5. i = 0;
  6. while(i<300)
  7. {
  8. i++;
  9. }
  10. if(j < 100)
  11. {
  12. j ++;
  13. }
  14. else
  15. {
  16. j = 0;
  17. }
  18. __HAL_TIM_DISABLE(&htim2);
  19. Test_Counter = __HAL_TIM_GET_COUNTER(&htim2);
  20. 通过上面的修改后测试下来,Test_Counter 数据分别为:
复制代码


通过上面的修改后测试下来,Test_Counter 数据分别为:
STM32F446 数据为 1543
STM32F746 数据为 1836
如果使用 Keil 自带的 States cycles 计算方法得到如下数据,后面会按照这个来计算执行时间数据。
STM32F446 数据为 3009
STM32F746 数据为 3635




产生上述问题的原因:
上面的测试都是在使用了 Cache 以及 ART 加速方法测得,如果针对 STM32F7xx 的性能优化可以参考 AN4667 "STM32F7 Series system architecture and performance"这篇应用文档的描述,本例已经对文档描述部分做过优化,但问题依然是STM32F7xx 速度慢于 STM32F4xx。两颗芯片运行同样代码,比较两颗芯片汇编代码也是相同的:

  1. LDRH r2,[sp,#0x00]
  2. ADDS r2,r2,#1
  3. STRH r2,[sp,#0x00]
  4. LDRH r2,[sp,#0x00]
  5. CMP r2,r3
  6. BCC 0x00000128
复制代码


通过查看 ARM Cortex-M7 内核文档发现下面描述:

WYR6GPVK496P{@B9Y03$ZXY.png

反映到本例中发现定义的 i 数据为 16-bit 数据,同样也在汇编代码上发现了 STRB 这个汇编代码;这样在 RMW(readmodify-write机制下,当定义为 byte 以及 half-word 数据时将有一个先读取数据,修改后再写入数据的过程,这个读取-修改-写入的过程正是能够影响到内核执行效率的问题点,如果定义为 32-bit 就避免了这个问题的发生。



问题解决
按照文档说明,我们将 16-bit 定义数据,改为 32-bit 的定义数据,即

  1. volatile uint32_t i;
  2. static volatile uint16_t j = 0;
复制代码
生成的汇编代码如下
  1. LDR r0,[sp,#0x00]
  2. ADDS r0,r0,#1
  3. STR r0,[sp,#0x00]
  4. CMP r0,r1
  5. BCC 0x08001F28
复制代码
测试下来结果如下:
STM32F446 数据为 2102
STM32F746 数据为 1807
可以看到不管是 STM32F4xx 还是 STM32F7xx,当数据定义为 32-bit 时都有显著的速度提升,当然 STM32F7xx 的提升更加明显,同样测试条件下 STM32F7xx 执行时间小于 STM32F4xx 的执行时间。


深入内核修改
因为 32-bit 数据定义会增加内存,并且有时候定义为 byte 或 halfword 更方便,还需要提升速度的话我们看到同样是内核文件给出的说明,可以将 RMW 机制屏蔽掉:


QPE2}_OJ$`PR)`86P~)H[~K.png

实际上就是对 CM7_ITCMCR 寄存器的第 1 位写 0, 即可以在程序中有下面的操作:
  1. __IO uint32_t * DTCM_CR = (uint32_t*)(0xE000EF94);
  2. * DTCM_CR &= 0xFFFFFFFD; /* Disable read-modify-write */
复制代码

禁止 RMW 后测试下来数据如下:
16-bit 定义数据 STM32F746 测试 cycles 数据为 3022
32-bit 定义数据 STM32F746 测试 cycles 数据为 1808
可以对比上面的测试数据也可以看到当禁止 RMW 后 STM32F7xx 性能也是优于 STM32F4xx 的。
具体测试数据如下:



结论:
需要提升 STM32F7xx 执行时间,发挥出最大效能时,请参考 AN4667,同时需要注意 RMW 对内核性能发挥的影响















收藏 评论0 发布时间:2022-2-26 16:17

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版