STM32再认识 - (1) Cortex®-M4
Cortex®-M4 处理器
Cortex®-M4 处理器介绍
Cortex-M4 处理器是一款专为微控制器市场设计的高性能 32 位处理器。其显著优点包括:
• 出色的处理性能与快速中断处理相结合
• 通过广泛的断点和跟踪功能增强系统调试
• 高效的处理器内核、系统和存储器
• 超低功耗,集成睡眠模式和可选的深度睡眠模式
• 平台安全稳健,具有可选的集成内存保护单元(MPU)

Cortex-M4 处理器基于高性能处理器内核构建,采用 3 级流水线哈佛架构,非常适合要求苛刻的嵌入式应用。该处理器通过高效的指令集和广泛优化的设计提供卓越的功效,提供高端处理硬件,包括可选的符合 IEEE754 标准的单精度浮点计算、一系列单周期和 SIMD 乘法以及累加乘法功能、饱和算术和专用硬件除法。
- Cortex-M3:
针对低功耗微控制器设计的处理器,面积小但是性能强劲,支持可以处理器快速处理复杂任务的丰富指令集。具有硬件除法器和乘加指令(MAC).并且,M3支持全面的调试和跟踪功能,使软件开发者可以快速的开发他们的应用- Cortex-M4:
不但具备Cortex-M3的所有功能,并且扩展了面向数字信号处理(DSP)的指令集,比如单指令多数据指令(SMID)和更快的单周期MAC操作。此外,它还有一个可选的支持IEEE754浮点标准的单精度浮点运算单元
综上所述,简单来说 Cortex-M4 是一个添加了浮点数支持的 Cortex-M3 超集。
为了促进成本敏感型设备的设计,Cortex-M4 处理器实现了紧密耦合的系统组件,可减少处理器面积,同时显着提高中断处理和系统调试功能。 Cortex-M4 处理器实现了基于 Thumb-2 技术的 Thumb® 指令集版本,确保了高代码密度并降低了程序内存要求。 Cortex-M4 指令集提供了现代 32 位架构所期望的卓越性能,以及 8 位和 16 位微控制器的高代码密度。
Cortex-M4 处理器紧密集成了可配置的嵌套向量中断控制器 (NVIC),可提供业界领先的中断性能。 NVIC 包括不可屏蔽中断 (NMI),可提供多达 256 个中断优先级。处理器内核和 NVIC 的紧密集成提供了中断服务程序 (ISR) 的快速执行,从而显着减少了中断延迟。这是通过寄存器的硬件堆栈以及暂停多次加载和多次存储操作的能力来实现的。中断处理程序不需要包装在汇编代码中,从而消除了 ISR 中的任何代码开销。尾链优化还可以显着减少从一个 ISR 切换到另一个 ISR 时的开销。
为了优化低功耗设计,NVIC 集成了睡眠模式,其中包括可选的深度睡眠功能。这使得整个设备能够快速断电,同时仍保留程序状态。
处理器内核架构
Cortex-M3 和 Cortex-M4 处理器基于 ARMv7-M 架构。
最初的 ARMv7-M 架构是在 Cortex-M3 处理器开发时定义的。当 Cortex-M4 发布时,该架构进行了扩展,包含了额外的指令和架构功能。该扩展架构有时称为 ARMv7E-M 架构。ARMv7-M 和 ARMv7E-M 功能均记录在同一架构规范文档中:ARMv7-M 架构参考手册。
ARMv7-M 架构参考手册是一份超过 1000 页的庞大文档。它提供了处理器行为的非常详细的架构要求,从指令集、内存系统到调试支持。虽然它对于处理器设计人员、C 编译器设计人员和开发工具等专家很有用,但该文档并不容易阅读,尤其是是对于刚接触 ARM 架构的读者来说。
编程模型
从程序的可访问级别来看,可分为特权级与非特权级:
-
特权级:
该程序可以使用所有指令并可以访问所有资源。 -
非特权级:
- 对 MSR 和 MRS 指令的访问受到限制,并且不能使用 CPS 指令。
- 无法访问系统定时器、NVIC 或系统控制块。
- 对内存或外围设备的访问可能受到限制。
软件可以将特权模式下的处理器切换为非特权模式,但它无法将自身从非特权状态切换回特权状态。如果需要返回特权模式,处理器必须使用异常来进行切换。
特权和非特权访问级别的分离,使系统设计人员可以在开发嵌入式系统时实现安全机制,通过提供基本的安全模型来保护对关键区域的内存访问。
除了内存及特殊指令集访问权限的差异以外,非特权级与特权级几乎具有相同的访问权限。
例如,系统可以包含一个在私有环境中执行的嵌入式操作系统内核,同时在为执行的应用程序任务时设置合理的访问级别。
这样我们就可以利用内存保护 (MPU) 来设置内存访问权限,用于防止应用程序损坏内存和由操作系统内核及其他任务所使用的外设单元。若应用程序任务崩溃,其余的应用程序任务和操作系统内核仍然可以继续运行。

从处理器的运行时来看,包含两种可能的工作状态与两种工作模式:
-
Thumb State:
当处理器正在运行程序代码(Thumb 指令)时,则称它处于 Thumb 状态。与 ARM7TDMI 等经典 ARM 处理器不同,没有 ARM 状态,因为 Cortex-M 处理器不支持 ARM 结构集。
此时,处理器可能处于两种模式:
-
Handler Mode:
用于处理异常。
在该模式下,处理器永远具有特权访问级别。当处理器进行异常处理(如 ISR)时,会进入 Handler Mode ;退出该模式时,将返回线程模式,在此之前应完成全部异常处理。 -
Thread Mode:
用于执行应用软件。
在该模式下,处理器处于特权访问级别还是非特权访问级别是由软件控制(CONTROL 寄存器)的。当处理器复位后,将先进入处于特权访问级别的线程模式。
-
-
Debug State:
当处理器停止时(例如,由调试器停止,或者在点击断点),则称处理器进入调试状态。此时处理器停止执行指令。
与访问级别同样,Thread 模式和 Handler 模式也是相似的。
值得注意的是,线程模式下处理器可以将堆栈指针切换为单独的影子堆栈指针。这允许应用程序任务使用独立的堆栈内存,从而实现更优的系统可靠性。
在很多简单应用中,没有必要使用非特权的线程模型和影子堆栈指针。例如,在 Cortex-M0 处理器不具有非特权线程模式;但在 Cortex-M0+ 中是可选的。
调试状态仅用于调试操作。该状态由来自调试器或来自调试组件(调试事件)的停止请求触发。
该状态允许调试器访问或更改处理器寄存器值。无论是在 Thumb 状态或是调试状态下,全部系统内存都可以由调试器访问。
堆栈
处理器使用完整的降序堆栈。
降序堆栈: 在计算机体系结构中,堆栈向较低内存地址增长,即每次入栈(push)时,栈指针(SP)会减小。
处理器硬件上实现了两个堆栈,即主堆栈和进程堆栈(即上文的影子堆栈)。每个堆栈都有一个指针保存在相互独立的 SP 寄存器中。
在线程模式下,CONTROL 寄存器控制处理器是使用主堆栈还是进程堆栈。在处理程序模式下,处理器始终使用主堆栈。
也就是说,处于进程模式时的处理器具有 种可能的状态。
内核寄存器
总览
与几乎所有其他处理器类似,Cortex-M3 和 Cortex-M4 处理器在处理器内核内部有许多寄存器来执行数据处理和控制。
大多数这些寄存器都分组在一个称为寄存器组的单元中。每个数据处理指令指定所需的操作、源寄存器和目标寄存器(如果适用)。在ARM架构中,如果要处理内存中的数据,则必须将其从内存加载到寄存器组中的寄存器,在处理器内部进行处理,然后在需要时写回内存。 这通常称为“加载-存储架构”。通过在寄存器组中具有足够数量的寄存器,这种布置易于使用,并且允许使用C编译器生成高效的程序代码。例如,在进行其他数据处理时,可以在寄存器组中短期存储多个数据变量,而无需在每次使用时更新到系统内存并读回。

| Name | Type | Required privilege | Reset value |
|---|---|---|---|
| R0-R12 | RW | Either | Unknown |
| MSP | RW | Privileged | See description |
| PSP | RW | Either | Unknown |
| LR | RW | Either | 0xFFFFFFFF |
| PC | RW | Either | See description |
| PSR | RW | Privileged | 0x01000000 |
| ASPR | RW | Either | Unknown |
| IPSR | RO | Privileged | 0x00000000 |
| EPSR | RO | Privileged | 0x01000000 |
| PRIMASK | RW | Privileged | 0x00000000 |
| FAULTMASK | RW | Privileged | 0x00000000 |
| BASEPRI | RW | Privileged | 0x00000000 |
| CONTROL | RW | Privileged | 0x00000000 |
type 描述了 Thumb State 下程序执行时的访问类型。Debug State访问可能有所不同。
寄存器组
通用寄存器(R0-R12)
R0 - R12是通用寄存器。
R0 - R7 也称为低位寄存器。由于指令集中可用空间有限,许多16位指令只能访问低位寄存器。
R8 - R12 也称为高位寄存器。高位寄存器可与 32 位指令一起使用,少数寄存器可与 16 位指令一起使用,例如 MOV 。
R0-R12的初始值未定义
堆栈指针(R13)
寄存器 R13 被称为堆栈指针(Stack Pointer, SP)。它用于通过 PUSH 和 POP 操作访问堆栈内存。物理上有两个不同的堆栈指针:
- MSP(主堆栈指针)或某些 ARM 文档中的 SP_main 是默认堆栈指针。在复位后或处理器处于 Handle Mode 时,只能使用 MSP 。
- PSP(进程堆栈指针),或某些 ARM 文档中的 SP_process 只能在线程模式下使用。
堆栈指针的选择由 CONTROL[1] 决定,在某一时刻,有且仅有一个堆栈指针是被使用的。
尽管 MSP 和 PSP 都是 32 位寄存器,但堆栈指针(MSP 或 PSP)的最低两位始终为零,并且忽略对这两位的写入。
在 ARM Cortex-M 处理器中,PUSH 和 POP 始终为 32 位,并且堆栈操作中的传输地址必须与 32 位字边界对齐。换句话说,如果不需要特殊的溢出控制,运行在 CortexM4 上的程序的局部变量只推荐 int32 类型。
PSP 的初始值未定义,MSP 的复位值来自 0x00000000 。(见 bootloader 分析)
连接寄存器(R14)
寄存器 R14 被称为链接寄存器(Link Register, LR)。该寄存器被用于在调用函数或子程序时保存返回地址。当函数或子程序结束时,程序控制可以返回到调用程序,并通过将 LR 的值加载到程序计数器 (PC) 来恢复。
当调用函数或子程序时,LR 的值会自动更新。如果一个函数需要调用另一个函数或子程序,则必须先将LR的值保存在堆栈中。否则,当函数调用时,LR中的当前值将丢失。
在异常处理期间,LR 也会自动更新为一个特殊的 EXC_RETURN(异常返回)值,然后用于在异常处理程序结束时触发异常返回。这将后续文章中更深入地讨论。
尽管 Cortex-M 处理器中的返回地址值始终是偶数(位 0 为零,因为指令必须与半字地址对齐),但 LR 的位 0 是可读可写的。某些分支/调用操作要求将 LR(或任何正在使用的寄存器)的位 0 设置为 1 以指示 Thumb 状态。
LR 的复位值为 0xFFFFFFFF 。
程序计数器(R15)
寄存器 R15 被称为程序计数器(Program Counter, PC)。它包含当前程序地址。
该寄存器是可读可写的:
- 读取时,返回当前指令地址加 4(这是由于设计的流水线性质以及与 ARM7TDMI 处理器的兼容性要求)。
- 写入时,(例如,使用数据传输/处理指令)会导致分支操作。
由于指令必须与半字或字地址对齐,因此 PC 的最低有效位 (LSB) 为零。
❗ 需要注意的是,当使用某些分支/内存读指令更新 PC 时,需要将新 PC 值的 LSB 设置为 1 以指示 Thumb 状态。否则,可能会触发故障异常,因为它表示尝试切换到使用 ARM 指令(即 ARM7TDMI 中的 32 ARM 指令),而这是不受支持的。在高级编程语言(包括C、C++)中,分支目标中LSB的设置由编译器自动处理。
在大多数情况下,分支和调用由专用于此类操作的指令处理。使用数据处理指令来更新 PC 的情况不太常见。然而,PC 的值对于访问存储在程序存储器中的文字数据很有用。因此,你经常会发现以 PC 作为基址寄存器的内存读操作,其地址偏移量是由指令中的立即数生成的。
复位时,处理器将位于 0x00000004 的值加载到 PC 。同时,该值的 Bit[0] (必须为 1)也会被加载至 EPSR T-bit 。
特殊寄存器
除了寄存器组中的寄存器外,还有许多特殊寄存器(Special registers)。这些寄存器包含处理器状态并定义操作状态以及中断/异常屏蔽。
在使用 C 等高级编程语言开发简单应用程序时,需要访问这些寄存器的场景并不多。但是,开发嵌入式操作系统或需要高级中断屏蔽功能时需要使用它们。
特殊寄存器不是内存映射的,可以使用特殊寄存器访问指令(例如 MSR 和 MRS)进行访问。
程序状态寄存器(PSR)
程序状态寄存器由三个状态寄存器组成:
- 应用程序状态寄存器(APSR)
- 中断程序状态寄存器(IPSR)
- 执行程序状态寄存器(EPSR)
这三个寄存器互斥的位域共同组成了 32-bit PSR 。因此,可以通过 PSR ,IEPSR/IAPSR/EAPSR 和 APSR/EPSR/IPSR 访问任意个寄存器。
因此,PSR 也常常记作 xSPR 。

参见《DUI0553》P2-4 。
| APSR | |
|---|---|
| N | 负标志 |
| Z | 零标志 |
| C | 进位/借位标志(Carry or borrow flag) |
| V | 溢出标志 |
| Q | DSP 溢出/饱和标志 |
| GE[3:0] | 大于/等于标志 |
| IPSR | |
|---|---|
| ISR_NUMBER | 当前异常的编号 |
| 0 = Thread mode | |
| 1 = Reserved | |
| 2 = NMI | |
| 3 = HardFault | |
| 4 = MemManage | |
| 5 = BusFault | |
| 6 = UsageFault | |
| 7-10 = Reserved | |
| 11 = SVCall | |
| 12 = Reserved for Debug | |
| 13 = Reserved | |
| 14 = PendSV | |
| 15 = SysTick | |
| 16 = IRQ0. | |
| ⋮ | |
| n+15 = IRQ(n-1) | |
| EPSR | |
|---|---|
| ICI | Interruptible-continuable instruction bits |
| IT | Indicates the execution state bits of the IT instruction |
| T | Thumb state bit |
异常屏蔽寄存器组(EMR)
异常屏蔽寄存器(Exception Mask Registers, EMR)用于根据优先级屏蔽异常。该组寄存器包含三个 32-bits 寄存器,分别为:
-
Priority Mask Register, PRIMASK
PRIMASK 寄存器是一个 1 位宽的中断屏蔽寄存器。
设置后,它会阻止除不可屏蔽中断 (Non-Maskable Interrupt, NMI) 和 HardFault 异常之外的所有异常(包括中断)。实际上,它将当前异常优先级提高到 0,这是可编程异常/中断的最高级别。
PRIMASK 最常见的用法是禁用时间关键进程的所有中断。时间关键过程完成后,需要清除 PRIMASK 以重新启用中断。 -
Fault Mask Register, FAULTMASK
FAULTMASK 寄存器与 PRIMASK 非常相似,但它也阻止 HardFault 异常,从而有效地将当前异常优先级提高到 -1。故障处理代码可以使用 FAULTMASK 来抑制在故障处理期间触发更多故障(仅其中几种类型)。
例如,FAULTMASK 可用于绕过 MPU 或抑制总线故障(这些是可配置的)。这可能使错误处理代码更容易执行补救操作。与 PRIMASK 不同,FAULTMASK 在异常返回时自动清除。 -
Base Priority Mask Register, BASEPRI
为了实现更灵活的中断屏蔽,ARMv7-M架构还提供了BASEPRI,它可以根据优先级屏蔽异常或中断。 BASEPRI 寄存器的宽度取决于设计中实现的优先级数量,这由微控制器供应商确定。大多数 Cortex-M3 或 Cortex-M4 微控制器具有 8 或 16 个可编程异常优先级,在这些情况下,BASEPRI 的宽度将分别为 3 位或 4 位。
当 BASEPRI 设置为 0 时,它被禁用。当它设置为非零值时,它会阻止具有相同或较低优先级的异常(包括中断),同时仍然允许处理器接受具有较高优先级的异常。

每个异常(包括中断)都有一个优先级,数字越小,优先级越高,数字越大,优先级越低。
们只能在特权访问级别进行访问(在非特权状态下,对这些寄存器的写入将被忽略,读取将返回零)。
默认情况下,它们全部为零,这意味着任何异常/中断都不会被屏蔽。
控制寄存器

| EPSR | ||
|---|---|---|
| [2] | FPCA |
浮点上下文活动
异常处理机制使用该位来确定发生异常时是否需要保存浮点单元中的寄存器。
当该位为0(默认)时,当前上下文中尚未使用浮点单元,因此不需要保存浮点寄存器;当该位为1时,当前上下文已使用浮点指令,因此需要保存浮点寄存器。
当执行浮点指令时,FPCA 位自动置位。该位在异常进入时由硬件清除。有多种方法可用于处理浮点寄存器的保存,这些方法将在后文展开。
|
| [1] | SPSEL |
定义线程模式下的堆栈指针选择:
当该位为 0(默认)时,线程模式使用主堆栈指针 (MSP);当该位为 1 时,线程模式使用进程堆栈指针 (PSP)。
在处理程序模式下,该位始终为 0,并且忽略对此位的写入。
|
| [0] | nPRIV |
定义线程模式下的特权级别:
当该位为 0(默认)时,处于线程模式时为特权级别;当该位为 1 时,在线程模式下无特权。
在处理程序模式下,处理器始终处于特权访问级别。
|
浮点寄存器
浮点单元 (Floating Point Unit,FPU)是 Cortex-M4 的可选组成部分。
- FPU 完全支持单精度加、减、乘、除、乘和累加以及平方根运算。它还提供定点和浮点数据格式以及浮点常量指令之间的转换。
- FPU 提供符合 ANSI/IEEE Std 754-2008、IEEE 二进制浮点算术标准(称为 IEEE 754 标准)的浮点计算功能。
- FPU 包含 32 个单精度扩展寄存器,您也可以将其作为 16 个双字寄存器进行访问,以进行加载、存储和移动操作。

Coprocessor Access Control Register
Floating-point Context Control Register
Floating-point Context Address Register
Floating-point Status Control Register
🤪 不想写了,自己读参考文献吧。(逃 ε=ε=ε=┏(゜ロ゜;)┛
参考文献
- 《The Definitive Guide to ARM Cortex®-M3 and Cortex®-M4 Processors(Third Edition)》
- 《Cortex®-M4 Devices Generic User Guide》
- 《Cortex®-M4 Technical Reference Manual》
- ARM Cortex-M 处理器家族介绍和比较
