在很多MCU的库代码里一般都会有类似下面的时钟使能配置宏(不同厂商在配置模式上会存在差异),即如果你需要使用MCU的某个外设,首先就需要使能外设对应的时钟,即让外设正常工作起来,并且会根据所挂载的总线不同会进行区分:
![]()
![]()
然后在数据手册里一般也会有专门一个章节,一般称为时钟和复位控制RCC,来专门讲解相关内容:
![]()
那到底这几条总线(AHB,APB1,APB2)是什么呢?有什么作用呢?我们继续往下看!
其实对从事基于MCU的嵌入式软件攻城狮来说,应该都知道MCU里面的AHB、APB2、APB1三大总线吧,即使了解不深,起码也多少熟悉一点,因为有时候很多软件问题和Bug什么的,都是与它们息息相关的,比如低功耗产品的功耗偏高达不到要求、串口通信收不到数据、需要大量传输音频数据和时钟配置错误导致的数据通信异常等等。因此,我们就有必要来深入认识和了解一下这三大总线,来一次比较彻底的扫盲行动。
其实,可以如文章标题那样,我们将AHB、APB2、APB1三大总线理解为MCU芯片内部连接各个部件和外设的“高速公路”,它们分工明确,主要负责在处理器核心、内存和各种外设之间传输数据和控制信号等。而这个“高速公路”的高速也是相对的含义,就是说这三大总线支持的速度是不一样的,AHB最快,APB2次之,APB1相对较慢,不同的外设挂载在不同的总线上。
先简单介绍一下三大总线:
AHB:
Advanced High Performance Bus,高级高性能总线,其总线频率一般等于系统时钟,这是系统的主干线,追求高性能和高速度;直接连接对速度要求极高的核心部件,确保数据能快速流通,即主要负责连接处理器、DMA等一些内部接口;
APB2:
Advanced Peripheral Bus 2,高级外设总线2,专门服务于对速度有较高要求的外设,让它们能更快地与内核交换数据,即主要负责连接外围设备(简称外设);
APB1:
Advanced Peripheral Bus 1,高级外设总线1,主要为了功耗优化而设计,专门连接对速度不那么敏感的外设,也主要负责连接外围设备,它的时钟频率通常较低,可以有效节省电能。
其中,APB总线架构不像 AHB那样可以支持多个主模块,在APB里面唯一的主模块就是APB 桥,这个APB桥就是连接AHB和APB中间的玩意,下面会说到。
所以,从其含义和主要作用就可以看出,其设计之讲究,分工明确,互不干扰,相辅相成。
再来看看三大总线的架构形式:
通过下面这张图就能明白三大总线的基本架构形式了:
![]()
上面这张图里的低速是相对高速而言的,并不是真正意义上的速度慢,只是为了更好的区分APB2和APB1,比如STM32的某些系列的AHB最高是72M,APB2是72M,APB1是36M;Artery的某些系列的AHB最高是240M,APB2是120M,APB1也是120M,等等。
通过这张图也可以看出,AHB总线是高速核心干道,连接了一些最重要的区域,而APB2和APB1根据外设类型分别连接着不同速度的外设模块。
另外,三大总线也不是孤立工作的,它们通过总线桥接器相互连接起来,形成了一个完整的系统,如下面某Cortex-M4核的系列MCU的功能框图所示:
![]()
该功能框图明确了哪些外设挂载在哪条总线上面,并且还标注了各总线支持的最高频率,比如如果你需要配置SPI1的时钟频率,在设置分频系数之前,肯定要先确定SPI1是挂载在哪条总线上及该总线配置的最高频率是多少,这样你才能最终确定SPI1的时钟频率是你想要配置的:
![]()
![]()
另外,也可以看出,APB2和APB1都是通过AHB-APB桥接器连接到AHB总线上面的,这种架构不仅保证了高速外设的读写速度,还可以兼顾低速外设的功耗管理。
之所以有相对高速而言的低速外设,主要目的是为了降低功耗。因为在电池供电的低功耗产品中,功耗是非常重要的设计指标,对于很多对速度要求不高的外设,我们使用低速外设就能满足设计需求,还可以管理功耗;比如我们通过控制APB2执行降频运行,可以一定程度上延长电池的使用寿命。
接着再来说说与总线时钟配置相关的一些问题和排查方法。
我们在实际代码开发时,其实会经常遇到与时钟配置有关的问题,一般排查的步骤可以参考如下所述:
先检查对于的外设总线时钟是否使能;
之前我就遇到过一次,串口通信的时候收不到主机发来的数据,后来排查发现,是串口对应的外设时钟没有使能导致的,这种问题看似简单,在代码工程中有时候却不容易定位;
再检查时钟频率是否正确,特别是对应的总线频率不能超过其最高频率;
最后可以检查一下外部或者内部时钟源是不是稳定,特别是当你用的是外部晶振的时候。
对于功耗优化的时候一直很难调试到最优值的时候,可以尝试将高速外设修改为低速外设,比如用基本或者通用定时器来代替高级定时器等;另外,通过代码反复精准的使能或禁止外设时钟等操作,也可以降低功耗,毕竟功耗优化是一个需要耐心和信心,慢慢调试的过程。
如果需要频繁大量传输音视频数据,可以考虑使用通过AHB总线通信的DMA外设来避开CPU干预等等。
在项目开发时,一定要明确清楚所用的外设归属于哪一条总线,这样在遇到问题或者功能和性能优化的时候,才能知道怎么修改,而不是模棱两可。
其实,我们再来看三大总线的框图,也可以理解为APB2总线和APB1总线是AHB总线的分支和继承,两者实现目标不同,应用场景不一样而已。
另外,有些系列的MCU可能还有将AHB总线细分为AHB1 和AHB2,并将其中之一通过总线桥接器连接到APB1和APB2,之所以这么设计,一般是基于性能优化、时钟管理、功耗控制以及硬件设计的物理限制等因素,简单一点来说,这就像把一条高速公路(单个AHB)扩建为拥有快慢车道和专用匝道的复合路网(AHB1和AHB2),以确保不同速度的车辆(外设/内核)都能高效通行,不会互相堵塞。
比如下面某个厂商的某个系列的MCU的功能框图所示:
![]()
将AHB细分为了AHB1和AHB2,其中AHB2挂载了DAC外设和GPIO外设,AHB1连接了APB1和APB2。比如下面这段代码就是使能GPIOA和GPIOB时钟的,明显可以看到是挂载在AHB2上面的:
![]()
而DAC同样也是挂载在AHB2总线上面的:
![]()
综上,一般情况下,通过MCU数据手册里的功能框图或者MCU外设库代码都能知道外设挂载在哪个总线上面。
有些外设库代码是以下面这种带形参的函数接口形式来使能或禁止外设时钟的:
![]()
其中的CRM就是时钟和复位管理的意思,比如你要使能SPI2外设的时钟,这么操作即可:
复制
crm_periph_clock_enable(CRM_SPI2_PERIPH_CLOCK,TRUE);
![]()
有些库代码是以统一管理外设时钟使能的方式实现的,有些是分外设单独管理实现的,归根结底,本质不变。
不仅如此,有些系列的MCU可能还有将AHB总线细分为AHB1 ,AHB2和AHB3,但一般常见的APBx都只有APB1和APB2,如下图所示,不过再怎么变化,只是把不同功能模块挂载在不同总线上,只要你看的懂功能框图,会用库代码,就没什么大问题:
![]()
然后在用户手册上也会有对应的可配置的寄存器:
![]()
因此,三大总线的基本架构形式基本上都只用AHB作为参考,至于其继承的AHBx(x=1,2,3,……)因MCU不同而存在差异,需要阅读对应的数据手册才能知道。
以上便是对MCU的AHB、APB2和APB1三大总线的一些扫盲解读,希望可以给你带来一些有用的东西~~
![]()
:
---------------------
作者:dffzh
链接:https://bbs.21ic.com/icview-3507106-1-1.html
来源:21ic.com
此文章已获得原创/原创奖标签,著作权归21ic所有,任何人未经允许禁止转载。