社区导航

 

搜索
查看: 6511|回复: 3
打印 上一主题 下一主题

[经验] 小议ARM Cortex-m0/m4系列的总线差异

[复制链接]

1265

TA的帖子

1

TA的资源

五彩晶圆(初级)

Rank: 7Rank: 7Rank: 7

跳转到指定楼层
楼主
发表于 2019-1-28 23:06 | 只看该作者 |只看大图 |倒序浏览 |阅读模式
从一个简单问题说起: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 的三条总线都有连接的呀。我曾经就问过这个问题 http://bbs.pyfle.com/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 访问的存储器设备中执行。
此帖出自单片机论坛
0

5719

TA的帖子

207

TA的资源

版主

Rank: 6Rank: 6

沙发
发表于 2019-1-29 08:56 | 只看该作者
不错不错,学习了

EEWORLD开发板置换群:309018200,——电工们免费装β的天堂,上班摸鱼场,释放压力好地方!商家勿入!加群暗号:喵


632

TA的帖子

20

TA的资源

一粒金砂(高级)

Rank: 3Rank: 3

板凳
发表于 2019-1-29 13:30 | 只看该作者
学习知识了

29

TA的帖子

2

TA的资源

一粒金砂(中级)

Rank: 2

4
发表于 2020-2-14 07:25 | 只看该作者

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


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

关闭

站长推荐上一条 1/4 下一条

  • 论坛活动 E手掌握

    扫码关注
    EEWORLD 官方微信

  • EE福利  唾手可得

    扫码关注
    EE福利 唾手可得

Archiver|手机版|小黑屋|电子工程世界 ( )

GMT+8, 2020-4-3 10:10 , Processed in 0.174186 second(s), 18 queries , Gzip On, MemCache On.

快速回复 返回顶部 返回列表
湖南快乐十分官网 任我赢机器人 235棋牌 云南11选5分布走势图 快乐飞艇彩票安全吗 快乐飞艇能玩吗 快乐飞艇6码计划算法 快乐赛车直播开奖视频 快乐飞艇 吉林快3