白话讲懂Cortex 内核中的AHB总线

1.1.AHB介绍

高级高性能总线简单点理解就是一条架在处理器CPU与内存与外设之间的通信渠道,大家相互之间需要遵循此总线的约束协议,然后就能在高频时钟的驱动下进行数据交互,交互是总线的核心要义。我开始理解与接触总线是先搜索的 RCC->AHB1ENR|=1<<5;这条语句是如何调用AHB总线的,芯片是如何解析这条指令的,结果在百度与谷歌引擎下都没有搜到相关的内容。(难道是太简单了,没有人来讲解与问这种问题,好吧,懂的都懂。。。)

1.2.AHB交互过程

机缘巧合之下(朋友搜到的)得到了一本神书——《ARM Cortex-M0 全可编程SoC原理及实现》不得不说这本书的作者太懂底层的人了,讲解的很细致,哪怕一个小知识点都给你说明一遍,从Cortex的寄存器,汇编指令,中断与异常开始讲解,将Cortex M3内核的内容都进行了浓缩,学习arm内核的神书,建议大家支持正版。
首先从通信双方数据交互的层面说一下总线是如何通信的,CPU根据用户编译生成的二进制文件(还是理解为汇编吧,好理解些),比如一些寄存器操作指令 MOV、MOVS、STR、LDR指令等,就涉及到读取与写入地址,而这些地址与数据就写在了AHB总线的不同总线中;
RCC->AHB1ENR|=1<<5; --假定地址转换后为(uint32_t volatile *) 0x40000000 = 0x20;
M0 的AHB总线有三个信号:32位数据总线(分为写数据总线与读数据总线)-0x20就在写数据总线中;32位地址总线-0x40000000就在地址总线中;控制信号-用于同步与识别,比如此处用于写入地址,那么控制信号 HWRITE就是高电平,还有几条控制信号,一会儿再讲。
有点尴尬,书上是用的读取数据来举例,道理类似,先看图。
总线响应

(1)处理器先将需要读取的地址写到地址总线上,译码器会根据地址,译码分路出该地址区域的一个片选信号HSEL为高电平,并且读操作时写控制信号HWRITE就是低电平表示是读取操作。
(2)而对应要被读的外设就应该要在自己的模块中做出响应(准确来说是随时都在将数据放在自己的读数据总线上),多路复用器就根据HSEL信号,被选中模块外设生成的准备信号YOUT,将该模块总线的数据总线数据映射到AHB的RWATA(读)数据总线上,这样处理器读取RWATA数据总线的数据并保存就是一次完整的数据读取流程。也就是说你拿到了你想要拿的地址的数据值。

1.3.AHB的内部构成

前面提到了地址译码器与多路复用器,这都是AHB总线里面的分模块,正是这两个负责选择的模块才能让总线有选择的操作哪个外设地址。
1.3.1.地址译码器
译码器模块接口

作用一目了然,就是输入32位地址,然后根据地址选通S0 S1 …中的哪一个,被选通的那个信号就很重要,在模块实现与复用器里面都要用到这个信号作为核心的判断依据。输出MUL_HSL是将所有片选的HSEL信号聚合为一个四位数据,与HSEL信号是同步产生的。
实现就类似于这种
译码器实现
一目了然,Verilog case就是C语言里的switch语句,分路选择的功能。
1.3.2.数据复用器
多路复用器模块接口

多路复用器功能也一目了然,输出就两个:一个是 RWATA数据总线,也就是AHB的读取数据总线,专用于外设到处理器的数据传输通道,内部实现是将S0 S1…等的数据总线数据根据译码器输出的多路组合MUL_HSL[3:0]的数据位来选通是哪个外设的数据总线映射到RWATA上;HREADY输出信号则是直接等于选通外设产生的HREADYOUT_Sx。
1.3.3.控制线
实例外设模块接口
如图中模块是实现中,输入中除了HCLK(时钟) HREST(复位) HSEL (译码片选)HADDR(地址总线) HWDATA (写数据总线)这些是上面提到的,当然key是用户设定的按键输入口,跟总线没关系,其余的就是控制信号。
书上要清楚全面些
总线信号
HSIZE;由处理器指向从设备的表示传输的数据宽度是字,字节,半字。(汇编指令中有对应的操作指令如STRH)
HTRANS;由处理器指向从设备的表示处理器当前的传输状态,在繁忙态时是不希望有任何读写操作。[1:0]可以有四种状态 IDEL,BUSY,NONSEQUENTIAL,SEQUENTIAL。
HWRITE;由处理器产生用来表示当前是写还是读操作,STR就是写,HWRITE就是高电平,LDR就是读,HWRITE是低电平。
HPORT与HBURST是一些内核的高级功能需要使用的地方,我们就不深究了,书上有讲解什么意思我没用,就不瞎讲。

1.4.实现过程与理解

比如说你在地址译码器先划分了不同地址区域的片选信号,然后你要往某一个地址写一个数据或读取数据,(uint32_t volatile *)0x51000008 假设这就是你要操作的地址,如果你代码是用在的左值,那就是写操作,0x51000008 = 1;对应的汇编可以看看,也就是分别向51000008与51000004写数据1;
汇编代码

地址译码HSEL对应的区域就会被拉高,对芯片内核来说呢,编译后识别到汇编的代码是STR指令,就像51芯片一样,你使用mov指令时,芯片的/R引脚就会自动输出低电平一样,控制线的HWRITE就会输出高电平,HADDR[31:0] 就是你要写的地址值,WDATE[31:0]就是你的数据1,的对应的接收模块里面就要设置接收判断,接收并保存这个数据就可以了,仿真图如图
总线写仿真时序
因为FPGA是时钟对齐的,写入数据要先判断HSEL因此数据就会在下一个时钟。
又比如接收芯片发过来的数据;你代码是用在的右值,那就是读操作 i = (uint32_t volatile *)0x51000008; 对应的汇编可以看看是啥,
读数据汇编代码

地址译码HSEL对应的区域就会被拉高,控制线的HWRITE就会输出低电平表示读,HADDR[31:0] 就是你要读的地址值,此时是RDATA[31:0] 与数据复用器在起作用,数据复用器会根据生成的HSEL芯片选择对应的RDATA到复用器的输出总线上,这样芯片读总线的数据那就是模块返回的数据了。如仿真图。
读数据仿真时序
附上启动代码与对应的C代码。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

总结:

以上呢就是我对Cortex内核总线AHB的一些实现过程的了解,虽然是最简单的读写操作,但是在整个AHB总线中也就只有读写,具有复杂功能的外设只是在外设实现中有复杂的逻辑判断,因此在设计c代码的时候就要配置这样寄存器那样寄存器,核心就是在于数据的传送。当然,如果你也对RCC->AHB1ENR|=1<<5;这条寄存器指令比较费解如何实现的,那么我希望你看完了我的理解之后能对别人说的明白你的理解,那样就变成了你的知识了。
最后,启动代码与结构体只是为了让对理解有一点点帮助,使用宏定义将地址转换为结构体地址从而方便访问连续的地址值是嵌入式封装的核心,我觉得这点有必要对理解总线的朋友提出来。

  • 3
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

weixin_三剑客

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值