11565|4

1381

帖子

2

TA的资源

五彩晶圆(初级)

楼主
 

小议ARM Cortex-m0/m4系列的总线差异 [复制链接]

从一个简单问题说起:STM32的GPIO翻转速度(比如用来模拟时序)最快能多快?
写段代码测试一下:
  1. void test(void)
  2. {
  3.         for(;;)
  4.         {
  5.                    GPIOA->ODR = (1<<5);
  6.                    GPIOA->ODR = 0;
  7.                    GPIOA->ODR = (1<<5);
  8.                    GPIOA->ODR = 0;
  9.                    GPIOA->ODR = (1<<5);
  10.                    GPIOA->ODR = 0;
  11.                    GPIOA->ODR = (1<<5);
  12.                    GPIOA->ODR = 0;
  13.                    GPIOA->ODR = (1<<5);
  14.                    GPIOA->ODR = 0;
  15.                    GPIOA->ODR = (1<<5);
  16.                    GPIOA->ODR = 0;
  17.                    GPIOA->ODR = (1<<5);
  18.                    GPIOA->ODR = 0;
  19.                    GPIOA->ODR = (1<<5);
  20.                    GPIOA->ODR = 0;
  21.                    GPIOA->ODR = (1<<5);
  22.                    GPIOA->ODR = 0;
  23.                    GPIOA->ODR = (1<<5);
  24.                    GPIOA->ODR = 0;
  25.                    GPIOA->ODR = (1<<5);
  26.                    GPIOA->ODR = 0;
  27.                    GPIOA->ODR = (1<<5);
  28.                    GPIOA->ODR = 0;
  29.                    GPIOA->ODR = (1<<5);
  30.                    GPIOA->ODR = 0;
  31.                    GPIOA->ODR = (1<<5);
  32.                    GPIOA->ODR = 0;
  33.                    GPIOA->ODR = (1<<5);
  34.                    GPIOA->ODR = 0;
  35.                    GPIOA->ODR = (1<<5);
  36.                    GPIOA->ODR = 0;
  37.                    GPIOA->ODR = (1<<5);
  38.                    GPIOA->ODR = 0;
  39.                    GPIOA->ODR = (1<<5);
  40.                    GPIOA->ODR = 0;
  41.                    GPIOA->ODR = (1<<5);
  42.                    GPIOA->ODR = 0;
  43.                    GPIOA->ODR = (1<<5);
  44.                    GPIOA->ODR = 0;
  45.         }
  46. }
复制代码

这段代码作用是让 PA5 在高低状态来回翻转,连续20次之后会有一次跳转间隔一下。经过编译器优化处理,变成了一连串的 STR 指令:
......
100001c0:       6159            str     r1, [r3, #20]
100001c2:       615a            str     r2, [r3, #20]
100001c4:       6159            str     r1, [r3, #20]
100001c6:       615a            str     r2, [r3, #20]
100001c8:       6159            str     r1, [r3, #20]
100001ca:       615a            str     r2, [r3, #20]
100001cc:       6159            str     r1, [r3, #20]
......

这样子的,向同一个内存地址(GPIO ODR寄存器的地址)交替写不同的两个值,引起I/O口电平的变化。

如果每条 STR 指令的执行只需要1个机器周期的话(这是最理想的情况),以上程序可以让GPIO输出一半系统时钟频率的方波。实际上是否每条 STR 指令时间是1个机器周期

我曾经在玩8位的AVR的时候,用汇编写过一个ISP下载器的程序,模拟时序也用到了。我到现在也记得清楚,AVR手册上写明了,OUT 指令写I/O空间寄存器是1个机器周期,ST 指令写寄存器或者SRAM要2个机器周期。ARM 的情况呢?我不记得手册上有没有指令周期数的描述,不过可以先测试一下。
为了示波器测量方便,我先把系统时钟频率降到 200kHz. 然后……

这个很不错,除了连续20个脉冲之后因为有跳转指令多停顿了一下之外,每段高和低电平都持续了5us,也就是一条STR指令只用了5us, 对应正好一个机器周期

不过先不要太激动,上面这个测试中,代码是在 STM32L452 的 SRAM2 当中执行的。现在我再把代码放在 SRAM1 中执行,结果:

是不是很奇怪,不仅变慢了,而且同样的指令执行时间还会变化。我可以猜测,如果在 Cortex-m0 上执行同样的代码,也近乎后面这个效果。

差异从何而来? 如果你对计算机怎么工作的有所了解的话,能想得到,CPU需要先取得指令,才能够执行指令。那么指令从何处取得呢?单片机上最常用的是 Flash ROM, 还可能是从 SRAM, 甚至从片外挂的 SRAM, SDRAM, NOR Flash 等等。CPU要读内存设备取得指令,就要访问总线。上面的程序里,CPU执行 STR 指令写 GPIO 的寄存器,又是一次总线写操作。好,问题在这里:从总线读内存,与向总线写GPIO设备,这两个操作能否同时进行

然而单片机内部总线也是按照固定的时钟频率来操作的,一个总线 master 在每个总线周期最多只能发出一次请求。下图是 STM32F0x 系列(Cortex-m0)的内部结构

CPU 核心和外面的数据通道只有一条 System Bus, 因此它访问 SRAM/Flash 与访问 GPIO 在时间上必须错开。于是就会出现上面第二个画面——总线争用的结果。虽然我的实验并非在 Cortex-m0 上进行,原因是一样的。

那么第一幅画面,那个理想的结果是怎么来的? 看看我实验的这款 Cortex-m4 内部结构图:

注意了,注意了,Cortex-m4 出来有三条总线,它们是可以并行访问的。分别叫做 I-Code bus, D-Code bus 和 System bus. 这样一来,CPU在从 System bus 写 AHB2 总线上的 GPIO 设备时,CPU还可以同时从 I-Code bus 读 SRAM2 中的程序指令。于是(考虑到流水线操作的结果)就可以达到每个机器周期翻转一次 GPIO 的效果。

上面我的两次实验,代码在 SRAM2 和 SRAM1 中执行效率不同,是因为 SRAM1 是从 System bus 访问的,和访问 GPIO 设备产生了总线争用的问题。倘若把代码放在 Flash 中执行呢?也可能达到和 SRAM2 中执行(从I-Code bus访问)同样的效率,不过有一些条件,因为 Flash 的速度没有 SRAM 快,在CPU频率高的时候必须要插入等待,如果没有缓存(Cache)就会影响速度了。

再说 SRAM1 的问题,上面这个图里面,SRAM1 可是和 Cortex-m4 的三条总线都有连接的呀。我曾经就问过这个问题 https://bbs.eeworld.com.cn/forum.php?mod=viewthread&tid=508085&extra=,现在回答一下:这是按地址空间分的。在 0x20000000 以上的地址,Cortex-m4 (m3也是) 从 System bus 访问,而在 0x20000000 以下的地址,从 I-Code 和 D-Code bus 访问。倘若要提高 SRAM1 中代码的执行效率,需要启用地址重映射:


总结一下,Cortex-m0 CPU 只有一条总线(因此它属于冯·诺依曼结构,指令和数据统一寻址),就算是执行同样的机器指令程序,也跟有三条总线的 Cortex-m3/m4 (它们属于哈佛结构,指令和数据分开寻址)效率有所差异。为了在 Cortex-m3/m4 上充分发挥这个优势,注意尽量让程序在能从 I-Code bus 访问的存储器设备中执行。
此帖出自单片机论坛

最新回复

谢谢分享,学习了   详情 回复 发表于 2020-11-9 22:24
点赞(1) 关注(3)
 

回复
举报

6040

帖子

195

TA的资源

版主

沙发
 
不错不错,学习了
此帖出自单片机论坛
 
 

回复

606

帖子

20

TA的资源

一粒金砂(高级)

板凳
 
学习知识了
此帖出自单片机论坛
 
 
 

回复

37

帖子

3

TA的资源

一粒金砂(中级)

4
 

非常詳細的分析,謝謝樓主的分享;又學習了 些細微的小細節~   

此帖出自单片机论坛
 
 
 

回复

260

帖子

0

TA的资源

一粒金砂(中级)

5
 

谢谢分享,学习了

此帖出自单片机论坛
 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/7 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表