Cortex-M4内核参考手册笔记-核心外设

4.1 STM32 Cortex-M4核心外设概述

私有外设总线(PPB)的地址映射如下:

在寄存器描述中:

  • 寄存器类型定义如下:

    • RW:可读写

    • RO:只读

    • WO:只写

  • 访问权限表示访问寄存器所需的特权级别:

    • Privileged(特权):仅特权软件可访问该寄存器

    • Unprivileged(非特权):非特权和特权软件均可访问该寄存器

4.2 存储器保护单元(MPU)

本节介绍某些 STM32 微控制器中实现的内存保护单元(MPU)。请参考相应设备的数据手册,确认您使用的 STM32 型号是否支持 MPU。

MPU 将内存映射划分为多个区域,并定义每个区域的地址范围、大小、访问权限和内存属性。其功能包括:

  • 支持为每个区域独立设置属性

  • 支持区域重叠

  • 将内存属性导出至系统

内存属性会影响对区域的内存访问行为。Cortex-M4 的 MPU 支持:

  • 8 个独立内存区域(0-7)

  • 1 个背景区域

当内存区域发生重叠时,内存访问行为由编号最大的区域属性决定。例如,区域7的属性将覆盖任何与之重叠区域的属性。

背景区域具有与默认内存映射相同的访问属性,但仅允许特权软件访问。

Cortex-M4的MPU采用统一内存映射架构,这意味着指令访问和数据访问共享相同的区域设置。

如果程序访问被MPU禁止的内存地址,处理器将触发内存管理故障(Memory Management Fault),引发故障异常,在操作系统环境中可能导致进程终止。

在操作系统环境下,内核可根据待执行进程动态更新MPU区域设置。典型情况下,嵌入式操作系统会利用MPU实现内存保护功能。

MPU区域配置基于内存类型实现,详见第29页第2.2.1节《内存区域、类型与属性》。

 表38. 内存属性摘要

内存类型共享性其他属性描述
Strongly-ordered - - 对该类内存的所有访问严格按程序顺序执行,默认视为共享区域
Device Shared - 多处理器共享的内存映射外设区域
  Non-shared - 单处理器独占的内存映射外设区域
Normal Shared Non-cacheable/Write-through/Write-back 多处理器共享的普通内存区域(支持非缓存/透写/回写模式)
  Non-shared Non-cacheable/Write-through/Write-back 单处理器独占的普通内存区域(支持非缓存/透写/回写模式)

 

4.2.1 MPU访问权限属性

本节描述MPU访问权限属性。MPU_RASR寄存器中的访问权限位(TEX、C、B、S、AP和XN)控制对应内存区域的访问。如果访问未获得权限的内存区域,MPU将触发权限错误。

表39. TEX/C/B/S位编码对照表

 

TEXC位B位S位内存类型共享性附加属性说明
0 0 - Strongly-ordered 强制共享 严格按序执行
  1 - Device 共享模式 用于多核外设访问
b000 0 0 0 Normal 非共享 内外层透写,无写分配
  1 1 1   共享模式  
  1 0 0 Normal 非共享 内外层回写,无写分配
b001 0 0 0 Normal 非共享 内外层非缓存模式
  - 1 1   共享模式  
b010 0 0 Device 非共享 独占设备内存
b1BB A A 0 Normal 非共享 缓存内存(BB=外层策略,AA=内层策略)

注1:该位数值被MPU忽略
注2:AA/BB位定义参见表40

表40. 缓存策略编码(TEX=4~7时适用)

 

编码(AA/BB)缓存策略
00 非缓存模式
01 回写模式,带读写分配
10 透写模式,无写分配
11 回写模式,无写分配

表41. AP权限编码对照表

AP[2:0]特权级权限非特权级权限功能说明
000 禁止访问 禁止访问 所有访问均触发权限错误
001 读写 禁止访问 仅允许特权级软件访问
010 读写 只读 非特权级写操作触发权限错误
011 读写 读写 完全开放访问权限
100 未定义 未定义 保留编码
101 只读 禁止访问 仅允许特权级软件读取
110 只读 只读 允许所有软件读取
111 只读 只读 允许所有软件读取(同110)

 

4.2.2 MPU权限冲突

当访问违反MPU权限设置时:

  1. 处理器触发内存管理错误(详见第26页2.1.4节《异常与中断》)

  2. 错误状态寄存器(MMFSR)记录具体错误原因

  3. 错误地址可通过内存管理错误地址寄存器(MMFAR)查询(详见第242页4.4.15节)

4.2.3 MPU区域更新方法

要更新MPU区域的属性,需要更新MPU_RNR、MPU_RBAR和MPU_RASR寄存器。
您可以分别对每个寄存器进行编程,或者使用多字写入对所有这些寄存器进行编程。
您可以使用MPU_RBAR和MPU_RASR别名,使用一个STM指令同时对最多四个区域进行编程。

 

单寄存器写入(基础方法):

 

; R1=区域编号 R2=大小/使能位 R3=属性 R4=基址
LDR R0,=MPU_RNR      ; 加载MPU区域编号寄存器地址(0xE000ED98)
STR R1,[R0,#0x0]     ; 写入区域编号
STR R4,[R0,#0x4]     ; 写入基址
STRH R2,[R0,#0x8]    ; 写入区域大小及使能位
STRH R3,[R0,#0xA]    ; 写入属性配置

在向MPU写入新的区域设置之前,如果先前已启用要更改的区域,请先禁用该区域。例如:

软件必须使用内存屏障指令:

  • 在MPU设置之前,如果可能存在未完成的内存传输(如缓冲写入)可能受MPU设置更改的影响。

  • 在MPU设置之后,如果其中包含必须使用新MPU设置的内存传输。
    然而,如果MPU设置过程以进入异常处理程序开始,或后跟异常返回,则不需要内存屏障指令,因为异常进入和异常返回机制会引发内存屏障行为。
    软件在MPU设置期间不需要任何内存屏障指令,因为它通过PPB(一种强序内存区域)访问MPU。

例如,如果希望所有内存访问行为在编程序列后立即生效,可使用DSB指令和ISB指令:

  • 更改MPU设置后(如上下文切换结束时)需要DSB指令。

  • 如果通过分支或调用进入编程MPU区域的代码,则需要ISB指令。如果编程序列是通过异常返回或触发异常进入的,则不需要ISB指令。

使用多字写入更新MPU区域

根据信息划分方式,可以直接使用多字写入编程。考虑以下重新编程示例:

; R1 = 区域编号
; R2 = 地址
; R3 = 大小和属性(合并为一个值)
LDR R0, =MPU_RNR ; 0xE000ED98,MPU区域编号寄存器
STR R1, [R0, #0x0] ; 区域编号
STR R2, [R0, #0x4] ; 区域基地址
STR R3, [R0, #0x8] ; 区域属性、大小与启用

使用STM指令优化:

; R1 = 区域编号
; R2 = 地址
; R3 = 大小和属性(合并为一个值)
LDR R0, =MPU_RNR ; 0xE000ED98,MPU区域编号寄存器
STM R0, {R1-R3} ; 区域编号、地址、属性、大小与启用

对于预打包信息,可以用两个字完成。这意味着RBAR(MPU区域基地址寄存器)包含所需的区域编号,并将VALID位设为1(参见第203页的MPU_RBAR说明)。此方法适用于静态打包的数据,例如在引导加载程序中:

; R1 = 地址与区域编号合并为一个值
; R2 = 大小与属性合并为一个值
LDR R0, =MPU_RBAR ; 0xE000ED9C,MPU区域基地址寄存器
STR R1, [R0, #0x0] ; 区域基地址与区域编号组合,且VALID位(第4位)设为1
STR R2, [R0, #0x4] ; 区域属性、大小与启用

使用STM指令优化:

; R1 = 地址与区域编号合并为一个值
; R2 = 大小与属性合并为一个值
LDR R0,=MPU_RBAR ; 0xE000ED9C,MPU区域基地址寄存器
STM R0, [R1-R2] ; 区域基地址、区域编号及VALID位,
; 以及区域属性、大小与启用

子区域

256字节或更大的区域会被划分为8个等大小的子区域。通过设置RASR(MPU区域属性与大小寄存器)中的SRD字段的相应位来禁用一个子区域(详见第204页第4.2.9节)。SRD的最低有效位控制第一个子区域,最高有效位控制最后一个子区域。禁用一个子区域意味着重叠该禁用范围的另一个区域将生效。如果没有其他已启用的区域覆盖禁用的子区域,MPU会触发故障。

32、64和128字节的区域不支持子区域。对于这些大小的区域,必须将SRD字段设为0x00,否则MPU行为将不可预测。

SRD使用示例:

两个具有相同基地址的区域重叠。区域一为128KB,区域二为512KB。为确保区域一的属性应用于前128KB范围,需将区域二的SRD字段设为b00000011以禁用前两个子区域,如图所示。

图18. 子区域示例

4.2.4 MPU设计提示与技巧

为避免意外行为,在更新中断处理程序可能访问的区域属性前,请先禁用中断。

确保软件使用正确大小的对齐访问来操作MPU寄存器:

  • 除RASR外,必须使用对齐的字访问(word accesses)

  • 对于RASR,可使用字节、对齐的半字或字访问

处理器不支持对MPU寄存器的非对齐访问。

配置MPU时,若MPU之前已编程过,请禁用未使用的区域,以防止旧的区域设置影响新的MPU配置。


推荐的MPU配置

STM32微控制器系统为单处理器架构,MPU应按以下方式编程:

 

表42. STM32内存区域属性

内存区域TEXCBS内存类型与属性
Flash存储器 b000 1 0 0 普通内存,非共享,写透传(write-through)
内部SRAM b000 1 0 1 普通内存,共享,写透传
外部SRAM b000 1 1 1 普通内存,共享,写回(write-back)且写分配
外设 b000 0 1 1 设备内存,共享

在STM32实现中,共享性和缓存策略属性不影响系统行为,但为MPU区域设置这些属性可增强代码的可移植性。表中值为典型场景推荐值。

注意:MPU属性不会影响DMA对内存/外设地址空间的访问。因此,为防止DMA意外访问受保护内存区域,MPU必须控制软件/CPU对DMA寄存器的访问。

4.2.5 MPU类型寄存器(MPU_TYPER)

 MPU_TYPER寄存器用于指示MPU是否存在及其支持的区域数量。

 

寄存器位域结构

位域名称类型描述
31:24 保留 - 保留位
23:16 IREGION[7:0] r MPU指令区域数量(恒为0x00,MPU采用统一内存映射,实际区域数由DREGION决定)
15:8 DREGION[7:0] r MPU数据区域数量:
• 0x08:支持8个区域
• 0x00:无MPU
7:1 保留 - 保留位
0 SEPARATE r 内存映射类型标志位:
• 0 = 统一指令/数据内存映射
• 1 = 分离指令/数据内存映射

4.2.6 MPU控制寄存器(MPU_CTRL)

 

MPU_CTRL寄存器功能:

  • 启用MPU

  • 启用默认内存映射背景区域

  • 在硬错误(Hard Fault)、不可屏蔽中断(NMI)及FAULTMASK升级处理程序中启用MPU

关键控制逻辑

  1. 当ENABLE与PRIVDEFENA同时置1时:

    • 特权访问:未命中已启用区域时,按第28页第2.2节"内存模型"的默认内存映射处理

    • 非特权访问:未命中已启用区域时将触发内存管理故障

  2. XN(执行永不)与强序规则:

    • 始终适用于系统控制空间(SCS),与ENABLE位状态无关

  3. 启用条件:

    • ENABLE=1时,必须至少启用一个内存区域(除非PRIVDEFENA=1)

    • PRIVDEFENA=1且无区域启用时,仅允许特权软件运行

  4. 禁用状态(ENABLE=0):

    • 系统使用默认内存映射(属性等同于未实现MPU,参见第30页表13)

    • 默认映射对特权/非特权软件均有效

  • MPU启用时:

    • 系统控制空间和向量表访问始终允许

    • 其他区域访问取决于:

      • 已配置区域

      • PRIVDEFENA位状态

  1. 异常处理优先级:

    • HFNMIENA=0时,处理器处理优先级-1或-2的异常(硬错误/NMI/FAULTMASK启用时)会禁用MPU

    • HFNMIENA=1时允许MPU在这些优先级下运行

 

位 31:3 保留,硬件强制置0。

位 2 PRIVDEFENA(特权默认使能): 启用特权软件对默认内存映射的访问。

0:若MPU已启用,则禁用默认内存映射。任何未被已启用区域覆盖的内存访问将触发故障。
1:若MPU已启用,则启用默认内存映射作为特权软件访问的背景区域。

注:启用时,背景区域的行为类似于编号为-1的区域。任何已定义并启用的区域优先级均高于此默认映射。若MPU被禁用,处理器将忽略此位。

位 1 HFNMIENA(硬故障/NMI使能): 在硬故障、NMI及FAULTMASK处理程序期间启用MPU操作。当MPU启用时:

0:在硬故障、NMI及FAULTMASK处理程序期间禁用MPU,无论ENABLE位的值如何。
1:在硬故障、NMI及FAULTMASK处理程序期间启用MPU。

注:若MPU被禁用时此位设置为1,行为不可预测。

位 0 ENABLE(启用): 启用MPU

0:MPU禁用
1:MPU启用

4.2.7 MPU区域编号寄存器(MPU_RNR)

 MPU_RNR寄存器用于指定当前通过MPU_RBAR和MPU_RASR寄存器操作的目标内存区域。

Bits 31:8 Reserved, forced by hardware to 0.
Bits 7:0 REGION[7:0]: MPU region
这些位指示由MPU_RBAR和MPU_RASR寄存器引用的MPU区域。MPU支持8个内存区域,因此该字段的允许值为0-7。
通常情况下,在访问MPU_RBAR或MPU_RASR之前,需将所需的区域编号写入此寄存器。但也可以通过向MPU_RBAR寄存器写入VALID位设置为1的值来更改区域编号,具体参见《MPU区域基地址寄存器(MPU_RBAR)》。此操作会更新REGION字段的值。

 

4.2.8 MPU区域基地址寄存器(MPU_RBAR)

 MPU_RBAR寄存器用于定义由MPU_RNR寄存器选定的MPU区域的基地址,并可更新MPU_RNR寄存器的值。
通过向MPU_RBAR寄存器写入VALID位设置为1的值,可更改当前区域编号并更新MPU_RNR寄存器。

 

寄存器位域说明

位域名称类型描述
31:N ADDR[31:N] rw 区域基地址字段
      - N值取决于区域大小(由MPU_RASR中的SIZE字段指定):N = Log₂(区域字节数)
      - 若区域大小配置为4 GB(通过MPU_RASR),则无有效ADDR字段,此时区域占用完整内存映射,基地址为0x00000000
      - 基地址需按区域大小对齐(例如64 KB区域必须在64 KB倍数地址,如0x00010000或0x00020000)
N-1:5 保留 - 硬件强制置0
4 VALID rw MPU区域编号有效位
      写入时:
      - 0:不修改MPU_RNR寄存器,处理器:
      • 更新MPU_RNR指定区域的基地址
      • 忽略REGION字段的值
      - 1:处理器:
      • 将MPU_RNR更新为REGION字段的值
      • 更新REGION字段指定区域的基地址
      读取时: 恒为0
3:0 REGION[3:0] rw MPU区域编号字段
      - 写入行为参见VALID字段说明
      - 读取时返回MPU_RNR寄存器指定的当前区域编号

4.2.9 MPU区域属性和大小寄存器(MPU_RASR)

MPU_RASR寄存器用于定义由MPU_RNR指定的MPU区域的区域大小和内存属性,并启用该区域及其子区域。
MPU_RASR支持字或半字访问:

    • 高半字(31:16位)存储区域属性

    • 低半字(15:0位)存储区域大小、区域及子区域使能位。

 

位域详解

位域名称类型描述
31:29 保留 - 硬件强制置0
28 XN rw 指令访问禁止位:0=允许指令获取;1=禁止指令获取
27 保留 - 硬件强制置0
26:24 AP[2:0] rw 访问权限控制,详见第4章核心外设及第196页表41
23:22 保留 - 硬件强制置0
21:19 TEX[2:0] rw 内存属性配置,详见第195页表39
18 S rw 可共享内存属性,详见第195页表39
17 C rw 内存属性
16 B rw 内存属性
15:8 SRD[7:0] rw 子区域禁用位:0=启用对应子区域;1=禁用对应子区域(详见第198页)
      注:128字节及以下的区域不支持子区域,此时SRD字段应写为0x00
7:6 保留 - 硬件强制置0
5:1 SIZE rw MPU保护区域大小,最小允许值为3(b00010)
0 ENABLE rw 区域使能位

SIZE字段取值规则

区域大小(字节)= 2(SIZE+1)2(SIZE+1)
最小允许区域大小为32B(对应SIZE=4),下表为示例:

表43. SIZE字段示例值

SIZE值区域大小N值(1)(1)说明
b00100 (4) 32B 5 允许的最小尺寸
b01001 (9) 1KB 10 -
b10011 (19) 1MB 20 -
b11101 (29) 1GB 30 -
b11111 (31) 4GB b01100 允许的最大尺寸

注1:N值用于MPU_RBAR寄存器,详见第203页4.2.8节。

4.2.10 MPU寄存器映射图

4.3 嵌套向量中断控制器(NVIC)

本节介绍嵌套向量中断控制器(NVIC)及其使用的寄存器。NVIC支持以下功能:

  • 最多240个中断

  • 每个中断可编程优先级为0-15,数值越大优先级越低,因此0级为最高中断优先级

  • 中断信号的电平与脉冲检测

  • 动态重设中断优先级

  • 将优先级值分组为组优先级和子优先级字段

  • 中断尾链

  • 外部不可屏蔽中断(NMI)

处理器在异常进入时自动保存状态,异常退出时自动恢复状态,无需指令开销,从而实现了低延迟的异常处理。NVIC寄存器的硬件实现如下:

 注:中断数量取决于具体产品型号,请参考相关STM32产品的参考手册或数据手册以获取详细信息。

4.3.1 使用 CMSIS 访问 Cortex-M4 NVIC 寄存器

 CMSIS函数实现了不同Cortex-M系列处理器之间的软件可移植性。在使用CMSIS访问NVIC寄存器时,可使用以下函数:

 

表46. CMSIS访问NVIC函数

CMSIS函数(1)(1)描述
void NVIC_EnableIRQ(IRQn_Type IRQn) 启用一个中断或异常。
void NVIC_DisableIRQ(IRQn_Type IRQn) 禁用一个中断或异常。
void NVIC_SetPendingIRQ(IRQn_Type IRQn) 将中断或异常的挂起状态设置为1。
void NVIC_ClearPendingIRQ(IRQn_Type IRQn) 将中断或异常的挂起状态清除为0。
uint32_t NVIC_GetPendingIRQ(IRQn_Type IRQn) 读取中断或异常的挂起状态。若挂起状态为1,则返回非零值。
void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority) 设置可配置优先级的中断或异常的优先级为1。
uint32_t NVIC_GetPriority(IRQn_Type IRQn) 读取可配置优先级的中断或异常的优先级。该函数返回当前优先级值。
  1. 输入参数IRQn为IRQ编号。具体的“n”取值范围取决于产品型号,请参考相关STM32产品的参考手册或数据手册以获取详细信息。

4.3.2 中断使能设置寄存器 x(NVIC_ISERx)

寄存器位分配:

  • NVIC_ISER0 的位 0 至 31 分别对应中断 0 至 31

  • NVIC_ISER1 的位 0 至 31 分别对应中断 32 至 63

  • ......

  • NVIC_ISER6 的位 0 至 31 分别对应中断 192 至 223

  • NVIC_ISER7 的位 0 至 15 分别对应中断 224 至 239

 

位域功能说明:

  • 位 31:0 SETENA:中断使能设置位

    • 写入操作:

      • 0:无作用

      • 1:使能对应中断

    • 读取操作:

      • 0:中断未使能

      • 1:中断已使能

功能说明:

  • 若一个挂起的中断被使能,NVIC 将根据其优先级激活该中断。

  • 若中断未使能,即使其信号被触发,状态会变为挂起,但 NVIC 永远不会激活该中断(无论优先级如何)。

  • NVIC_ISER7 寄存器的位 16 至 31 为保留位。

注:中断数量取决于具体产品型号,请参考相关 STM32 产品的参考手册或数据手册以获取详细信息。

4.3.3 中断使能清除寄存器 x(NVIC_ICERx)

寄存器位分配:

  • NVIC_ICER0的位0至31分别对应中断0至31

  • NVIC_ICER1的位0至31分别对应中断32至63

  • ......

  • NVIC_ICER6的位0至31分别对应中断192至223

  • NVIC_ICER7的位0至15分别对应中断224至239

位域功能说明:

  • 位31:0 CLRENA:中断使能清除位(rc_w1类型)

    • 写入操作:

      • 0:无效果

      • 1:禁用对应中断

    • 读取操作:

      • 0:中断已禁用

      • 1:中断已使能

功能说明:

  • 写入1可禁用指定中断,读取返回当前中断使能状态

  • NVIC_ICER7寄存器的位16至31为保留位

注:具体支持的中断数量取决于产品型号,请参考相关STM32产品的参考手册或数据手册获取详细信息。

4.3.4 中断挂起设置寄存器 x(NVIC_ISPRx)

寄存器位分配:

  • NVIC_ISPR0的位0至31分别对应中断0至31

  • NVIC_ISPR1的位0至31分别对应中断32至63

  • ......

  • NVIC_ISPR6的位0至31分别对应中断192至223

  • NVIC_ISPR7的位0至15分别对应中断224至239

位域功能说明:

  • 位31:0 SETPEND:中断挂起设置位

    • 写入操作:

      • 0:无效果

      • 1:将中断状态设置为挂起

    • 读取操作:

      • 0:中断未挂起

      • 1:中断已挂起

功能说明:

  • 对已处于挂起状态的中断写入1无效

  • 对已禁用的中断写入1会将其状态设为挂起

  • NVIC_ISPR7寄存器的位16至31为保留位

注:具体支持的中断数量取决于产品型号,请参考相关STM32产品的参考手册或数据手册获取详细信息。

4.3.5 中断挂起清除寄存器 x(NVIC_ICPRx)

寄存器位分配:

  • NVIC_ICPR0的位0至31分别对应中断0至31

  • NVIC_ICPR1的位0至31分别对应中断32至63

  • ......

  • NVIC_ICPR6的位0至31分别对应中断192至223

  • NVIC_ICPR7的位0至15分别对应中断224至239

寄存器位域布局:

位域功能说明:

  • 位31:0 CLRPEND:中断挂起清除位(rc_w1类型)

    • 写入操作:

      • 0:无效果

      • 1:清除对应中断的挂起状态

    • 读取操作:

      • 0:中断未挂起

      • 1:中断已挂起

功能说明:

  • 写入1仅清除中断挂起状态,不影响其中断激活状态

  • NVIC_ICPR7寄存器的位16至31为保留位

注:具体支持的中断数量取决于产品型号,请参考相关STM32产品的参考手册或数据手册获取详细信息。

4.3.6 中断活动位寄存器 x(NVIC_IABRx)

寄存器位分配:

  • NVIC_IABR0的位0至31分别对应中断0至31

  • NVIC_IABR1的位0至31分别对应中断32至63

  • ......

  • NVIC_IABR6的位0至31分别对应中断192至223

  • NVIC_IABR7的位0至15分别对应中断224至239

位域功能说明:

  • 位31:0 ACTIVE:中断活动状态标志位(只读)

    • 0:中断未激活

    • 1:中断已激活

    • 当对应中断状态为"激活"或"激活且挂起"时,该位读为1

功能说明:

  • 本寄存器仅用于读取中断激活状态,不可写入

  • NVIC_IABR7寄存器的位16至31为保留位

注:具体支持的中断数量取决于产品型号,请参考相关STM32产品的参考手册或数据手册获取详细信息。

4.3.7 中断优先级寄存器 x(NVIC_IPRx)

 NVIC_IPRx(x = 0至59)为字节可访问寄存器,为240个中断分别提供8位优先级字段IP[N](N = 0至239)。如图19所示,每个寄存器包含CMSIS中断优先级数组中的四个IP[N]字段。

 下表展示了任意NVIC_IPRx寄存器的位分配。每个IP[N]字段的序号可表示为N = 4 * x + 字节偏移量。

关于中断优先级的软件视角描述,请参见第210页的中断使能设置寄存器x(NVIC_ISERx)。

注:具体支持的中断数量取决于产品型号,请参考相关STM32产品的参考手册或数据手册获取详细信息。

4.3.8 软件触发中断寄存器(NVIC_STIR)

 

位域功能说明:

  • 位31:9:保留位,必须保持清零

  • 位8:0 INTID:软件生成的中断ID

    • 向STIR写入值可生成软件触发中断(SGI)

    • 写入值为所需SGI的中断ID,范围0-239(例如0x03表示IRQ3中断)

 

4.3.9 电平敏感和脉冲中断

STM32中断同时支持电平敏感和脉冲敏感模式,脉冲中断也称为边沿触发中断。

电平敏感中断

  • 中断信号会持续保持有效状态,直到外设撤销中断信号

  • 典型场景:中断服务程序(ISR)访问外设后,外设自动清除中断请求

  • 若处理器从ISR返回时中断信号仍未撤销,将立即重新进入中断

脉冲中断

  • 中断信号在处理器时钟上升沿同步采样

  • 外设必须维持至少1个时钟周期的高电平,确保NVIC能检测到脉冲

  • 处理器进入ISR时会自动清除挂起状态


中断的硬件与软件控制

Cortex-M4会锁存所有中断。外设中断进入挂起状态的条件包括:

  1. NVIC检测到高电平信号且中断未激活

  2. NVIC检测到中断信号上升沿

  3. 软件写中断挂起寄存器(NVIC_ISPRx)或STIR寄存器触发SGI

挂起状态的中断将保持挂起,直到以下任一条件满足:

  1. 处理器进入该中断的ISR

    • 中断状态从挂起转为激活,随后:

      • 电平敏感中断:

        • ISR返回时,若NVIC检测到中断信号仍有效 ⇒ 状态转回挂起 ⇒ 可能导致处理器立即重新进入ISR

        • ISR返回时,若中断信号已无效 ⇒ 状态转为未激活

      • 脉冲中断:

        • ISR执行期间出现新脉冲 ⇒ 状态转为"挂起且激活" ⇒ ISR返回后状态转回挂起 ⇒ 可能导致立即重新进入ISR

        • ISR执行期间无新脉冲 ⇒ ISR返回后状态转为未激活

  2. 软件写中断清除挂起寄存器

    • 电平敏感中断:

      • 中断信号仍有效 ⇒ 状态不变

      • 中断信号已无效 ⇒ 状态转为未激活

    • 脉冲中断:

      • 原状态为挂起 ⇒ 转为未激活

      • 原状态为激活且挂起 ⇒ 保持激活

4.3.10 NVIC 设计提示和技巧

  1. 寄存器访问规范

  • 必须使用正确对齐的寄存器访问方式

  • 处理器不支持对NVIC寄存器的非对齐访问

  • 具体支持的访问大小请参考各寄存器描述

  1. 中断状态说明

  • 即使中断被禁用,仍可能进入挂起状态

  • 禁用中断仅阻止处理器响应该中断

  1. 向量表重定位注意事项

  • 编程VTOR寄存器重定位向量表前,必须确保新向量表中已配置:

    • 故障处理程序

    • NMI(不可屏蔽中断)

    • 所有已使能的异常(包括中断)

  • 详细信息参见4.4.4节(第227页):向量表偏移寄存器(VTOR)

  1. NVIC编程提示

  • 中断开关控制:

    • 使用CPSIE ICPSID I指令启用/禁用中断

    • CMSIS提供以下内联函数:

      void __disable_irq(void);  // 禁用中断
      void __enable_irq(void);   // 启用中断
  1. CMSIS NVIC控制函数

表48. CMSIS NVIC控制函数

CMSIS中断控制函数功能描述
void NVIC_SetPriorityGrouping(uint32_t priority_grouping) 设置优先级分组
void NVIC_EnableIRQ(IRQn_t IRQn) 使能指定IRQ
void NVIC_DisableIRQ(IRQn_t IRQn) 禁用指定IRQ
uint32_t NVIC_GetPendingIRQ(IRQn_t IRQn) 获取IRQ挂起状态(返回IRQ编号表示挂起)
void NVIC_SetPendingIRQ(IRQn_t IRQn) 设置IRQ挂起状态
void NVIC_ClearPendingIRQ(IRQn_t IRQn) 清除IRQ挂起状态
uint32_t NVIC_GetActive(IRQn_t IRQn) 获取当前活动中断的IRQ编号
void NVIC_SetPriority(IRQn_t IRQn, uint32_t priority) 设置IRQ优先级
uint32_t NVIC_GetPriority(IRQn_t IRQn) 读取IRQ优先级
void NVIC_SystemReset(void) 系统复位

注:

    1. 参数IRQn为中断号,参见第38页表17(不同异常类型的属性)

    2. 更多函数说明请参考CMSIS文档

4.3.11 NVIC 寄存器映射

4.4 系统控制块(SCB)

 系统控制块(SCB)提供系统实现信息和系统控制功能,包括系统异常的配置、控制和状态报告。

4.4.1 辅助控制寄存器(ACTLR)

默认配置下,该寄存器已针对Cortex-M4处理器进行最优性能设置,通常无需修改。ACTLR寄存器提供以下处理器功能的禁用控制位:
• IT指令折叠优化
• 默认内存映射访问的写缓冲使用
• 多周期指令中断

 

位域功能说明:

    • 位31:10:保留位

    • 位9 DISOOFP:
      禁用浮点指令与整数指令的乱序执行

    • 位8 DISFPCA:
      禁用CONTROL.FPCA寄存器的自动更新
      (该位应写入0或保持原值SBZP)

    • 位7:3:保留位

 

位2 DISFOLD
禁用IT指令折叠功能:

  • 0:启用IT指令折叠

  • 1:禁用IT指令折叠

在某些场景下,处理器可以在执行IT指令的同时开始执行IT块中的第一条指令,这种行为称为IT折叠,可提升性能。但IT折叠可能导致循环执行时出现抖动。若任务需避免抖动,应在执行前将DISFOLD位置1以禁用IT折叠。


位1 DISDEFWBUF
(仅影响Cortex-M4处理器实现的写缓冲)
禁用默认内存映射访问的写缓冲:

  • 0:启用写缓冲

  • 1:禁用写缓冲(内存存储操作需在下条指令执行前完成)
    效果说明

  • 禁用后将导致所有总线错误变为精确错误(precise BusFaults)

  • 性能下降原因:存储操作必须完成后才能执行后续指令


位0 DISMCYCINT
禁用多周期指令中断:

    • 0:启用中断(支持加载/存储及乘除运算的中断)

    • 1:禁用中断(LDM/STM指令必须完成后才能响应中断)
      影响说明

    • 置1将增加中断延迟,因为处理器需先完成当前多周期指令才能保存状态并进入中断处理程序

4.4.2 CPUID 基本寄存器(CPUID)

CPUID寄存器包含处理器型号、版本及实现信息。

 

位域功能说明:

    • 位31:24 厂商代码
      0x41:表示Arm公司

    • 位23:20 变体编号
      对应产品版本号中的r值(格式:rnpn)
      0x0:修订版本0

    • 位19:16 固定值
      固定读取为0xF

    • 位15:4 处理器型号
      0xC24:Cortex-M4处理器

    • 位3:0 修订版本
      对应产品版本号中的p值(格式:rnpn),表示补丁版本
      0x1:补丁版本1

4.4.3 中断控制和状态寄存器(ICSR)

ICSR功能概述

  • 控制功能:

    • 提供不可屏蔽中断(NMI)的挂起设置位

    • 提供PendSV和SysTick异常的挂起设置/清除位

  • 状态指示:

    • 显示当前正在处理的异常编号

    • 指示是否存在被抢占的活跃异常

    • 显示最高优先级挂起异常的编号

    • 检测是否有中断处于挂起状态

重要警告:
若同时执行以下操作将导致不可预测后果:

    1. 对PENDSVSET和PENDSVCLR位同时写1

    2. 对PENDSTSET和PENDSTCLR位同时写1

 

位31 NMIPENDSET - NMI挂起设置位

  • 写入:

    • 0:无作用

    • 1:将NMI异常状态设为挂起

  • 读取:

    • 0:NMI异常未挂起

    • 1:NMI异常已挂起

:作为最高优先级异常,写入1后处理器会立即进入NMI处理程序,同时该位自动清零。仅当处理器执行NMI处理程序期间再次收到NMI信号时,读取才会返回1。

位30:29:保留位

位28 PENDSVSET - PendSV异常挂起设置位

  • 写入:
    ▸ 0:无作用
    ▸ 1:将PendSV异常状态设为挂起

  • 读取:
    ▸ 0:PendSV异常未挂起
    ▸ 1:PendSV异常已挂起
    :此位是设置PendSV挂起状态的唯一途径

位27 PENDSVCLR - PendSV异常清除挂起位(只写)

  • 0:无作用

  • 1:清除PendSV异常的挂起状态
    :读取值不确定

位26 PENDSTSET - SysTick异常挂起设置位

  • 写入:
    ▸ 0:无作用
    ▸ 1:将SysTick异常状态设为挂起

  • 读取:
    ▸ 0:SysTick异常未挂起
    ▸ 1:SysTick异常已挂起

位25 PENDSTCLR - SysTick异常清除挂起位(只写)

  • 0:无作用

  • 1:清除SysTick异常的挂起状态

位24:保留位(必须保持清零)

位23:调试保留位(非调试模式下读为0)

位22 ISRPENDING - 中断挂起标志(不含NMI和错误异常)

  • 0:无中断挂起

  • 1:有中断挂起

位21:19:保留位(必须保持清零)

位18:12 VECTPENDING - 最高优先级挂起异常编号

  • 0:无挂起异常

  • 其他值:已使能的最高优先级挂起异常编号
    :受BASEPRI和FAULTMASK寄存器影响,不受PRIMASK影响

位11 RETTOBASE - 返回基级标志

  • 0:存在被抢占的活跃异常待执行

  • 1:无活跃异常,或当前异常是唯一活跃异常

位10:9:保留位

位8:0 VECTACTIVE - 当前活跃异常编号

  • 0:线程模式

  • 其他值:当前活跃异常编号¹

技术说明:

    1. 该值与IPSR[8:0]相同(参见第22页中断程序状态寄存器)

    2. 获取CMSIS IRQ编号需将此值减去16(参见第22页表6)

4.4.4 向量表偏移寄存器(VTOR)

 

位域功能说明:

    • 位31:30:保留位(必须保持清零)

    • 位29:9 TBLOFF:向量表基址偏移字段

      • 存储从内存地址0x00000000开始的偏移量[29:9]位

      • 设置要求:
        ▸ 偏移地址必须按向量表条目数对齐
        ▸ 最小对齐单位为128字(512字节)
        ▸ 因此偏移量的[8:0]位始终为0

      • 位29特殊功能:

        • 0:向量表位于代码区

        • 1:向量表位于SRAM区
          :该位又称TBLBASE位

    • 位8:0:保留位(必须保持清零)

4.4.5 应用中断和复位控制寄存器(AIRCR)

AIRCR寄存器提供异常模型的优先级分组控制、数据访问的字节序状态以及系统复位控制。写入此寄存器时,必须向VECTKEY字段写入0x5FA,否则处理器将忽略该写入操作。

 

位域功能说明:

  • 位31:16 VECTKEYSTAT/VECTKEY:寄存器密钥

    • 读取值:0xFA05

    • 写入要求:必须写入0x5FA,否则忽略写入

  • 位15 ENDIANESS:数据字节序

    • 固定读为0(表示小端模式)

  • 位14:11:保留位(必须保持清零)

  • 位10:8 PRIGROUP:中断优先级分组字段

    • 用于划分组优先级和子优先级(参见第228页二进制点说明)

  • 位7:3:保留位(必须保持清零)

  • 位2 SYSRESETREQ:系统复位请求

    • 0:无复位请求

    • 1:向外部系统发送复位信号(不影响调试模块)

  • 位1 VECTCLRACTIVE:调试保留位

    • 必须写入0,否则行为不可预测

  • 位0 VECTRESET:调试保留位

    • 必须写入0,否则行为不可预测

二进制点说明:
PRIGROUP字段用于确定中断优先级寄存器(IPRx)中优先级字段的分割位置,将优先级值划分为组优先级和子优先级两部分。表51展示了PRIGROUP值对优先级分组的具体控制方式(若实际优先级位数少于8位,需相应调整表格内容)。

 异常抢占规则:
仅依据组优先级字段决定异常抢占行为(详见第41章2.3.6节《中断优先级分组》)。

4.4.6 系统控制寄存器(SCR)

SCR寄存器用于控制低功耗状态的进入与退出行为。

 

位域功能说明:

    • 位31:5:保留位(必须保持清零)

    • 位4 SEVONPEND:挂起事件唤醒控制位

      • 当事件或中断进入挂起状态时:
        ▸ 若处理器处于WFE等待状态,将立即唤醒
        ▸ 若未处于等待状态,事件将记录并影响下一次WFE

      • 模式选择:

        • 0:仅已使能的中断/事件可唤醒处理器

        • 1:所有中断(包括禁用中断)和事件均可唤醒

    • 位3:保留位(必须保持清零)

    • 位2 SLEEPDEEP:深度睡眠模式选择

      • 0:普通睡眠模式

      • 1:深度睡眠模式

    • 位1 SLEEPONEXIT:异常返回睡眠控制

      • 0:从异常返回线程模式时不进入睡眠

      • 1:从中断服务程序返回后自动进入睡眠/深度睡眠

    • 位0:保留位(必须保持清零)

4.4.7 配置和控制寄存器(CCR)

CCR寄存器用于控制线程模式进入及以下功能使能:
• 使NMI、硬错误及FAULTMASK升级的错误处理程序忽略总线错误
• 捕获除零和未对齐访问异常
• 允许非特权软件访问STIR寄存器(参见第216页软件触发中断寄存器)

 

位域功能说明:

    • 位31:10:保留位(必须保持清零)

    • 位9 STKALIGN:异常入口堆栈对齐配置

      • 0:4字节对齐

      • 1:8字节对齐
        :处理器通过压栈的PSR[9]位保存对齐状态,异常返回时恢复

    • 位8 BFHFNMIGN:高优先级处理程序总线错误忽略

      • 0:加载/存储指令导致的总线错误将引发死锁

      • 1:优先级-1和-2的处理程序忽略此类错误
        警告:仅当处理程序及其数据位于绝对安全内存时可设为1

    • 位7:5:保留位(必须保持清零)

    • 位4 DIV_0_TRP:除零陷阱使能

      • 0:SDIV/UDIV除零返回0(不触发异常)

      • 1:触发除零异常

位3 UNALIGN_TRP - 未对齐访问陷阱使能

  • 0:不捕获半字/字未对齐访问

  • 1:捕获半字/字未对齐访问(触发用法错误)
    :LDM/STM/LDRD/STRD指令始终会触发错误(不受此位影响)

位2:保留位(必须保持清零)

位1 USERSETMPEND - 非特权STIR访问使能

  • 0:禁止非特权软件访问STIR寄存器

  • 1:允许非特权软件访问STIR寄存器
    (参见第216页软件触发中断寄存器说明)

位0 NONBASETHRDENA - 线程模式进入控制

    • 0:仅当无活跃异常时可进入线程模式

    • 1:通过EXC_RETURN值控制可从任意异常层级进入线程模式
      (参见第44页异常返回机制)

4.4.8 系统处理程序优先级寄存器(SHPRx)

SHPR1-SHPR3寄存器用于配置可编程优先级系统异常的处理程序优先级(0-255级)。SHPR1-SHPR3支持字节访问。

系统错误处理程序及其对应优先级字段如下:

 

表52. 系统错误处理程序优先级字段

异常类型优先级字段所属寄存器
内存管理错误 PRI_4  
总线错误 PRI_5 系统异常优先级寄存器1 (SHPR1)
用法错误 PRI_6  
SVCall PRI_11 系统异常优先级寄存器2 (SHPR2)(见233页)
PendSV PRI_14 系统异常优先级寄存器3 (SHPR3)(见234页)
SysTick PRI_15  

  • 每个PRI_N字段为8位宽,但处理器仅实现[7:4]位,[3:0]位读为0且写入无效(M=4时)


系统异常优先级寄存器1 (SHPR1)

地址偏移量:0x18
复位值:0x0000 0000
访问权限:特权级

寄存器位域布局:

位域功能说明:

  • 位31:24:保留位(必须保持清零)

  • 位23:16 PRI_6:系统异常6(用法错误)优先级

  • 位15:8 PRI_5:系统异常5(总线错误)优先级

  • 位7:0 PRI_4:系统异常4(内存管理错误)优先级


系统异常优先级寄存器2 (SHPR2)

地址偏移量:0x1C
复位值:0x0000 0000
访问权限:特权级

寄存器位域布局:

位域功能说明:

  • 位31:24 PRI_11:系统异常11(SVCall)优先级

  • 位23:0:保留位(必须保持清零)


系统异常优先级寄存器3 (SHPR3)

地址:0xE000ED20
复位值:0x0000 0000
访问权限:特权级

寄存器位域布局:

位域功能说明:

  • 位31:24 PRI_15:系统异常15(SysTick异常)优先级

  • 位23:16 PRI_14:系统异常14(PendSV)优先级

  • 位15:0:保留位(必须保持清零)

4.4.9 系统处理程序控制和状态寄存器(SHCSR)

SHCSR寄存器功能说明

    1. 核心功能

      • 控制系统异常处理程序的使能状态

      • 实时反映以下状态:
        ✓ 总线错误、内存管理错误及SVC异常的挂起状态
        ✓ 系统异常处理程序的激活状态

    2. 禁用处理程序的风险

      • 若禁用某异常处理程序后发生对应错误,处理器将自动升级为硬错误(Hard Fault)

    3. 寄存器写入权限

      • 允许通过写操作修改系统异常的挂起/激活状态

      • 操作系统内核可通过修改激活位实现异常上下文切换

    4. 安全操作规范

      • ⚠️ 关键警告:

        • 错误修改激活位且未同步调整栈内容将触发错误异常

        • 必须保存当前激活状态并在操作后恢复

      • 🔧 操作要求:

        • 启用异常处理程序后,必须采用"读取-修改-写入"流程

        • 确保仅修改目标位,避免影响其他位域

 

系统控制与状态寄存器(SHCSR)位域说明

高位域 (位31-19)

  • 保留位:必须保持清零

异常使能控制位

  • 位18 USGFAULTENA:用法错误使能位(1=使能)⁴

  • 位17 BUSFAULTENA:总线错误使能位(1=使能)⁴

  • 位16 MEMFAULTENA:内存管理错误使能位(1=使能)¹

异常挂起状态位

  • 位15 SVCALLPENDED:SVC调用挂起状态(1=挂起)²

  • 位14 BUSFAULTPENDED:总线错误挂起状态(1=挂起)³

  • 位13 MEMFAULTPENDED:内存管理错误挂起状态(1=挂起)³

  • 位12 USGFAULTPENDED:用法错误挂起状态(1=挂起)²

异常激活状态位

  • 位11 SYSTICKACT:SysTick异常激活状态(1=激活)²

  • 位10 PENDSVACT:PendSV异常激活状态(1=激活)

  • 位9:保留位(必须保持清零)


低位域 (位8-0)

位域功能说明
位8 MONITORACT 调试监控激活状态(1=激活)
位7 SVCALLACT SVC调用激活状态(1=激活)
位6-4 保留位(必须保持清零)
位3 USGFAULTACT 用法错误激活状态(1=激活)
位2 保留位(必须保持清零)
位1 BUSFAULTACT 总线错误激活状态(1=激活)
位0 MEMFAULTACT 内存管理错误激活状态(1=激活)

技术注解

  1. 使能位:置1启用对应异常,置0禁用

  2. 挂起位:读为1表示异常挂起,可写入修改状态

  3. 激活位:读为1表示异常激活,写入操作需参考本节注意事项

 

4.4.10 可配置故障状态寄存器(CFSR;UFSR+BFSR+MMFSR)

CFSR由以下子寄存器组成:
• 用法错误状态寄存器 (UFSR)(见238页)
• 总线错误状态寄存器 (BFSR)(见239页)
• 内存管理错误状态寄存器 (MMFSR)(见240页)

访问方式:

  • 字访问(0xE000ED28):读取完整CFSR

  • 字节访问(0xE000ED28):访问MMFSR

  • 半字访问(0xE000ED28):访问MMFSR+BFSR

  • 字节访问(0xE000ED29):访问BFSR

  • 半字访问(0xE000ED2A):访问UFSR

 

位域说明:

  • 位31:16 UFSR:用法错误状态(详见238页)

  • 位15:8 BFSR:总线错误状态(详见239页)

  • 位7:0 MMFSR:内存管理错误状态(详见240页)

4.4.11 使用故障状态寄存器(UFSR)

位域说明:

    • 位31:26:保留位(必须保持清零)

    • 位25 DIVBYZERO:除零错误

      • 0:未发生除零错误,或未启用除零捕获

      • 1:处理器执行了SDIV/UDIV指令且除数为0
        配置要求:需在CCR寄存器中置位DIV_0_TRP(参见231页)

    • 位24 UNALIGNED:非对齐访问错误

      • 0:未发生非对齐访问,或未启用非对齐捕获

      • 1:处理器执行了非对齐内存访问
        :LDM/STM/LDRD/STRD指令始终触发此错误

    • 位23:20:保留位(必须保持清零)

    • 位19 NOCP:协处理器访问错误

      • 0:未访问协处理器

      • 1:处理器尝试访问不支持的协处理器

    • 位18 INVPC:非法PC加载错误

      • 0:未发生

      • 1:处理器尝试通过EXC_RETURN非法加载PC

    • 位17 INVSTATE:非法状态错误

      • 0:未发生

      • 1:处理器尝试非法使用EPSR寄存器

    • 位16 UNDEFINSTR:未定义指令错误

      • 0:未发生

      • 1:处理器尝试执行无法解码的指令

4.4.12 总线故障状态寄存器(BFSR)

位域说明:

    • 位15 BFARVALID:总线错误地址寄存器(BFAR)有效标志

      • 0:BFAR中的地址无效

      • 1:BFAR包含有效的错误地址
        :若总线错误因优先级升级为硬错误,硬错误处理程序必须将此位清零

    • 位14:保留位(必须保持清零)

    • 位13 LSPERR:浮点惰性状态保存总线错误

      • 0:未发生

      • 1:浮点状态保存过程中发生总线错误

    • 位12 STKERR:异常入口堆栈操作总线错误

      • 0:未发生

      • 1:异常压栈过程中发生总线错误(SP已调整但栈数据可能损坏)

    • 位11 UNSTKERR:异常返回弹栈总线错误

      • 0:未发生

      • 1:异常返回弹栈过程中发生总线错误(原始栈未被修改)

    • 位10 IMPRECISERR:非精确数据总线错误

      • 0:未发生

      • 1:检测到异步总线错误(无法定位具体指令)

    • 位9 PRECISERR:精确数据总线错误

      • 0:未发生

      • 1:检测到总线错误(PC指向触发指令)

    • 位8 IBUSERR:指令总线错误

      • 0:未发生

      • 1:处理器尝试执行预取错误指令

4.4.13 内存管理故障地址寄存器(MMFSR)

位域说明:

    • 位7 MMARVALID:内存管理错误地址寄存器(MMAR)有效标志

      • 0:MMAR中的地址无效

      • 1:MMAR包含有效的错误地址
        安全提示:若错误升级为硬错误,处理程序必须手动清零此位

    • 位6:保留位(必须保持清零)

    • 位5 MLSPERR:浮点惰性状态保存错误

      • 0:未发生

      • 1:浮点状态保存过程中触发内存保护错误

    • 位4 MSTKERR:异常入口堆栈操作错误

      • 0:正常

      • 1:异常压栈时发生内存违规(SP已调整但栈数据可能损坏)

    • 位3 MUNSTKERR:异常返回弹栈错误

      • 0:正常

      • 1:异常返回弹栈时发生内存违规(原始栈保留未修改)

    • 位2:保留位(必须保持清零)

    • 位1 DACCVIOL:数据访问违规

      • 0:未发生

      • 1:尝试非法数据访问(PC指向触发指令,MMAR记录违规地址)

    • 位0 IACCVIOL:指令访问违规

      • 0:未发生

      • 1:尝试从不允许执行的区域取指(PC指向触发指令)
        特性说明:即使MPU禁用,XN区域访问仍会触发此错误

4.4.14 硬件故障状态寄存器(HFSR)

HFSR寄存器记录触发硬错误处理程序的事件信息,采用"读常规-写清零"机制:读取返回当前状态,写入1则清除对应位。

寄存器位域布局:

位域功能说明:

    • 位31 DEBUG_VT:调试保留位

      • 必须写入0,否则行为不可预测

    • 位30 FORCED:强制硬错误标志

      • 0:未发生

      • 1:因优先级或禁用导致的可配置错误升级为硬错误
        处理要求:需检查其他错误状态寄存器定位根源

    • 位29:2:保留位(必须保持清零)

    • 位1 VECTTBL:向量表读取错误

      • 0:正常

      • 1:异常处理期间读取向量表时发生总线错误
        特性说明:错误PC指向被异常抢占的指令

    • 位0:保留位(必须保持清零)

4.4.15 内存管理故障地址寄存器(MMFAR)

 

功能说明:

  • 当MMFSR寄存器的MMARVALID位为1时,存储触发内存管理错误的地址

  • 未对齐访问错误时,记录实际触发错误的地址(可能与指令请求地址不同)

  • 具体错误原因需查看MMFSR寄存器(参见237页可配置错误状态寄存器)

4.4.16 总线故障地址寄存器(BFAR)

 

功能说明:

  • 当BFSR寄存器的BFARVALID位为1时,存储触发总线错误的地址

  • 未对齐访问错误时,记录指令原始请求地址(而非实际错误地址)

  • 具体错误原因需查看BFSR寄存器(参见237页可配置错误状态寄存器)

4.4.17 辅助故障状态寄存器(AFSR)

 位 31:0 IMPDEF:实现定义。AFSR包含额外的系统故障信息。这些位映射到AUXFAULT输入信号。
此寄存器为“读、写清零”类型。这意味着寄存器中的位可以正常读取,但向任何位写入1会将该位清零为0。
每个AFSR位直接映射到处理器的AUXFAULT输入,输入信号为单周期高电平时,会将对应的AFSR位置1。该位将保持为1,直到向其写入1将其清零为0。
当AFSR位被锁存为1时,不会触发异常。如果需要异常,请使用中断。

4.4.18 系统控制块设计提示和技巧

确保软件使用正确大小的对齐访问来访问系统控制块寄存器:
• 除CFSR和SHPR1-SHPR3外,必须使用对齐的字访问;
• 对于CFSR和SHPR1-SHPR3,可以使用字节、对齐的半字或字访问。

处理器不支持对系统控制块寄存器的非对齐访问。

在故障处理程序中,确定真实的故障地址:

  1. 读取并保存MMFAR或BFAR的值。

  2. 读取MMFSR中的MMARVALID位或BFSR中的BFARVALID位。只有当该位为1时,MMFAR或BFAR地址才有效。

软件必须遵循此顺序,因为另一个更高优先级的异常可能会更改MMFAR或BFAR的值。例如,如果更高优先级的处理程序抢占当前故障处理程序,其他故障可能会修改MMFAR或BFAR的值。

4.4.19 SCB 寄存器映射图

 

4.5 SysTick定时器(STK)

处理器内置一个24位系统定时器SysTick,该定时器从重载值开始递减计数至零,并在下一个时钟边沿重新加载(回绕至)STK_LOAD寄存器中的值,随后继续递减计数。

当处理器因调试暂停时,计数器不会递减。

4.5.1 SysTick控制和状态寄存器(STK_CTRL)

SysTick CTRL寄存器用于配置SysTick功能。

 位 31:17 保留位,必须保持清零。
位 16 COUNTFLAG:
若定时器自上次读取后曾计数至0,则返回1。
位 15:3 保留位,必须保持清零。
位 2 CLKSOURCE:时钟源选择
选择时钟源:
0:AHB时钟8分频(AHB/8)
1:处理器时钟(AHB)
位 1 TICKINT:SysTick异常请求使能
0:递减至0时不触发SysTick异常请求
1:递减至0时触发SysTick异常请求
注:软件可通过COUNTFLAG判断SysTick是否曾计数至0。
位 0 ENABLE:计数器使能
启用计数器。当ENABLE置1时,计数器从LOAD寄存器加载RELOAD值并开始递减计数。计数至0时,将COUNTFLAG置1,并根据TICKINT的值决定是否触发SysTick异常。随后重新加载RELOAD值并继续计数。
0:禁用计数器
1:启用计数器

4.5.2 SysTick重载值寄存器(STK_LOAD)

 

位 31:24 保留位,必须保持清零。
位 23:0 RELOAD:重载值
LOAD寄存器指定计数器启用时及计数至0时加载到STK_VAL寄存器的起始值。

RELOAD值计算
RELOAD值可设为0x00000001至0x00FFFFFF范围内的任意值。起始值设为0是允许的,但无实际效果,因为SysTick异常请求和COUNTFLAG标志仅在从1计数至0时激活。

RELOAD值根据用途按以下方式计算:

    • 周期性定时器:若需生成周期为N个处理器时钟周期的多触发定时器,RELOAD值设为N-1。例如,若需每100个时钟脉冲触发一次SysTick中断,则设置RELOAD为99。

    • 单次延迟中断:若需在N个时钟周期后触发单次SysTick中断,RELOAD值设为N-1。例如,若需在100个时钟脉冲后触发中断,则设置RELOAD为99。

4.5.3 SysTick当前值寄存器(STK_VAL)

 

位 31:24 保留位,必须保持清零。

位 23:0 CURRENT:计数器当前值
VAL寄存器包含SysTick计数器的当前值。
读取操作返回SysTick计数器的当前值。
写入任意值会将该字段清零,同时将STK_CTRL寄存器中的COUNTFLAG位清零。

4.5.4 SysTick校准值寄存器(STK_CALIB)

CALIB寄存器用于指示SysTick校准特性。

 

位 31 NOREF:无参考时钟标志
读为0,表示提供独立参考时钟(频率为HCLK/8)。

位 30 SKEW:偏差标志
读为1,表示TENMS值不精确。由于TENMS值未知,1ms定时校准可能不准确,这会影响SysTick作为软件实时时钟的适用性。

位 29:24 保留位,必须保持清零。

位 23:0 TENMS[23:0]:校准值
表示SysTick计数器使用HCLK最大频率/8作为外部时钟时的校准值。该值因产品而异,请参考产品参考手册的SysTick校准值章节。当HCLK设置为最大频率时,SysTick周期为1ms。

4.5.5 SysTick设计提示和tips

  • SysTick计数器运行在处理器时钟上。若为低功耗模式停止时钟信号,计数器将停止。

  • 确保软件使用对齐的字访问方式操作SysTick寄存器。

  • SysTick的重载值和当前值在复位时未定义,正确初始化顺序如下:

    1. 设置重载值

    2. 清除当前值

    3. 配置控制与状态寄存器

4.5.6 SysTick寄存器map

4.6 浮点单元(FPU)

 

Cortex-M4F的FPU实现了FPv4-SP浮点扩展架构,完整支持单精度加、减、乘、除、乘累加和平方根运算,同时提供定点数与浮点数格式转换及浮点常量指令功能。该单元符合ANSI/IEEE 754-2008二进制浮点运算标准(简称IEEE 754标准)。

FPU包含32个单精度扩展寄存器,这些寄存器也可作为16个双字寄存器进行加载、存储和移动操作。

表56列出了Cortex-M4F系统控制块(SCB)中的浮点系统寄存器,FP扩展寄存器的基地址为0xE000ED00。

后续章节将详细描述该处理器特有的浮点系统寄存器。

注:关于IEEE标准及浮点运算(IEEE 754)的更多细节,请参考AN4044应用笔记(可从www.st.com网站获取)。

4.6.1 辅助处理器访问控制寄存器(CPACR)

 CPACR寄存器用于设置协处理器的访问权限。

位 31:24 保留位。读取为0,写入忽略。
位 23:20 CPn:[2n+1:2n](n取值为10和11)。协处理器n的访问权限,各字段可选值:
0b00:禁止访问,任何访问尝试将触发NOCP用法错误
0b01:仅特权访问,非特权访问将触发NOCP错误
0b10:保留值,访问结果不可预测
0b11:完全访问权限
位 19:0 保留位。读取为0,写入忽略。

4.6.2 浮点上下文控制寄存器(FPCCR)

 FPCCR寄存器用于设置或返回FPU控制数据。

 

位 31 ASPEN:浮点指令执行时CONTROL<2>位使能控制
该位使能时,异常进入和退出时将自动完成浮点上下文硬件状态的保存与恢复
0:执行浮点指令时禁用CONTROL<2>位设置
1:执行浮点指令时启用CONTROL<2>位设置

位 30 LSPEN:延迟状态自动保存使能
0:禁用浮点上下文的延迟状态自动保存功能
1:启用浮点上下文的延迟状态自动保存功能

位 29:9 保留位

位 8 MONRDY:调试监控就绪状态
0:分配浮点堆栈帧时,调试监控器未启用或优先级不允许设置MON_PEND
1:分配浮点堆栈帧时,调试监控器已启用且优先级允许设置MON_PEND

位 7 保留位

位 6 BFRDY:总线错误就绪状态
0:分配浮点堆栈帧时,总线错误未启用或优先级不允许将总线错误处理程序设为挂起状态
1:分配浮点堆栈帧时,总线错误已启用且优先级允许将总线错误处理程序设为挂起状态

位 5 MMRDY:内存管理就绪状态
0:分配浮点堆栈帧时,内存管理未启用或优先级不允许将内存管理处理程序设为挂起状态
1:分配浮点堆栈帧时,内存管理已启用且优先级允许将内存管理处理程序设为挂起状态

位 4 HFRDY:硬件错误就绪状态
0:分配浮点堆栈帧时,优先级不允许将硬件错误处理程序设为挂起状态
1:分配浮点堆栈帧时,优先级允许将硬件错误处理程序设为挂起状态

位 3 THREAD:线程模式状态
0:分配浮点堆栈帧时未处于线程模式
1:分配浮点堆栈帧时处于线程模式

位 2 保留位

位 1 USER:用户权限级别状态
0:分配浮点堆栈帧时未处于用户权限级别
1:分配浮点堆栈帧时处于用户权限级别

位 0 LSPACT:延迟状态保存激活标志
0:延迟状态保存未激活
1:延迟状态保存已激活(已分配浮点堆栈帧但状态保存操作被延迟)

4.6.3 浮点上下文地址寄存器(FPCAR)

 FPCAR寄存器用于保存异常堆栈帧上分配的未初始化浮点寄存器空间地址。

 

位域说明:

  • 位31-3 ADDRESS:异常堆栈帧中未初始化浮点寄存器空间的地址

  • 位2-0 保留位(读取为0,写入忽略)

4.6.4 浮点状态控制寄存器(FPSCR)

 FPSCR寄存器提供浮点系统所需的全部用户级控制功能。

标志位说明:
位31 N(负标志):

  • 0:运算结果为正数、零、大于或等于

  • 1:运算结果为负数或小于

位30 Z(零标志):

  • 0:运算结果非零

  • 1:运算结果为零

位29 C(进位标志):

    • 0:加法无进位/减法有借位

    • 1:加法有进位/减法无借位

位28 V(溢出标志):

  • 0:运算未发生溢出

  • 1:运算发生溢出

位27 保留位

位26 AHP(半精度格式选择):

  • 0:选择IEEE半精度格式

  • 1:选择替代半精度格式

位25 DN(默认NaN模式):

  • 0:NaN操作数参与浮点运算并传播结果

  • 1:任何涉及NaN的运算都返回默认NaN

位24 FZ(清零模式):

  • 0:禁用清零模式(完全符合IEEE 754标准)

  • 1:启用清零模式

位23-22 RMode(舍入模式):
0b00:就近舍入(RN)
0b01:向正无穷舍入(RP)
0b10:向负无穷舍入(RM)
0b11:向零舍入(RZ)

位21-8 保留位

位7 IDC(输入非规格化异常标志):

  • 1:自上次清零后发生对应异常

位6-5 保留位

位4 IXC(不精确异常标志):

  • 1:自上次清零后发生对应异常

位3 UFC(下溢异常标志):

  • 1:自上次清零后发生对应异常

位2 OFC(上溢异常标志):

  • 1:自上次清零后发生对应异常

位1 DZC(除零异常标志):

  • 1:自上次清零后发生对应异常

位0 IOC(无效操作异常标志):

  • 1:自上次清零后发生对应异常

 

表57. 浮点比较操作对条件标志位的影响

比较结果NZCV
相等 0 1 1 0
小于 1 0 0 0
大于 0 0 1 0
无序比较 0 0 1 1

 

4.6.5 浮点默认状态控制寄存器(FPDSCR)

 FPDSCR寄存器存储浮点状态控制数据的默认值

 

位域说明:

  • 位31-27 保留位(必须保持清零)

  • 位26 AHP:FPSCR.AHP位的默认值

  • 位25 DN:FPSCR.DN位的默认值

  • 位24 FZ:FPSCR.FZ位的默认值

  • 位23-22 RMode:FPSCR.RMode位的默认值

  • 位21-0 保留位(必须保持清零)

4.6.6 使能FPU

FPU在复位后处于禁用状态,使用任何浮点指令前必须启用它。
以下示例代码展示如何在特权模式和用户模式下启用FPU(读写CPACR必须在特权模式下完成):

 
; CPACR地址为0xE000ED88
LDR.W R0, =0xE000ED88  
; 读取CPACR当前值
LDR R1, [R0]  
; 设置位20-23以启用CP10和CP11协处理器
ORR R1, R1, #(0xF << 20)  
; 将修改值写回CPACR
STR R1, [R0]  
; 等待存储操作完成
DSB  
; FPU启用后重置流水线
ISB  

4.6.7 使能和清除FPU异常中断

FPU异常标志通过中断控制器产生中断。FPU中断的全局控制由中断控制器实现。系统配置控制器(SYSCFG)还提供单独的掩码位,可独立启用/禁用各FPU标志的中断生成。

注:在STM32F4xx系列器件中,没有单独的掩码位,FPU中断的启用/禁用需通过中断控制器实现。由于IXC异常标志频繁触发,该系列器件中此标志未连接至中断控制器,无法产生中断。如需使用,必须采用轮询方式管理。

FPU异常标志的清除方式取决于FPU上下文保存/恢复配置:

  1. 不保存浮点寄存器(FPCCR寄存器位30 LSPEN=0且位31 ASPEN=0)
    需直接清除浮点状态控制寄存器(FPSCR)中的中断源。示例:

     

  2. 延迟保存/恢复(FPCCR寄存器位30 LSPEN=1且位31 ASPEN=X)
    需先对FPSCR进行虚拟读取以强制状态保存并清除FPSCR,再处理栈中的FPSCR值。示例:

  3. 自动保存/恢复浮点寄存器(FPCCR寄存器位30 LSPEN=0且位31 ASPEN=1)
    需读取FPSCR以强制清除,再处理栈中的FPSCR值。示例:

     

posted @ 2025-06-07 16:34  明er  阅读(278)  评论(0)    收藏  举报