一、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位,但使用位段操作的方法更简洁。
优点:位段操作是原子操作,不会被其它指令或者异常打断