一、ARM 微处理器概览
1.1 ARM 公司与 Cortex 系列
- ARM 公司:
 - 成立于1990年11月,原名 Advanced RISC (精简指令集)Machines。
 - 与复杂指令集(CISC)不同,RISC的每条指令长度相同且指令格式简单,而CISC使用变长指令且指令功能复杂。RISC的简化设计使处理器能以更高的时钟频率运行,实现更高的指令吞吐量。
 - 主要设计 RISC 处理器核心,也提供IP核、软件工具、模型和单元库等。
 - ARM 公司不制造芯片,而是授权其设计给合作伙伴。
 - 截至2020年,合作伙伴已出货超过1800亿颗基于ARM的芯片。
 
- Cortex 系列命名与分类 :
 - 2004年后,ARM 处理器采用 Cortex 命名。
 - Cortex-A 系列:用于高性能开放应用平台。
 - Cortex-R 系列:用于实时控制系统。
 - Cortex-M 系列:用于传统微控制器系统。
 - 2020年第三季度出货67亿颗基于ARM的芯片,其中44亿为 Cortex-M 处理器。
 
- ARM 架构版本演进 :
 - 主要版本包括 v4, v4T, v5, v5E, v6, v7, 直至最新的 v9。
 - Thumb 指令集在 v4T 问世。
 - Thumb-2 指令集在 v6 架构开始支持时问世。
 - v5E 架构加入了增强型 DSP 指令。
 - v6 架构开始支持 SIMD (单指令多数据流)。
 

1.2 Cortex-M3/M4 处理器特性
数据宽度与寻址 :❗
- 32位 RISC 处理器。
 
- 32位寄存器、32位内部数据路径、32位总线接口。
 
- 32位寻址,地址空间高达 4GB。
 - ARM的地址是32位的。
 - 每个唯一的32位地址对应内存中一个8位(1字节)的数据存储位置。
 
- 支持处理字节 (8位/byte)、半字 (16位/2 bytes)、字 (32位/4 bytes) 和双字 (64位/8 bytes)
 
指令集 - Thumb-2 技术 ❗
- 传统 ARM 指令集包含32位 ARM 指令和16位 Thumb 指令,两者需切换模式。
 
- Cortex-M 采用 Thumb-2 指令集技术,同时支持16位和32位指令,无需切换状态。
 
- Thumb-2 兼顾了 ARM 指令的性能和 Thumb 指令的优秀代码密度。
 - 代码尺寸比 ARM 指令小约26%。
 - 性能比 Thumb 指令快约25%。
 


三级流水线 ❗
- 取指 (Fetch)
 - 考点:PC会指向下一个取指的地址(当前地址+4)
 - 51中PC指向下一个执行的指令,因为流水线的缘故这里的PC手伸得更长
 
- 译码 (Decode)
 
- 执行 (Execute)
 
可一次读取两条16位指令。(因为系统是32位的)
某些指令执行多个周期时,流水线会暂停。
跳转到分支后流水线清空。


- Flash 访问速度限制 :Flash 读取速度较慢 (典型20-50ns)。
 - 解决策略:增加 Flash 读取数据宽度 (如128位) 和指令预取。
 - STM32F4 的 Flash 访问加速器 (ART Accelerator) 包含指令预取和缓存机制。
 - 也就是在空闲的时候将Flash中的指令读取好放到某一个高速缓冲区域内
 


字节顺序 (Endianness) ❗
指字节在内存中的存储顺序。
- ARM中内存仍然以byte(8bits)为基本单位储存
 
- 一个字有4个字节,也就有4个地址;👉这就带来了问题
 
- 小端模式 (Little-endian):字的最低有效字节存储在最低地址。Cortex-M 一般采用小端模式。
 

- 大端模式 (Big-endian):字的最低有效字节存储在最高地址。
 

Cortex-M4 理论上支持两种模式,但通常采用小端模式。
数据对齐 :
- 内存系统为32位 (4字节),地址按字节定义。
 
- 对齐传输:字访问地址应为4的倍数,半字访问地址应为2的倍数。
 

- 非对齐传输:对字和半字的地址无此限制。Cortex-M3/M4 支持非对齐数据访问,但可能会牺牲性能,因为硬件会将其转换为多次对齐访问。
 - 多加载/存储指令 (LDM/STM) 和栈操作不支持非对齐传输。
 - 应尽量避免非对齐传输。
 

存储器保护单元 (MPU) :
- 一种硬件机制,通过定义内存区域的访问权限和属性来增强系统安全性和可靠性。
 
- 作用:防止任务访问未授权内存、避免非法操作导致系统崩溃、辅助调试。
 
- STM32 M3 存储器访问缺省设置对不同区域有不同用户级许可权限。
 
二、ARM Cortex-M 处理器架构
2.1 寄存器组❗❗

通用寄存器 (R0-R12) ❗
- R0-R7 (低组寄存器):一些16位Thumb指令只能访问这些寄存器。
 
- R8-R12 (高组寄存器):可用于32位和16位指令。
 
栈指针 (R13, SP) ❗
- 用于 PUSH 和 POP 操作
 
- 物理上存在两个栈指针:
 - 主栈指针 (MSP):复位后默认使用,通常在处理模式和特权级线程模式下使用。
 - 进程栈指针 (PSP):通常在用户级线程模式下使用,特别是在 RTOS 环境中。
 
处理器模式  | CONTROL[1] (SPSEL)  | 当前活动的堆栈指针  | 场景说明  | 
处理模式 (Handler Mode)  | 任意值  | MSP  | 任何中断、异常服务程序都在此模式下运行  | 
线程模式 (Thread Mode)  | 0 (默认)  | MSP  | 运行简单的裸机程序,或RTOS内核本身  | 
线程模式 (Thread Mode)  | 1  | PSP  | 运行在RTOS(实时操作系统)下的用户任务  | 
链接寄存器 (R14, LR) ❗
- Link Register
 
- 存储函数或子程序调用时的返回地址。
 
- 执行了函数或者子程序调用的时候,LR的数值会自动更新
 
NOTE THAT:
中断中LR的行为较为特殊,具体参见异常和中断部分笔记
程序计数器 (R15, PC) ❗
- 可读可写
 
- 读操作返回当前指令地址+4(由于流水线)
 
- 写 PC 会引起跳转。
 
特殊寄存器 ❗
- 不能直接通过内存地址访问,需使用 MRS (读) 和 MSR (写) 指令。
 
程序状态寄存器 (xPSR) ❗

物理上,这是一个32位的寄存器。
逻辑上,这个寄存器又可以分为以下三个部分。我们可以像访问独立的寄存器一样单独访问他们。
- 应用PSR (APSR):包含算术逻辑单元 (ALU) 的状态标志 (N, Z, C, V, Q, GE[3:0])。
 
- 中断PSR (IPSR):包含当前中断服务例程 (ISR) 的异常编号。
 
- 执行PSR (EPSR):包含 ICI/IT (中断继续指令/IF-THEN 指令状态) 和 T (Thumb状态) 位。T位恒为1,清除会导致错误。
 

中断屏蔽寄存器
- PRIMASK: 置1后关闭所有可屏蔽异常,仅NMI和HardFault可响应。
 
- FAULTMASK: 置1后关闭所有可屏蔽异常和HardFault,仅NMI可响应。
 
- BASEPRI: 定义被屏蔽优先级的阈值,高于此值(数值上,优先级越低)的中断被关闭。0表示不关闭任何中断。
 
- 这些寄存器只能在特权等级下操作。
 

控制寄存器 (CONTROL)
- nPRIV (位[0]): 定义线程模式的特权等级 (0=特权级, 1=用户级)。
 
- SPSEL (位[1]): 选择线程模式下的栈指针 (0=MSP, 1=PSP)。处理模式下固定使用MSP。
 
- FPCA (位[2]): (仅M4F) 浮点上下文活动标志,指示异常发生时是否需要保存浮点寄存器。
 

Cortex-M4F 浮点寄存器 (FPU) : (若处理器包含浮点单元)
- 32个单精度寄存器 (S0-S31)。
 - 可作为16个双精度寄存器 (D0-D15)。
 
- 浮点状态和控制寄存器 (FPSCR)。
 
2.2 工作模式与特权等级 ❗
2.3 存储器映像❗
总共 4GB 的地址空间,被划分为不同的区域。
片上系统(前1.5GB)
- 代码区 (Code),0.5GB:通常从 0x00000000 开始,主要存放程序代码。
 
- SRAM 区,0.5GB:通常从 0x20000000 开始,主要存放数据,但也可以执行代码。
 
- 外设区 (Peripheral),0.5GB:通常从 0x40000000 开始,用于访问片上外设。
 

外部拓展(后2GB)
- RAM区 (1GB): 这个地址空间是预留给你外接 RAM 芯片使用的。如果你的应用需要比片内SRAM更大的内存,就可以通过FSMC(灵活的静态存储控制器)等接口外扩RAM,并将其映射到这个地址范围。
 
- 设备区 (1GB): 这个地址空间同样是预留给你外接其他设备使用的,比如外接更大容量的Nor-Flash,或者其他需要内存映射的专用芯片。
 
系统/供应商定义区(0.5GB)
三、Cortex-M 指令集 (Thumb-2)
3.1 指令集特点与格式❗
语言格式
- 32位或16位的 RISC 指令集。
 
- 指令格式:
标号 操作码 操作数1, 操作数2, ... ;注释 - 标号可选,顶格写。
 - 操作码前至少一个空白符。
 - 第一个操作数通常是结果存储处。
 
- 立即数以 
#开头。 
- 注释以 
;开头。 
- 可使用 
EQU定义常数。 
指令后缀 ❗
S❗: 要求更新 APSR 中的状态标志 (N, Z, C, V, S)。
位号  | 标志位  | 功能描述  | 
31  | N  | 负数标志 (Negative): ALU 运算结果为负数,即结果的最高位 (bit[31]) 为 1 时,N 位置 1 。  | 
30  | Z  | 零结果标志 (Zero): ALU 运算结果为 0 时,Z 位置 1 。  | 
29  | C  | 进位/借位标志 (Carry):无符号数运算溢出标志:如果无符号数运算产生进位(加法)或借位(减法),C 位置 1 。 
对于加法指令,如果产生了超出 32 位范围的进位,C 位置 1。
对于减法指令,如果没有发生借位(即结果为正或零),C 位置 1。  | 
28  | V  | 溢出标志 (oVerflow): 有符号数运算溢出标志:如果算术运算结果超出了有符号数的表示范围(例如两个正数相加得到负数,或两个负数相加得到正数),V 位置 1 。  | 
27  | S  | 饱和标志 (Saturation):仅在 Cortex-M4F 中可用,表示饱和运算是否发生饱和。它不做条件转移的依据 。  | 
- 条件后缀❗ (如 
EQ,NE,LT,GT等):用于条件执行,主要用于转移指令 (B)。 - 条件码基于 APSR 中的 N, Z, C, V 标志。
 
后缀  | 含义 (英文)  | 含义 (中文)  | 标志位条件  | 解释  | 
EQ  | Equal  | 等于  | Z = 1  | 如果结果为零(通常表示比较的两个数相等)  | 
NE  | Not Equal  | 不等于  | Z = 0  | 如果结果不为零(通常表示比较的两个数不相等)  | 
GE  | Greater than or Equal  | 有符号大于等于  | N = V  | 如果有符号数A >= B (即N位和V位相同)  | 
GT  | Greater Than  | 有符号大于  | Z=0 和 (N = V)  | 如果有符号数A > B  | 
LT  | Less Than  | 有符号小于  | N != V  | 如果有符号数A < B (即N位和V位不同)  | 
统一汇编语言 (UAL) :
- 规范了汇编语言格式,解决传统 Thumb 到 Thumb-2 的兼容问题。
 
- 允许汇编器自动选择16位或32位指令,或手动指定 (
.N为窄指令/16位,.W为宽指令/32位)。 
- 16位和32位指令的立即数范围不同。
 
3.2 主要指令类型与示例❗
处理器内部数据传送指令  ❗
MOV是寄存器之间传送数据的指令
MOV Rd, Rn: Rd = Rn❗
MOV Rd, #imm: Rd = imm❗
MOVS: 带S后缀,更新标志位。❗
MOVW Rd, #imm16: 将16位立即数存入Rd低16位,高16位清零。❗
MOVT Rd, #imm16: 将16位立即数存入Rd高16位,低16位不变。❗
MVN Rd, Rn: Rd = ~Rn (按位取反)❗
存储器访问指令 :❗
所有对寄存器操作都是用指针
基础指令:
LDR (Load,读存储器),STR (Store,写存储器)。数据大小后缀 :
B(Byte, 8位无符号),SB(Signed Byte, 8位有符号)
H(Halfword, 16位无符号),SH(Signed Halfword, 16位有符号)
- 无后缀 (Word, 32位)
 
D(Doubleword, 64位)
M(多个32位)

寻址模式: 
这么设计的部分原因是为了和C语言方便的转化
- 立即数偏移 (前序): 
LDR Rd, [Rn, #offset] !后缀:指令执行后更新基址寄存器 Rn (Rn = Rn + offset)。
以一个寄存器作为存储器的基准地址(指针),与一个立即数相加,和作为访问的存储器的地址。称为“前序”寻址

- 寄存器偏移 (前序): 
LDR Rd, [Rn, Rm, {LSL, #n}] 
以一个寄存器作为存储器的基准地址(指针),与一个从索引寄存器值相加,和作为访问的存储器的地址。从索引寄存器的值在相加前,可以左移0-3位。

- 后序 (Post-indexed): 
LDR Rd, [Rn], #offset 
在存储器访问期间不使用偏移值,仅在数据结束后更新地址寄存器(指针)。指令无需使用感叹号!

- PC相对寻址: 
LDR Rd, [PC, #offset] 
例1:
多重加载/存储指令 :
LDMIA Rd!, {reg_list}: 从 Rd 指向的地址开始,连续加载多个字到寄存器列表,Rd 每次递增 (Increase After)。
STMIA Rd!, {reg_list}: 连续存储多个寄存器到 Rd 指向的地址,Rd 每次递增。
LDMDB Rd!, {reg_list}: ... Rd 每次递减 (Decrease Before)。
STMDB Rd!, {reg_list}: ... Rd 每次递减。STMDB SP!, {reg_list}等效于 PUSH。
LDMIA SP!, {reg_list}等效于 POP。
加载32位立即数/地址到寄存器的方法 :
MOVW+MOVT
ADR Rd, label: PC相对寻址,将标号地址加载到 Rd。偏移量有限制。
LDR Rd, =value_or_label(伪指令):编译器自动选择合适方式加载,可能转换为 PC 相对加载或 MOVW+MOVT。
例2:对32位内存地址赋值
最好的方法似乎是伪指令


算术运算指令 :
ADD Rd, Rn, Rm: Rd = Rn + Rm

ADC Rd, Rn, Rm: Rd = Rn + Rm + Carry (带进位加法)

SUB Rd, Rn, Rm: Rd = Rn - Rm
SBC Rd, Rn, Rm: Rd = Rn - Rm - Carry (带借位减法)
RSB Rd, Rn, #imm: Rd = imm - Rn (反向减法)
MUL Rd, Rn, Rm: Rd = Rn * Rm (乘法)
MLA Rd, Rn, Rm, Ra: Rd = (Rn * Rm) + Ra (乘加)
MLS Rd, Rn, Rm, Ra: Rd = Ra - (Rn * Rm) (乘减)
UDIV Rd, Rn, Rm: 无符号除法,Rd = Rn /Rm
SDIV Rd, Rn, Rm: 有符号除法
- 饱和运算指令 (如 
SSAT,QADD):将结果限制在特定范围内。 

逻辑运算指令 :
AND Rd, Rn, Rm: Rd = Rn & Rm
ORR Rd, Rn, Rm: Rd = Rn | Rm
EOR Rd, Rn, Rm: Rd = Rn ^ Rm (异或)
BIC Rd, Rn, Rm: Rd = Rn & (~Rm) (位清除)
移位和循环移位指令 :
LSL Rd, Rn, #count或LSL Rd, Rn, Rm: 逻辑左移
LSR: 逻辑右移
ASR: 算术右移 (保留符号位)
ROR: 循环右移
位处理指令 (略)
数据转换指令 (如大小端转换) (略)
比较和测试指令 : (不保存结果,只更新APSR标志)
CMP Rn, Rm: Rn - Rm
CMN Rn, Rm: Rn - (-Rm) (即 Rn + Rm)
TST Rn, Rm: Rn & Rm
TEQ Rn, Rm: Rn ^ Rm
程序流控制指令 ❗
跳转 (Branch):❗
B label❗: 无条件跳转到标号,范围±2KB
BX Rm❗: 跳转到 Rm 中的地址 (Rm最低位决定目标状态,Cortex-M中应为1,保持Thumb状态)。
函数调用 (Branch with Link):
BL label: 跳转到标号,并将返回地址 (PC+4) 保存到 LR。
BLX Rm: 跳转到 Rm 中的地址,保存返回地址到 LR。
B和BL系列指令的区别是:是否保留返回地址。
条件跳转❗: B<cond> label 
- 比较和跳转:
 CBZ Rn, label: 如果 Rn 为零则跳转。CBNZ Rn, label: 如果 Rn 非零则跳转。
- 条件执行 (IF-THEN 指令) :
 IT{<cond>}: If-Then. 下一条指令条件执行。ITT{<cond>}: If-Then-Then.ITE{<cond>}: If-Then-Else.- 最多支持4条条件指令 (e.g., 
ITTEE). 
IT 指令最大的优势在于效率。传统的 if-else 通常用跳转指令实现(如 BEQ, BNE)。跳转指令会打乱CPU的指令流水线。示例:比较 R0 和 R1,如果相等则将 R2 设为1,否则将 R2 设为0。
等价的C语言代码:
注意:IT指令后的最多4条指令必须使用相应的条件后缀(如EQ、NE等),且必须符合IT指令指定的条件序列。
C语言与汇编的对应 :
- 函数参数通常通过 R0-R3 传递。
 
- 函数返回值通常通过 R0 传递。
 
- 局部变量优先使用寄存器,若寄存器不足则使用堆栈。
 

四、异常和中断
4.1 异常概述
- 异常 (Exception):改变程序正常执行流程的事件。处理器暂停当前任务,执行异常处理程序(异常服务例程, ESR),完成后返回原任务。
 
异常不仅包括中断,也包括错误❌(例如往程序存储区写了数据)
- 中断 (Interrupt):异常的一种,通常由外设、外部输入或软件触发。中断处理程序也称为中断服务例程 (ISR)。
 
异常类型与优先级 ❗
异常可以分为:
- 系统异常和外设异常
 
- 优先级可编程异常与优先级不可编程异常
 
其中,优先级不可编程的都是系统异常,优先级最高(为负数);其余的可编程异常优先级为正数,分为抢占和响应优先级
- 复位 (Reset):优先级 -3 (最高)。
 
- NMI (Non-Maskable Interrupt):优先级 -2。来自外部 NMI 输入脚。
 
- HardFault (硬件错误):优先级 -1。所有未被更具体错误类型捕获的错误。
 
- MemManage Fault (存储器管理错误):可编程优先级。访问 MPU 定义的非法内存区域。
 
- BusFault (总线错误):可编程优先级。指令预取或数据访问时的总线错误。
 
- UsageFault (使用错误):可编程优先级。无效指令、非法状态转换等。
 
- SVCall (系统服务调用):可编程优先级。执行 SVC 指令引发。
 
- Debug Monitor (调试监控):可编程优先级。
 
- PendSV (可挂起系统服务):可编程优先级。用于 RTOS 上下文切换。
 
- SysTick (系统节拍定时器):可编程优先级。周期性时基定时器。
 
- IRQ (外部中断):编号 0 至 239,可编程优先级。
 

4.2 异常响应过程❗
- 入栈 (Stacking):硬件自动将8个寄存器的值压入当前活动堆栈 (MSP 或 PSP):
 - xPSR, PC, LR,(R14), R12, R3, R2, R1, R0
 
NOTE THAT:
主程序被中断的地址随PC一起压入堆栈

- 取向量 (Vector Fetch):从向量表中读取对应异常服务例程的入口地址。
 
- 更新寄存器:
 - SP (栈指针) 更新为当前活动栈 (MSP 或 PSP) 的新栈顶。
 - LR (链接寄存器) 更新为特殊的 
EXC_RETURN值 ( 如0xFFFFFFF9),用于异常返回时指示返回模式和栈。 - 这样做是为了区分普通的函数调用和异常
 - PC (程序计数器) 更新为服务例程的入口地址。
 - IPSR 更新为当前异常编号。
 
4.3 异常返回
- 当异常服务例程执行完毕,通过将 
EXC_RETURN值写入 PC 来触发异常返回序列。 
- 常用的返回指令:
BX LR或POP {..., PC}(如果LR已入栈)。 

- 硬件自动出栈之前保存的寄存器,恢复处理器状态,程序从被中断处继续执行。
 
- HardFault 调试 :当进入 HardFault 时,可以通过查看当前 SP 指向的栈帧内容,特别是偏移 
0x18处 (即栈中保存的 PC 值),来定位导致错误的代码位置。 
4.4 嵌套向量中断控制器 (NVIC)❗
- 负责异常和中断的配置、优先级管理、中断屏蔽。
 
- 位于存储器映像的系统控制空间 (SCS)。
 
- 支持中断嵌套(抢占式):高优先级中断可以打断正在执行的低优先级中断服务例程。
 
- 向量化的异常/中断入口。
 
4.5 向量表❗
当Cortex内核响应了一个发生的异常后,对应的异常服务程序(ESP)会开始执行。Cortex使用了向量表查表机制决定对应的ESP的入口地址
- 该向量表实际上是一个32位整数数组,每个元素都是一个32位数,对应异常服务例程的入口地址。这个地址是可以手动编程设计的(类似51中我们
LJMP去到的真正的中断服务程序地址) 
- 向量表的位置可以通过 NVIC 的向量表偏移寄存器 (VTOR) 进行重定位。
 
- 复位后,VTOR 为0,因此在地址 0x00000000 处必须有一张有效的向量表。
 
- 向量表结构 :
 0x00: 初始 MSP 值。0x04: 复位向量。0x08: NMI 向量。0x0C: HardFault 向量。- ...以此类推,每个向量占用4字节(32bits)。
 - 异常服务例程的地址最低位必须为1,以指示 Thumb 状态。
 

4.6 复位流程❗
Step1 处理器复位 (Reset)
这可以是上电复位、手动按下复位按钮,或者由看门狗定时器等内部信号触发的系统复位。一旦复位信号有效,处理器会停止当前所有操作,进入复位状态。
Step2 读取初始MSP值 (Fetch Initial MSP Value)
复位后,处理器做的第一件事就是访问地址 0x00000000。它从这个地址读取一个32位的数据,并把这个数据加载到主堆栈指针寄存器 (MSP) 中。
- 为什么? 这一步至关重要,它确保了在执行任何代码之前,系统堆栈就已经被正确初始化。这样,即将执行的启动代码(以及后续可能发生的任何中断)就立刻拥有了一个可用的、有效的堆栈空间。
 
回忆:在51单片机中,SP的默认初始位置和工作寄存器组1是重合的,这实际上很危险,需要编程者手动调整。
- 图中,
0x00000000地址存放的值是0x20008000,这通常是片上SRAM的最高地址,因为Cortex-M的堆栈是向下生长的。 
Step3 读取复位向量 (Fetch Reset Vector)
紧接着,处理器会访问地址 0x00000004。它从这个地址读取另一个32位的数据。这个数据就是复位向量,即复位服务例程 (Reset Handler) 的入口地址。
Step4 跳转并执行启动代码 (Jump to Reset Handler)
处理器将从 0x00000004 读取到的地址值加载到程序计数器 (PC) 中,然后从这个新的PC地址开始取指令并执行。这就是系统启动代码的开始。
- 一个重要的细节:你图中标注了“最低位必须为1”。这是因为Cortex-M处理器只支持Thumb/Thumb2指令集。地址的最低位(LSB)被用作标志位(T-bit),当T-bit为1时,表示目标地址的代码是Thumb指令。实际地址是
0x00000400。 

五、Cortex-M 存储器系统
5.1 总线接口与结构
- 32位总线,4GB 存储空间,指令和数据统一编址。
 
- 哈佛结构改进:通过多条总线实现指令和数据的并行访问。
 
- 基于 AMBA (Advanced Microcontroller Bus Architecture) 总线协议:
 - AHB (Advanced High-performance Bus): 用于系统和存储器,支持流水线操作。
 - APB (Advanced Peripheral Bus): 用于连接低速外设。
 
- Cortex-M3/M4 内部总线 :
 - I-Code 总线: AHB-Lite,负责 0x00000000 - 0x1FFFFFFF (代码区) 的取指。
 - D-Code 总线: AHB-Lite,负责 0x00000000 - 0x1FFFFFFF (代码区) 的数据访问。
 - I-Code 和 D-Code 总线的存在使得代码区的取指和数据访问可以同时进行。
 - 系统总线 (S-Bus): AHB-Lite,负责其他区域 (如SRAM、外设) 的所有数据传送(包括取指和数据访问)。
 - 外部私有外设总线 (PPB): APB,负责 0xE0040000 - 0xE00FFFFF 区域的私有外设访问 (如调试组件)。
 - 调试访问端口总线 (DAP Bus)。
 
- 总线设备连接示例 (STM32) :处理器内核通过总线矩阵/复用器连接到 Flash、SRAM、外设等。
 

5.2 Flash 访问加速器 (如 STM32 ART Accelerator)
- Flash 读取通常需要等待周期,影响性能。
 
- 加速器通过指令预取、指令缓存和数据缓存来减少等待时间,提高执行速度。
 
- CCM (Core Coupled Memory) RAM (如 STM32F407) :
 - 一块与内核紧密耦合的 SRAM,通常有更快的访问速度(零等待状态)。
 - 可以直接通过 I-Code 和 D-Code 总线访问,适合存放关键代码和数据。
 
5.3 总线矩阵 (Bus Matrix)
- 连接不同速度的总线主设备 (如 CPU, DMA) 和总线从设备 (如 Flash, SRAM, 外设)。
 
- 允许多条总线同时传输数据 (例如 CPU 访问 SRAM1 的同时,DMA 控制器访问 SRAM2),提高系统并行性和吞吐量。
 
- 支持 DMA (Direct Memory Access) 操作,数据传输无需 CPU 干预。
 

5.4 位段操作 (Bit-Banding) ❗
51虽然也有位地址,但是位地址和普通地址是重合的,需要通过特殊的位指令区分;Cortex-M中,位段区、位段别名区都和普通的地址分开,因此用普通的指令就可以实现位段操作

Cortex-M的位段操作是一种高级、强大的内存映射技巧,它巧妙地通过地址转换来实现对位的操作。
- 实现方式:它并不是通过特殊的位指令,而是通过普通的字(32位)读写指令 (
LDR,STR) 来实现的。它在内存中划定了两个区域 : - 位段区 (Bit-band Region):这是你想要操作单个比特的实际内存区域。在SRAM和外设区各有一块1MB的位段区 。
 - 位段别名区 (Bit-band Alias):这是一块32MB的内存区域。对这块区域中某个字地址的访问,会被硬件自动映射为对位段区中某一个比特位的访问 。
 
1MB映射到32MB,这是因为每个字有32位
- 寻址区域:
 - 片上SRAM的起始1MB (
0x20000000-0x200FFFFF) 。 - 片上外设的起始1MB (
0x40000000-0x400FFFFF) 。 
- 操作过程:假设你想将地址 
0x40000000的第n位置1。你不需要读-改-写,而是直接向这个比特位对应的别名地址写入一个非零值。硬件会自动完成定位和修改单个比特的操作。 
- 核心优势:原子操作 (Atomic Operation) 。由于对单个位的操作是通过一次对别名区的单次总线写操作完成的,这个过程是不可中断的。
 
特性  | 80C51 位寻址  | ARM Cortex-M 位段操作  | 
实现原理  | 专用的位操作指令和布尔处理器。  | 内存地址映射。通过访问一个“别名地址”来间接操作一个比特位。  | 
使用指令  | SETB, CLR, CPL, JB 等位指令。 | 普通的字读写指令,如  LDR, STR。 | 
可操作区域  | 固定且较小(128位RAM + 部分SFR)。  | 较大(SRAM和外设区各1MB)。  | 
原子性  | 非原子操作。大部分是“读-修改-写”过程,可能被中断打断。  | 原子操作 13。对单个位的操作是不可分割的,保证了数据一致性。  | 
效率与安全性  | 编程直观,但在复杂系统中存在数据竞争风险。  | 编程稍复杂(需要计算别名地址),但操作安全可靠,特别适合实时操作系统和复杂中断场景 14。  | 
例:将1写入SRAM的0x20000000的第2位
不使用位段操作:
使用位段操作:
这两段代码都是将1写入SRAM的0x2000 0000地址的第2位,但使用位段操作的方法更简洁。
优点:位段操作是原子操作,不会被其它指令或者异常打断




