LV04-07-中断与异常-04-CortexA7中断系统

本文主要是中断与异常——Cortex-A7中断系统的相关笔记,若笔记中有错误或者不合适的地方,欢迎批评指正😃。

点击查看使用工具及版本
Windows版本 windows11
Ubuntu版本 Ubuntu16.04的64位版本
VMware® Workstation 16 Pro 16.2.3 build-19376536
终端软件 MobaXterm(Professional Edition v23.0 Build 5042 (license))
Linux开发板 正点原子 i.MX6ULL Linux 阿尔法开发板
uboot NXP官方提供的uboot,NXP提供的版本为uboot-imx-rel_imx_4.1.15_2.1.0_ga(使用的uboot版本为U-Boot 2016.03)
linux内核 linux-4.15(NXP官方提供)
Win32DiskImager Win32DiskImager v1.0
点击查看本文参考资料
分类 网址 说明
官方网站 https://www.arm.com/ ARM官方网站,在这里我们可以找到Cotex-Mx以及ARMVx的一些文档
https://www.nxp.com.cn/ NXP官方网站
https://www.nxpic.org.cn/NXP 官方社区
https://u-boot.readthedocs.io/en/latest/u-boot官网
https://www.kernel.org/linux内核官网
点击查看相关文件下载
分类 网址 说明
NXP https://github.com/nxp-imx NXP imx开发资源GitHub组织,里边会有u-boot和linux内核的仓库
https://elixir.bootlin.com/linux/latest/source 在线阅读linux kernel源码
nxp-imx/linux-imx/releases/tag/rel_imx_4.1.15_2.1.0_ga NXP linux内核仓库tags中的rel_imx_4.1.15_2.1.0_ga
nxp-imx/uboot-imx/releases/tag/rel_imx_4.1.15_2.1.0_ga NXP u-boot仓库tags中的rel_imx_4.1.15_2.1.0_ga
I.MX6ULL i.MX 6ULL Applications Processors for Industrial Products I.MX6ULL 芯片手册(datasheet,可以在线查看)
i.MX 6ULL Applications ProcessorReference Manual I.MX6ULL 参考手册(下载后才能查看,需要登录NXP官网)
ARM Cortex-A7 MPCore Technical Reference Manual Cortex-A7 MPCore技术参考手册
ARM Architecture Reference Manual ARMv7-A and ARMv7-R edition ARM架构参考手册ARMv7-A和ARMv7-R版
Arm Generic Interrupt Controller Architecture Specification- version 3 and version 4 Arm通用中断控制器架构规范-版本3和版本4
ARM Generic Interrupt Controller Architecture Specification - Version 2.0 Arm通用中断控制器架构规范-版本2.0
ARM Cortex-A Series Programmer's Guide for ARMv7-A Cortex-A系列ARMv7-A编程指南

一、Cortex-A7 中断系统简介

1. 8个中断?

Cortex-A7 也有中断向量表,中断向量表也是在代码的最前面。 CortexA7 内核有 8 个异常中断,这 8 个异常中断的中断向量表如表 :

image-20230910104505665

中断向量表里面都是中断服务函数的入口地址,因此一款芯片有什么中断都是可以从中断向量表看出来的。从表中可以看出, Cortex-A7 一共有 8 个中断,而且还有一个中断向量未使用,实际只有 7 个中断。

①、复位中断(Rest), CPU 复位以后就会进入复位中断,我们可以在复位中断服务函数里面做一些初始化工作,比如初始化 SP 指针、 DDR 等等。

②、未定义指令中断(Undefined Instruction),如果指令不能识别的话就会产生此中断。

③、软中断(Software Interrupt,SWI),由 SWI 指令引起的中断, Linux 的系统调用会用 SWI指令来引起软中断,通过软中断来陷入到内核空间。

④、指令预取中止中断(Prefetch Abort),预取指令的出错的时候会产生此中断。

⑤、数据访问中止中断(Data Abort),访问数据出错的时候会产生此中断。

⑥、 IRQ 中断(IRQ Interrupt),外部中断,前面已经说了,芯片内部的外设中断都会引起此中断的发生。

⑦、 FIQ 中断(FIQ Interrupt),快速中断,如果需要快速处理中断的话就可以使用此中断。

难道一个能跑 Linux 的芯片只有这 7 个中断?明显不可能的!那类似 STM32 中的EXTI9_5_IRQHandler、 TIM2_IRQHandler 这样的中断向量在哪里? I2C、SPI、定时器等等的中断怎么处理呢?这个就是 Cortex-A 和 Cotex-M 在中断向量表这一块的区别,对于 Cortex-M 内核来说,中断向量表列举出了一款芯片所有的中断向量,包括芯片外设的所有中断。对于 CotexA 内核来说并没有这么做,在上面的表中有个 IRQ 中断, Cortex-A 内核 CPU 的所有外部中断都属于这个 IRQ 中断,当任意一个外部中断发生的时候都会触发 IRQ 中断。在 IRQ 中断服务函数里面就可以读取指定的寄存器来判断发生的具体是什么中断,进而根据具体的中断做出相应的处理。这些外部中断和 IRQ 中断的关系如下:

image-20230910105025878

左侧的 Software0_IRQn~PMU_IRQ2_IRQ 这些都是 I.MX6U 的中断,他们都属于 IRQ 中断。当图中左侧这些中断中任意一个发生的时候 IRQ 中断都会被触发,所以我们需要在 IRQ 中断服务函数中判断究竟是左侧的哪个中断发生了,然后再做出具体的处理。

2. GIC 控制器简介

2.1 GIC 控制器总览

GIC 是 ARM 公司给 Cortex-A/R 内核提供的一个中断控制器,类似 Cortex-M 内核中的NVIC。目前 GIC 有 4 个版本:V1~V4, V1 是最老的版本,已经被废弃了。 V2~V4 目前正在大量的使用。 GIC V2 是给 ARMv7-A 架构使用的,比如 Cortex-A7、 Cortex-A9、 Cortex-A15 等,V3 和 V4 是给 ARMv8-A/R 架构使用的,也就是 64 位芯片使用的。

I.MX6U 是 Cortex-A 内核的,因此我们主要学习 GIC V2。 GIC V2 最多支持 8 个核。 ARM 会根据 GIC 版本的不同研发出不同的 IP 核,那些半导体厂商直接购买对应的 IP 核即可,比如 ARM 针对 GIC V2 就开发出了 GIC400 这个中断控制器 IP 核。

我们来简单了解一下GIC V2,我们打开《ARM® Generic Interrupt Controller Architecture version 2.0》这篇文档,找到3.9 Example GIC usage models 一节,这一节有下面这么一个图:

image-20240121142504171

如上图所示,硬件中断信号发送到 GIC( Generic Interrupt Controller),GIC 产生一个 FIQ 或 IRQ 信号给 CPU。 GPIO 模块、 UART 模块均能产生硬件中断。在初始化中断时,要初始化这 4 部分:产生中断的源头(GPIO 模块或 UART模块等)、 GIC(内部有 Distributor 或 CPU interface)、 CPU 本身(设置 CPSR寄存器),如下图

image-20240121143724299

GIC 的主要作用可以归结为接受硬件中断信号,并进行简单的处理,按照一定的设置策略,分给对应的 CPU 处理,我们再找到3.9.3 Supporting IRQs and FIQs in a virtualized processor environment 一节,有这么一个图:

image-20240121143900941

当 GIC 接收到外部中断信号以后就会报给 ARM 内核,但是ARM 内核只提供了四个信号给 GIC 来汇报中断情况: VFIQ(虚拟快速 FIQ)、VIRQ(虚拟外部 IRQ)、FIQ(快速中断 IRQ)、IRQ(外部中断 IRQ),他们之间的关系如图:

image-20230910105439401

VFIQ 和 VIRQ 是针对虚拟化,剩下就是 IRQ 和 FIQ。GPIO 中断属于 IRQ 中断,所以在后面的GPIO中断实验中 GIC 上报 IRQ 信号给 ARM 内核。 这里我们先不关心虚拟化,剩下的就是 FIQ 和 IRQ 了,那么 GIC 是如何完成这个工作的呢? GICV2 的逻辑图如图 :

image-20230910105547375

左侧部分就是中断源,中间部分就是 GIC 控制器,最右侧就是中断控制器向处理器内核发送中断信息。GIC 控制器包括分发器( Distributor)和 CPU 接口端( CPU interface)。 分发器( Distributor)主要完成对整个中断控制器使能,设置中断优先级,设置中断触发方式,决定每个中断信号发送到哪一个具体的 CPU 上执行。CPU 接口端( CPU interface)主要完成使能和发送一个具体的中断信号到特定的 CPU 上,确认中断已被 CPU 接受、处理以及处理完成,设置 CPU 能接受中断的优先级以及基于级别的中断抢占。

所以中断信号先到达分发器,分发器根据该中断所设定的 CPU,把中断发送到 CPU对应的 CPU interface 上;在 CPU interface 里判断该中断的优先级是否足够高,能否抢断或打断当前的中端处理,如果可以, CPU interface 就会发送一个物理的 signa 到 CPU 的 IRQ 线上; CPU 接收到中断信号,转到中断处理模式进行处理。

然后我们重点要看的肯定是中间的 GIC 部分, GIC 将众多的中断源分为分为三类:

①、SPI(Shared Peripheral Interrupt),共享中断,顾名思义,所有 Core 共享的中断,这个是最常见的,那些外部中断都属于 SPI 中断(注意!不是 SPI 总线那个中断) 。比如按键中断、串口中断等等,这些中断所有的 Core 都可以处理,不限定特定 Core。

②、**PPI(Private Peripheral Interrupt)**,私有中断,我们说了 GIC 是支持多核的,每个核肯定有自己独有的中断。这些独有的中断肯定是要指定的核心处理,因此这些中断就叫做私有中断。

③、**SGI(Software-generated Interrupt)**,软件中断,由软件触发引起的中断,通过向寄存器GICD_SGIR 写入数据来触发,系统会使用 SGI 中断来完成多核之间的通信。

2.2 中断 ID

中断源有很多,为了区分这些不同的中断源肯定要给他们分配一个唯一 ID,这些 ID 就是中断 ID。每一个 CPU 最多支持 1020 个中断 ID,中断 ID 号为 ID0~ID1019。这 1020 个 ID 包含了 PPI、 SPI 和 SGI,那么这三类中断是如何分配这 1020 个中断 ID 的呢?这 1020 个 ID 分配如下:

  • ID0~ID15:这 16 个 ID 分配给 SGI。

  • ID16~ID31:这 16 个 ID 分配给 PPI。

  • ID32~ID1019:这 988 个 ID 分配给 SPI,像 GPIO 中断、串口中断等这些外部中断 ,至于具体到某个 ID 对应哪个中断那就由半导体厂商根据实际情况去定义了。

比如 I.MX6U 的总共使用了 128 个中断 ID,加上前面属于 PPI 和 SGI 的 32 个 ID, I.MX6U 的中断源共有 128+32=160个,这 128 个中断 ID 对应的中断在《I.MX6ULL 参考手册》的“3.2 Cortex A7 interrupts”小节,中断源如表:

image-20230910110046239

这里就不全部列出了,我们前面移植了 NXP 官方 SDK中的文件 MCIMX6Y2C.h,在此文件中定义了一个枚举类型 IRQn_Type,此枚举类型就枚举出了 I.MX6U 的所有中断,

2.3 GIC 逻辑分块

GIC 架构分为了两个逻辑块: Distributor 和 CPU Interface,也就是分发器端和 CPU 接口端。

  • Distributor(分发器端)

此逻辑块负责处理各个中断事件的分发问题,也就是中断事件应该发送到哪个 CPU Interface 上去。分发器收集所有的中断源,可以控制每个中断的优先级,它总是将优先级最高的中断事件发送到 CPU 接口端。分发器端要做的主要工作如下:

①、全局中断使能控制。

②、控制每一个中断的使能或者关闭。

③、设置每个中断的优先级。

④、设置每个中断的目标处理器列表。

⑤、设置每个外部中断的触发模式:电平触发或边沿触发。

⑥、设置每个中断属于组 0 还是组 1。

  • CPU Interface(CPU 接口端)

CPU 接口端听名字就知道是和 CPU Core 相连接的,因此在每个 CPU Core 都可以在 GIC 中找到一个与之对应的 CPU Interface。 CPU 接口端就是分发器和 CPU Core 之间的桥梁, CPU 接口端主要工作如下:

①、使能或者关闭发送到 CPU Core 的中断请求信号。

②、应答中断。

③、通知中断处理完成。

④、设置优先级掩码,通过掩码来设置哪些中断不需要上报给 CPU Core。

⑤、定义抢占策略。

⑥、当多个中断到来的时候,选择优先级最高的中断通知给 CPU Core。

2.4 IMX6ULL GIC中断寄存器

GIC 寄存器分为 Distributor register 和 CPU interface register。寄存器数目较多,这里我们看一下后面做IMX6ULL外部中断实验的时候需要我们设置的寄存器。

4.1 GICC_IAR 寄存器

《ARM® Generic Interrupt Controller Architecture version 2.0》的4.4.4 Interrupt Acknowledge Register, GICC_IAR 一节是介绍这个寄存器的:

image-20240121144939074
位域 名称 读写权限 描述
bit[31:13] - 保留
bit[12:10] CPUID R 对于SGI 类中断,它表示谁发出了中断。例如,值为3表示该请求是通过对CPU-interface3上的GICD_SGIR的写操作生成的。
bit[9:0] Interrupt ID R 中断ID

4.2 GICC_EOIR 寄存器

《ARM® Generic Interrupt Controller Architecture version 2.0》的4.4.5 End of Interrupt Register, GICC_EOIR 一节:

image-20240121150209876

写此寄存器,表示某中断已经处理完毕。 GICC_IAR 的值表示当前在处理的中断,把 GICC_IAR 的值写入 GICC_EOIR 就表示中断处理完了。

二、CP15 协处理器

1. 相关指令

关 于 CP15 协处理 器和其 相关寄存器的详细内容请参考下面两份文 档: 《 ARM ArchitectureReference Manual ARMv7-A and ARMv7-R edition.pdf》 第 1469 页“B3.17 Oranization of the CP15 registers in a VMSA implementation”。《Cortex-A7 Technical ReferenceManua.pdf》 第55 页“Capter 4 System Control”。

CP15 协处理器一般用于存储系统管理, 但是在中断中也会使用到, CP15 协处理器一共有 16 个 32 位寄存器。 CP15 协处理器的访问通过如下两个指令完成:

1
2
MRC ;将 CP15 协处理器中的寄存器数据读到 ARM 寄存器中。
MCR ;将 ARM 寄存器的数据写入到 CP15 协处理器寄存器中。

MRC 就是读 CP15 寄存器, MCR 就是写 CP15 寄存器, MCR 指令格式如下 :

1
MCR{cond} p15, <opc1>, <Rt>, <CRn>, <CRm>, <opc2>
  • cond:指令执行的条件码,如果忽略的话就表示无条件执行。

  • opc1:协处理器要执行的操作码。

  • Rt: ARM 源寄存器,要写入到 CP15 寄存器的数据就保存在此寄存器中。

  • CRn: CP15 协处理器的目标寄存器。

  • CRm: 协处理器中附加的目标寄存器或者源操作数寄存器,如果不需要附加信息就将CRm 设置为 C0,否则结果不可预测。

  • opc2: 可选的协处理器特定操作码,当不需要的时候要设置为 0。

MRC 的指令格式和 MCR 一样,只不过在 MRC 指令中 Rt 就是目标寄存器,也就是从CP15 指定寄存器读出来的数据会保存在 Rt 中。而 CRn 就是源寄存器,也就是要读取的写处理器寄存器。 假如我们要将 CP15 中 C0 寄存器的值读取到 R0 寄存器中,那么就可以使用如下命令:

1
MRC p15, 0, r0, c0, c0, 0

2. 相关寄存器

CP15 协处理器有 16 个 32 位寄存器, c0~c15,我们来看一下 c0、 c1、 c12 和 c15 这四个寄存器,因为我们目前学习的实验要用到这四个寄存器,其他的寄存器可以参考上面的两个文档即可。 通过 c0 寄存器可以获取到处理器内核信息;通过 c1 寄存器可以使能或禁止 MMU、 I/D Cache 等;通过 c12 寄存器可以设置中断向量偏移;通过 c15 寄存器可以获取 GIC 基地址。

2.1 c0 寄存器

CP15 协处理器有 16 个 32 位寄存器, c0~c15,在使用 MRC 或者 MCR 指令访问这 16 个寄存器的时候,指令中的 CRn、 opc1、 CRm 和 opc2 通过不同的搭配,其得到的寄存器含义是不同的。比如 c0 在不同的搭配情况下含义如图

image-20230910110829692

当 MRC/MCR 指令中的 CRn=c0, opc1=0, CRm=c0, opc2=0 的时候就表示此时的 c0 就是 MIDR 寄存器,也就是主 ID 寄存器,这个也是 c0 的基本作用。对于 Cortex-A7内核来说, c0 作为 MDIR 寄存器的时候其含义如图

image-20230910110902538

bit [31:24]:厂商编号, 0X41, ARM。

bit [23:20]:内核架构的主版本号, ARM 内核版本一般使用 rnpn 来表示,比如 r0p1,其中 r0后面的 0 就是内核架构主版本号。

bit [19:16]:架构代码, 0XF, ARMv7 架构。

bit [15:4]:内核版本号, 0XC07, Cortex-A7 MPCore 内核。

bit [3:0]:内核架构的次版本号, rnpn 中的 pn,比如 r0p1 中 p1 后面的 1 就是次版本号。

2.2 c1 寄存器

c1 寄存器同样通过不同的配置,其代表的含义也不同,如图 :

image-20230910111043784

当 MRC/MCR 指令中的 CRn=c1, opc1=0, CRm=c0, opc2=0 的时候就表示此时的 c1 就是 SCTLR 寄存器,也就是系统控制寄存器,这个是 c1 的基本作用。 SCTLR 寄存器主要是完成控制功能的,比如使能或者禁止 MMU、 I/D Cache 等, c1 作为 SCTLR 寄存器的时候其含义如图:

image-20230910111111179

SCTLR 的位比较多,我们就只看本章会用到的几个位:

bit [13]: V , 中断向量表基地址选择位,为 0 的话中断向量表基地址为 0X00000000,软件可以使用 VBAR 来重映射此基地址,也就是中断向量表重定位。为 1 的话中断向量表基地址为0XFFFF0000,此基地址不能被重映射。

bit [12]: I, I Cache 使能位,为 0 的话关闭 I Cache,为 1 的话使能 I Cache。

bit [11]: Z,分支预测使能位,如果开启 MMU 的话,此位也会使能。

bit [10]: SW, SWP 和 SWPB 使能位,当为 0 的话关闭 SWP 和 SWPB 指令,当为 1 的时候就使能 SWP 和 SWPB 指令。

bit [9:3]:未使用,保留。

bit [2]: C, D Cache 和缓存一致性使能位,为 0 的时候禁止 D Cache 和缓存一致性,为 1 时使能。

bit [1]: A,内存对齐检查使能位,为 0 的时候关闭内存对齐检查,为 1 的时候使能内存对齐检查。

bit [0]: M, MMU 使能位,为 0 的时候禁止 MMU,为 1 的时候使能 MMU。

如果要读写 SCTLR 的话,就可以使用如下命令:

1
2
MRC p15, 0, <Rt>, c1, c0, 0 ;读取 SCTLR 寄存器,数据保存到 Rt 中。
MCR p15, 0, <Rt>, c1, c0, 0 ;将 Rt 中的数据写到 SCTLR(c1)寄存器中。

2.3 c12 寄存器

c12 寄存器通过不同的配置,其代表的含义也不同,如图

image-20230910111303553

当 MRC/MCR 指令中的 CRn=c12, opc1=0, CRm=c0, opc2=0 的时候就表示此时 c12 为 VBAR 寄存器,也就是向量表基地址寄存器。设置中断向量表偏移的时候就需要将新的中断向量表基地址写入 VBAR 中,通过 VBAR 寄存器,可以设置异常向量表的映射地址。如果不把异常向量表
的映射地址告诉 CPU,在发生异常时, CPU 就找不到异常向量表,就无法处理异常 。比如在前面的例程中,代码链接的起始地址为0X87800000,而中断向量表肯定要放到最前面,也就是 0X87800000 这个地址处。所以就需要设置 VBAR 为 0X87800000,设置命令如下:

1
2
ldr r0, =0X87800000 ; r0=0X87800000
MCR p15, 0, r0, c12, c0, 0 ;将 r0 里面的数据写入到 c12 中,即 c12=0X87800000

2.4 c15 寄存器

c15 寄存器也可以通过不同的配置得到不同的含义,参考文档《Cortex-A7 Technical ReferenceManua.pdf》 第 68 页“4.2.16 c15 registers”,其配置如图 :

image-20230910111404866

我们需要 c15 作为 CBAR 寄存器,因为 GIC 的基地址就保存在 CBAR中,我们可以通过如下命令获取到 GIC 基地址:

1
MRC p15, 4, r1, c15, c0, 0 ; 获取 GIC 基础地址,基地址保存在 r1 中。

获取到 GIC 基地址以后就可以设置 GIC 相关寄存器了,比如我们可以读取当前中断 ID,当前中断 ID 保存在 GICC_IAR 中,寄存器 GICC_IAR 属于 CPU 接口端寄存器,寄存器地址相对于 CPU 接口端起始地址的偏移为 0XC,因此获取当前中断 ID 的代码如下:

1
2
3
4
MRC p15, 4, r1, c15, c0, 0 ;获取 GIC 基地址
ADD r1, r1, #0X2000 ;GIC 基地址加 0X2000 得到 CPU 接口端寄存器起始地址
LDR r0, [r1, #0XC] ;读取 CPU 接口端起始地址+0XC 处的寄存器值,也就是寄存器
;GIC_IAR 的值

三、中断使能

中断使能包括两部分,一个是 IRQ 或者 FIQ 总中断使能,另一个就是 ID0~ID1019 这 1020个中断源的使能。

1. IRQ 和 FIQ 总中断使能

IRQ 和 FIQ 分别是外部中断和快速中断的总开关,要想使用 I.MX6U 上的外设中断就必须先打开 IRQ 中断。我们知道寄存器 CPSR 的 I=1 禁止 IRQ,当 I=0 使能 IRQ; F=1 禁止 FIQ, F=0 使能 FIQ。我们还有更简单的指令来完成 IRQ 或者 FIQ 的使能和禁止:

image-20230910111752761

2. ID0 - ID1019 中断使能和禁止

GIC 寄存器 GICD_ISENABLERn 和 GICD_ ICENABLERn 用来完成外部中断的使能和禁止,对于 Cortex-A7 内核来说中断 ID 只使用了 512 个。一个 bit 控制一个中断 ID 的使能,那么就需要 512/32=16 个 GICD_ISENABLER 寄存器来完成中断的使能。同理,也需要 16 个GICD_ICENABLER 寄存器来完成中断的禁止。其中 GICD_ISENABLER0 的 bit[15:0]对应ID15~0 的 SGI 中断, GICD_ISENABLER0 的 bit[31:16]对应 ID31~16 的 PPI 中断。剩下的 GICD_ISENABLER1~GICD_ISENABLER15 就是控制 SPI 中断的。

四、中断优先级设置

1. 优先级数配置

Cortex-A7 的中断优先级可以分为抢占优先级和子优先级,两者同样是可以配置的。 GIC 控制器最多可以支持 256 个优先级,数字越小,优先级越高! Cortex-A7 选择了 32 个优先级。在使用中断的时候需要初始化 GICC_PMR 寄存器,此寄存器用来决定使用几级优先级,寄存器结构如图:

image-20230910111946129

GICC_PMR 寄存器只有低 8 位有效,这 8 位最多可以设置 256 个优先级,其他优先级数设置如表:

image-20230910112124153

I.MX6U 是 Cortex-A7 内核,所以支持 32 个优先级, 因此 GICC_PMR 要设置为 0b11111000。

2. 抢占优先级和子优先级位数设置

抢占优先级和子优先级各占多少位是由寄存器 GICC_BPR 来决定的, GICC_BPR 寄存器结构如图

image-20230910112207791

寄存器 GICC_BPR 只有低 3 位有效,其值不同,抢占优先级和子优先级占用的位数也不同,配置如表:

image-20230910112331142

为了简单起见,一般将所有的中断优先级位都配置为抢占优先级,比如 I.MX6U 的优先级位数为 5(32 个优先级),所以可以设置 Binary point 为 2,表示 5 个优先级位全部为抢占优先级。

3. 优先级设置

前面已经设置好了 I.MX6U 一共有 32 个抢占优先级,数字越小优先级越高。具体要使用某个中断的时候就可以设置其优先级为 0~31。某个中断 ID 的中断优先级设置由寄存器D_IPRIORITYR 来完成,前面说了 Cortex-A7 使用了 512 个中断 ID,每个中断 ID 配有一个优先级寄存器,所以一共有 512 个 D_IPRIORITYR 寄存器。如果优先级个数为 32 的话,使用寄存器 D_IPRIORITYR 的 bit[7:4] 来设置优先级,也就是说实际的优先级要左移 3 位。比如要设置ID40 中断的优先级为 5,示例代码如下:

1
GICD_IPRIORITYR[40] = 5 << 3;