目录前言一、MCU内部总线架构与统一编址详解1.1 总线主从设备与连接基础1.2 总线矩阵解决互联复杂度的关键1.2.1 为什么需要总线矩阵1.2.2 并行访问与仲裁机制1.2.3 专用路径直连1.3 哈佛架构与冯·诺依曼架构的演变1.3.1 冯·诺依曼架构大杂烩1.3.2 哈佛架构分道扬镳1.4 STM32的三条核心总线ICode、DCode与System1.4.1 ICode总线指令专用通道1.4.2 DCode总线数据专用通道针对Flash1.4.3 System总线系统通用通道1.5 高速与低速的分层设计AHB与APB1.5.1 AHB高速公路1.5.2 APB乡村公路1.6 统一编址软件视角的“大一统”1.6.1 什么是统一编址1.6.2 存储器映射图详解1.6.3 对开发者的意义1.7 总结与源码预告结语 云泽Q个人主页 专栏传送入口: 《C语言》《数据结构》《C》《Linux》《蓝桥杯系列》《笔试算法》《AI赋能》《STM32》⛺️遇见安然遇见你不负代码不负卿~前言大家好啊我是云泽Q欢迎阅读我的文章一名热爱计算机技术的在校大学生喜欢在课余时间做一些计算机技术的总结性文章希望我的文章能为你解答困惑~一、MCU内部总线架构与统一编址详解在正式深入理解点灯程序之前我们需要先打通一个至关重要的底层概念——总线与统一编址。这不仅是理解STM32等MCU如何工作的基石更是我们后续编写代码、操作寄存器的理论依据。为了让大家更直观地理解我们将结合各种图片从物理连接、逻辑架构到软件映射进行全方位的拆解。1.1 总线主从设备与连接基础之前的文章在STM32或接触ARM Cortex-M3内核时我都贴过一张MCU内部结构图但往往没有深究其背后的逻辑。首先我们要明确MCU内部并非孤立存在的组件堆砌它包含了ARM Cortex-M3这样的CPU核心以及大量的片上外设如GPIO、定时器、通信接口等。这些外设提供了数据存储能力和设备控制能力。既然我们要编写代码来控制这些外设就必须在硬件层面建立连接。如果没有“线”作为数据通路CPU发出的数据信号就无法传输到具体的外设中控制也就无从谈起。这种在MCU内部连接各个硬件模块的“线”我们称之为总线。基于总线的交互关系我们将MCU内部的设备分为两类总线主设备指能够主动发起对硬件单元访问请求的设备。最典型的就是ARM CPU此外还有我们后续文章中会写到的DMA直接存储器访问控制器。它们就像发号施令的“皇帝”或“指挥官”。总线从设备指被动响应主设备请求的硬件模块。例如内存、Flash以及各类片上外设GPIO、I2C等。它们相当于执行具体任务的“职能部门”。1.2 总线矩阵解决互联复杂度的关键如果MCU内部只有几个设备直接连线尚可维持。但随着外设数量增加如果让每个主设备都直接连接到每个从设备连线数量将呈爆炸式增长导致芯片面积巨大且布线极其复杂。为了解决这个问题引入了总线矩阵的概念。1.2.1 为什么需要总线矩阵想象一下如果所有线都直接从CPU引出连接到各个外设CPU引脚数将变得不可接受。总线矩阵的作用就是简化这种互联结构。它像一个智能的交通枢纽主设备只需要连接到矩阵的输入端从设备连接到输出端矩阵内部负责根据地址和需求动态建立通路。1.2.2 并行访问与仲裁机制总线矩阵不仅仅是简化连线它还支持并行访问。例如当CPU正在通过一条路径访问Flash读取指令时DMA控制器可以同时通过另一条路径访问SRAM进行数据搬运两者互不干扰极大地提高了系统效率。当多个主设备同时请求访问同一个从设备例如都想去读内存时总线矩阵会启动仲裁机制。它会根据预设的优先级或者轮询策略决定谁先谁后避免数据冲突。1.2.3 专用路径直连虽然大部分访问通过矩阵但为了提高性能某些高频访问的路径会被“特殊照顾”。比如ICode总线它是专门为了让CPU快速读取Flash中的指令而设计的专线直接绕过复杂的矩阵仲裁确保指令执行不卡顿。1.3 哈佛架构与冯·诺依曼架构的演变要理解为什么STM32会有ICode、DCode这么多条总线我们必须先聊聊计算机体系结构中的两大流派冯·诺依曼架构和哈佛架构。1.3.1 冯·诺依曼架构大杂烩在经典的冯·诺依曼架构中指令和数据是存放在同一个存储器里的而且共用同一套总线地址总线数据总线。缺点这就好比一条单行道CPU在取指令的时候就不能传数据传数据的时候就不能取指令。这会导致“总线瓶颈”性能受限实时性也一般。优点硬件简单成本低。1.3.2 哈佛架构分道扬镳为了解决速度问题哈佛架构应运而生。它的核心特点是物理分离存储空间分离指令存储器通常是Flash和数据存储器通常是SRAM是独立的。总线独立有独立的指令总线和数据总线。这意味着CPU可以一边通过指令总线取指令一边通过数据总线读写数据两者并行执行互不干扰。这就好比修了高架桥和地面道路快车和慢车互不影响性能大幅提升实时性也变得可预测。STM32采用的正是改进型的哈佛架构。STM32内部既有存指令的Flash又有存数据的SRAM并且通过不同的总线去访问它们。1.4 STM32的三条核心总线ICode、DCode与System基于哈佛架构的思想ARM Cortex-M3内核设计了三条主要的总线接口分别对应不同的任务这也是我们理解MCU内部数据流向的关键。1.4.1 ICode总线指令专用通道全称Instruction Code Bus指令代码总线。作用这是一条“VIP通道”专门负责从程序存储器Flash中读取指令然后交给CPU去执行。特点因为它只干这一件事所以速度极快且独占带宽。当你运行代码时CPU就是通过这条线源源不断地把指令“吸”进来的。1.4.2 DCode总线数据专用通道针对Flash全称Data Code Bus数据代码总线。作用主要负责从Flash中读取常量数据。场景解析大家在写代码时定义的const变量比如const int val 100;这些只读数据是存在Flash里的。当CPU需要用到这个常数时就会通过DCode总线去Flash里把它读出来。注意虽然它主要连Flash但在某些特定调试场景下也能访问其他区域但核心职责就是搬运Flash里的“只读数据”。1.4.3 System总线系统通用通道全称System Bus系统总线。作用这是一条“万能总线”负责处理除了取指令和读Flash常量之外的所有事情。具体任务访问SRAM读写全局变量、局部变量栈、堆内存等。访问外设控制GPIO、配置定时器等。访问外部存储器通过FSMC等接口扩展的外部设备。连接方式System总线连接到总线矩阵再通过AHB高速和APB低速总线桥接器最终连接到各个具体的外设上。1.5 高速与低速的分层设计AHB与APB有了System总线后面对速度差异巨大的外设比如高速的SRAM和低速的串口如果都用同一种速度通信要么浪费高性能要么拖慢整体节奏。因此ST引入了分层设计。1.5.1 AHB高速公路全称Advanced High-performance Bus高级高性能总线。定位这是系统的主干道类似于城市的主环路或高速公路。连接对象连接那些对速度要求高的设备如SRAM、Flash接口、DMA以及总线矩阵本身。特点频率高带宽大支持突发传输。1.5.2 APB乡村公路全称Advanced Peripheral Bus高级外设总线。定位这是连接低速外设的支线类似于通往各个小区的乡村公路。分类APB2相对高速挂载了一些比较重要的、速度稍快的外设比如GPIO我们要用的点灯端口就在这里、USART1、SPI1、ADC1等。它的最高时钟频率通常能达到72MHz在标准配置下。APB1低速挂载了大量低速外设如I2C、USART2/3、TIM2/3/4、CAN、USB等。它的最高时钟频率通常限制在36MHz。桥接器BridgeAHB和APB之间不是直接连的而是通过“桥”连接。这个桥就像一个变速器或协议转换器把AHB的高速信号“降速”并转换为APB能听懂的协议信号实现了不同速度域设备的无缝对接。1.6 统一编址软件视角的“大一统”讲了这么多硬件连线最后我们要回到软件开发者的视角。既然硬件上分了ICode、DCode、System分了AHB、APB那我们在写C语言代码时岂不是要分别调用不同的驱动去访问答案是不需要。这就是统一编址Unified Addressing的魅力。1.6.1 什么是统一编址在ARM Cortex-M3看来无论是内部的SRAM、Flash还是外挂的GPIO、USART寄存器本质上都是“存储空间”。MCU内部有一个巨大的地址空间对于32位CPU是4GB即2 32 2^{32}232。ST工程师把这个4GB的空间像切蛋糕一样划分成了不同的区域Block。每个存储单元、每个外设寄存器都被分配了一个唯一的、不重叠的物理地址。1.6.2 存储器映射图详解大家可以看这张复杂的“存储器映射图”Memory MapBlock 0 (Code)0x0000 0000-0x1FFF FFFF。这里主要放Flash和SRAM。我们的代码和变量主要就在这儿。Block 1 (SRAM)0x2000 0000开始。这是内置SRAM的起始地址。Block 2 (Peripherals)0x4000 0000-0x5FFF FFFF。这里是重点所有的片上外设寄存器都映射在这个区域。比如APB2总线上的外设起始地址通常在0x4001 0000。GPIOF的基地址就是0x4001 1C00举例具体查手册。APB1总线上的外设起始地址通常在0x4000 0000。1.6.3 对开发者的意义因为做了统一编址我们在C语言里操作外设就变得非常简单直接指针即地址我们可以直接定义一个指针指向某个特定的物理地址例如0x40011C00。读写即操作对这个地址进行写操作*ptr 1硬件电路就会把这个电信号通过System总线 - AHB - APB2 - GPIOF寄存器最终点亮LED。无感切换你在代码里访问变量读写SRAM和访问寄存器读写GPIO语法上完全一样都是解引用指针底层硬件会自动判断该走哪条总线SRAM走System-AHBGPIO走System-AHB-APB开发者完全不需要关心底层的总线切换细节。1.7 总结与源码预告综上所述STM32的内部是一个精密的交通网络CPU是指挥中心。ICode/DCode是读取程序和常量的专用快车道。System总线是通往内存和外设的主干道。AHB/APB是根据速度分级的高速路和辅路。统一编址则是这张交通网的地图让CPU能通过唯一的坐标地址找到任何一个设备。理解了这些我们就明白了为什么之前写的点灯代码中那个GPIOF其实代表的就是一串具体的物理地址。HAL库帮我们封装了这些地址但如果我们要看透本质就必须去看源码里的地址定义。在下篇文章中我们将正式切入源码分析环节看看这些理论上的地址是如何在代码中被定义和使用的彻底解决“地址从哪里来”的问题。结语