正点原子[第二期]Linux之ARM(MX6U)裸机篇学习笔记-15.1,2,3-GPIO中断控制实验

news2025/1/21 15:25:03

前言:

本文是根据哔哩哔哩网站上“正点原子[第二期]Linux之ARM(MX6U)裸机篇”视频的学习笔记,在这里会记录下正点原子 I.MX6ULL 开发板的配套视频教程所作的实验和学习笔记内容。本文大量引用了正点原子教学视频和链接中的内容。

引用:

正点原子IMX6U仓库 (GuangzhouXingyi) - Gitee.com

《【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.5.2.pdf》

正点原子资料下载中心 — 正点原子资料下载中心 1.0.0 文档

正文:

本文是 “正点原子[第二期]Linux之ARM(MX6U)裸机篇--第15.1, 15.2,15.3 讲” 的读书笔记。第15讲主要是介绍I.MX6U处理器GPIO中断控制实验。本节将参考正点原子的视频教程第15讲和配套的正点原子开发指南文档进行学习。

0. 概述

中断系统是一个处理器的重要的组成部分,中断系统极大的提高了CPU的执行效率,在学习STM32的时候就经常用到中断。本章就是通过与STM32的对比来学习一下 Cortex-A7(I.MX6U)中断系统和Cortex-M(STM32)中断系统的异同,同时,本章会将I.MX6U的一个IO作为输入中断,借此来讲解如何对I.MX6U的中断系统进行编程。

1. Conrtex-A7 中断系统详解

1.1 STM32中断系统回顾

STM32的中断系统主要有以下几个关键点:

  1. 中断向量表。
  2. NVIC(内嵌向量中断控制器,Nested Vector Interrupt Controller)。
  3. 中断使能。
  4. 中断服务函数。
1. 中断向量表

中断向量表是一个表,这个表里面存放的是中断向量。中断服务程序的入口地址或存放中断服务程序的首地址称为中断向量表,因此中断向量表是一些列中断服务程序入口地址组成的表。这些中断服务程序(函数)在中断向量表中的位置是由半导体厂商定好的,当某个中断被触发以后就会自动跳转到中断向量表中对应的中断服务程序(函数)入口地址处。中断向量表在整个程序的组前面,比如 STM32F103 的中断向量表如下所示:

上图示例代码就是 STM32F103 的中断向量表,中断向量表都是链接到代码的最前面,比如一般ARM处理器都是从 0x00000000 开始执行指令的,那么中断向量表就是从 0x0000_0000 开始存放的。示例代码中的第一行 “__initial_sp” 就是第一条中断向量,存放的是栈顶指针,接下来第2行复位中断函数 Reset_Handler 的入口地址,依次类推,知道第27行的最后一个中断服务函数 DMA2_Channel4_5_IRQHandler 的入口地址,这样 STM32F103的中断向量表就建好了。

我们说ARM处理器都是从地址 0x0000_0000 开始运行的,但是我们学习STM32的时候代码是下载到 0x80_0000 开始的存储区中。因此中断向量表是存放到 0x80_0000 地址处的,而不是 0x0000_0000 ,这样不就出错了么?为了解决这个问题,Cortex-M 架构引入了一个新的概念-中断向量表偏移,通过中断向量表偏移就可以将中断向量表存放到任意地址处,中断向量表偏移配置在函数 SystemInit 中完成,通过向 SCB_VTOR 寄存器写入新的中断向量表首地址即可,代码如下所示:

第8行和第10行就是设置中断向量表偏移,第八行是将中断向量表设置到 RAM 中,第10行是将中断向量表设置到 ROM 中,也就是地址 0x80_0000 处。第10行用到了 FLAS_BASSE 和 VEC_TAB_OFFSET ,这两个都是宏,定义如下所示:

#define FLASH_BASE                ((uint32_t)0x08000000)

#define VECT_TAB_OFFSET      0x0 

第10行的代码就是:SCB->VTOR = 0x0800_0000,中断向量表偏移设置完成。通过上面的讲解我们了解了STM32中断有关的概念:中断向量表和中断偏移,那么这跟  I.MX6U 有什么关系呢?因为I.MX6U 使用的是 Cortex-A7 内核也有中断向量表和中断向量表偏移,而且其含义和 STM32 是一模一样的!指示用到的寄存器不同而已,概念完全相同。

2. NVIC(内嵌向量中断控制器)

中断系统得有个管理结构,对于 STM32 这种 Cortex-M 内核的单片机来说这个管理机构叫做 NVIC,全程叫做 Nested Vector Interrupt Controller。关于 NVIC 本教程不做详细的讲解,既然 Corex-M 内核有个中断系统的管理结构--NVIC,那么 I.MX6U 所使用的 Corex-A7 内核是不是也应该有一个中断管理机构?答案是肯定的,不过 Cortex-A7 内核的中断管理机构不叫做 NVIC ,而是叫做 GIC,全程是 Geneal Interrupt Controller ,后面我们会详细的讲解 Cortex-A7 内核的 GIC。

3. 中断使能

要使用某个外设的中断,肯定要先使能这个外设的中断,以 STM32F103 的 PE2 这个IO为例,假如我们要使用 PE2 的输入中断肯定要使用下面的代码来使能对应的中断:

NVIC_InitStructure.NVIC_IRQChannel = EXIT2_IRQn;

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02; //抢占优先级2

NVIC_InitStructure.NVIC_IRQChannelSubPriority = x002;             //子优先级2

NVIC_InitStructure.NVIC_IRQChannelCmd = ENALBE;                 //使能外部中断通道

NVIC_Init(&NVIC_InitStructure);

上述代码就是使能 PE2 对应的 EXIT2 中断,同理,如果要使用 I.MX6U 的某个中断的话也需要使能其对应的中断。

4. 中断服务函数

我们使用中断的目的就是为了使用中断服务函数,当中断发生以后中断服务函数就会被调用,我们要处理的工作就可以放到中断服务函数中去完成。同样以 STM32F103 的 PE2 为例,其中断服务函数如下图所示:

/* 外部中断2 服务程序 */

void EXIT2_IRQHandler(void)

{

        /* 中断处理代码 */

}

当PE2引脚的中断触发以后就会调用其对应的中断服务函数 EXIT2_IRQHandler,我么可以在函数 EXIT2_IRQHandler 中提那家中断处理代码。同理,I.MX6U 也有中断服务函数,当某个外设发生中断以后就会调用其对应的中断服务函数。

通过对 STM32 中断系统的回顾,我们知道了 Cortex-M 内核的中断处理过程,那么 Cortex-A7 内核的中断处理过程是否是一样的,有什么异同呢?接下来我们就带着这样的疑问来学习 Cortex-A7 内核的中断处理系统。

1.2 Cortex-A7 中断系统简介

 跟STM32一样,Cortex-A7 内核也有中断向量表,中断向量表也是在代码的最前面。Cortex-A7 内核有8个异常中断,这8个异常中断的中断向量表如下表所示:

向量地址中断类型中断模式
0x00复位中断(Reset)特权模式(SVC)
0x04未定义指令中断(Undefined Instruction)未定义指令终止模式(Undef)
0x08软中断(Software Interrupt, SWI)特权模式(SVC)
0x0C指令预取中止中断(Prefetch Abort)中止模式
0x10数据访问中止 (Data Abort)中止模式
0x14未使用(Note Used)未使用
0x18IRQ中断(IRQ Interrupt)外部中断模式(IRQ)
0x1CFIRQ中断(FIRQ Interrupt)快速中断模式(FIRQ)

中断向量表里都是中断服务函数的入口地址,因此一款新芯片有什么中断都是可以从中断向量表看出来的。从上表中可以看出,Cortex-A7 内核一共有 8 个中断,而且还有一个中断向量未使用,实际只有7个中断。和“示例代码 17.1.1.1”中的 STM32F103 中断向量表比起来少了很多!难道一个能跑 Linux 的芯片只有这7个中断?明显是不可能的!那类似 STM32 中的 EXIT9-5_IRQHandler, TIM2_IRQHandler 这样的中断向量在哪里?I2C, SPI,定时器等等的中断怎么处理呢?

这个就是 Cortex-A 和 Cortex-M 在中断向量表这一块的区别,对于 Cortex-M 内核来说,中断向量表列举出了一款芯片所有的中断向量,包括芯片外设的所有中断。对于 Cortex-A 内核来说并没有这么做,在上表中有个 IRQ 中断,Cortex-A 内核CPU的所有外部中断都属于这个 IRQ 中断,当任意一个外设中断发生的时候都会触发 IRQ 中断。在IRQ中断服务函数中就可以读取指定的寄存器来判断发生的具体事什么中断,进而根据具体的中断做出相应的处理。这些外部中断和IRQ的关系如下图所示:

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

在表 17.1.2.1 中一共有7个中断,简单介绍一下这7个中断:

  1. 复位中断(Reset),CPU复位以后就会进入复位中断,我们可以在复位中断服务函数里面做一些初始化工作,比如初始化SP指针,DDR等等。
  2. 未定义指令中断(Undefined Instruction),如果指令不能识别的话就会产生此中断。
  3. 软中断(Software Interrupt,SWI),由SWI指令引起的中断,Linux系统调用会用 SWI 指令来一起软中断,通过软中断来陷入到内核空间。
  4. 指令预取中止中断(Prefetch Abort),预取指令出错的时候会产生此中断。
  5. 数据访问中止中断(Data Abort),访问数据出错的时候会产生此中断
  6. IRQ中断(IRQ Interrupt),外部中断,前面已经说过了,芯片内部的外设中断都会引起此中断的发生。
  7. FIQ中断(FIQ Interrupt),快速中断,如果需要快速处理中断的话就可以使用此中断。

在上面的7个中断中,我们常用的就是复位中断和IRQ中断,所以我们需要编写这两个中断的中断服务函数,稍后我们会讲解如何编写对应的中断服务函数。首先我们要将表 17.1.2.1 的内容来创建中断向量表,中断向量表处于程序最开始的地方,比如我们前面例程 Start.S 的文件最前面,中断向量表如下:

                                         示例代码 17.1.1.1 Cortex-A7 向量表模板

.global _start

_start:

        ldr pc, =Reset_Handler                /*复位中断*/

        ldr pc, =Undefined_Handler        /*未定义指令中断*/

        ldr pc, =SVC_Handler                 /*SVC(SuperVisor)中断*/

        ldr pc, =PrefAbort_Handler         /*预取中止中断*/

        ldr pr, =DataAbort_Handler         /*数据中止中断*/

        ldr pc, =NotUsed_Hanlder          /*未使用中断*/

        ldr pc, =IRQ_Handler                 /*IRQ中断*/

        ldr pc, =FIQ_Handler                  /*FIQ(快速中断)*/

/* 复位中断 */

Reset_Handler:

        /*复位中断具体处理过程*/

/*未定义中断*/

Undefined_Handler:

        ldr r0, =Undefined_Handler

        bx r0

/*SVC中断*/

SVC_Handler:

        ldr r0, =SVC_Handler
        bx r0

/*预取中止中断*/

PrefAbort_Handler:

        ldr r0, =PerfAbort_Handler

        bx r0

/*数据中止中断*/

DataAbort_Handler:

        ldr r0, =DataAbort_Handler

        bx r0


/*未使用的中断*/

NotUsed_Handler:

        ldr r0, =NotUserd_Handler

        bx r0


/* IRQ中断!重点!!!!*/

IRQ_Handler:

        /*IRQ中断具体处理过程*/

/*FIQ中断*/
FIQ_Handler:

        ldr r0, =FIQ_Handler

        bx r0

第4到11行时中断向量表,当指定的中断发生以后就会调用对应的中断服务函数,比如复位中断发生以后会执行第4行的代码,也就是调用 Reset_Handler,函数 Reset_Handler 就是复位中断的中断服务函数,其它中断同理。

第14到50行就是对应的中断服务函数,中断服务函数都是用汇编编写的,我们实际需要编写的只有复位中断服务函数 Reset_Handler 和 IRQ中断服务函数  IRQ_Handler,其它的中断本教程没有用到,所以是死循环。在编写复位(Reset)中断服务函数和IRQ中断服务函数之前我们还需要了解一些其他的知识,否则的话就没法编写。

1.3 GIC 控制器简介
1. GIC控制器总览

STM32(Cortex-M)的中断控制器叫做NVIC,I.MX6U(Cortex-A7)的中断控制器叫做GIC,关于GIC的详细内容参考开发板光盘中的文档《ARM Generic Interrupt Controller(ARM GIC控制器)V2.0.pdf》。

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等,CIC V3 和 V4 是给 ARMv8-A/R 构架使用的,也就是64为芯片使用的。I.MX6U 是 Cortex-A7 内核的,所以我们主要讲解 GIC V2。GIC V2 最多支持8个内核。ARM会根据GIC版本的不同研发出不同的IP核,哪些半导体厂商直接购买对应的IP核即可,比如ARM针对 GIC  V2 就开发出了 GIC400 这个中断控制器IP核。

当GIC接收到外部中断信号以后就会报给ARM内核,但是ARM内核只提供了4个信号给GIC来汇报中断情况:VFIQ,VIRQ,FIQ,IRQ,他们之间的关系如下图所示:

在图 17.1.3.1 中,GIC接收众多的外部中断,然后对其进行处理,最终就只通过四个信号报给ARM内核,这四个信号的含义如下:

  • VFIQ:虚拟快速FIQ
  • VIRQ:虚拟外部IRQ
  • FIQ:快速中断IRQ
  • IRQ:外部中断IRQ

VFIQ和VIRQ是针对虚拟化的,我们不讨论虚拟化,剩下的就是FIQ和IRQ了,我们前面讲过很多次了。本教程我们只使用IRQ,所以相当于GIC最终向ARM内核就上报了一个IRQ信号。那么GIC是如何完成工作的呢?GICV2的裸机结构如图17.1.3.2 所示:

图 17.1.3.2 中左侧部分就是中断源,中间部分就是GIC控制器,最右侧就是中断控制器向处理器内核发送的中断信息。我们重点要看的肯定是中间的GIC部分,GIC将众多的中断源分为三类:

  1. SPI(Shared Peripheral Interrupt),共享中断,顾名思义,所有的Core共享的中断,这个是最常见的,哪些外部中断都属于SPI中断(注意!不是SPI总线的那个中断)。比如按键中断,串口中断等等,这些中断所有的Core都可以处理,不限定特定的Core。
  2. PPI(Private Peripheral Interrupt),私有中断,我们锁了GIC是支持多核的,每个核肯定有自己独有的中断。这些独有的中断肯定是要指定的核心处理,因此这些中断就叫做私有中断。
  3. SGI(Software-generated Interrupt),软件中断,由软件触发引起的中断,通过向寄存器 GICD_SGIR 写入数据来触发,系统会使用 SGI 中断来完成多核之间的通信。
2. 中断ID

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

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

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

ID31~ID1019:这998个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”小节,中断源如表 17.1.3.1 所示:

IRQID中断源描述
032boot用于启动异常的时候通知内核
133ca7_paltformDAP中断,调试端口访问请求中断
234sdmaSDMA中断
335tcsTSC(触摸)中断
436snvs_lp_wrapper
snvs_hp_wrapper
SNVS中断
......
125157保留
126158保留
127159pmuPMU中断

限于篇幅原因,表 17.1.3.1 中并没有给出并没有给出 I.MX6U 完整的中断源,完整的中断源自行查阅《I.MX6ULL 参考手册》的 3.2 小节。代开裸机例程 “9_int”,我们在前面移植了 NXP SDK 中的文件  MCIMX6Y2C.h ,在此文件中定义了一个枚举类型 IRQn_Type ,此枚举类型就枚举出了 I.MX6U 的所有中断,代码如下所示:

 3. GIC逻辑分块

GIC构架分为两个逻辑块:Distributor 和 CPU Interface,也就是分发器端和CPU接口端。这两个逻辑块的含义如下:

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

  1. 全局中断使能控制
  2. 控制每一个中断的使能或者关闭
  3. 设置每个中断的优先级
  4. 设置每个中断的目标处理器列表
  5. 设置每个外部中断的触发方式:电平触发或边沿触发
  6. 设置每个中断属于组0还是组1

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

  1. 使能或者关闭发送到CPU Core的中断请求信号。
  2. 应答中断。
  3. 通知中断处理完成。
  4. 设置优先级掩码,通过掩码来设置哪些中断不需要上报给CPU Core。
  5. 定义抢占策略。
  6. 当多个中断到来的时候,选择优先级最高的中断通知给CPU Core。

例程 "9_int" 的文件中 core_ca7.h 定义了GIC结构体,此结构体里面的寄存器分为了发送端和CPU接口端,寄存器定义如下所示:

“示例代码 17.1.3.2”中的结构体 GIC_Type 就是 GIC 控制器,列举出了GIC控制器的所有寄存器,可以通过结构体 GIC_Type 来冯文GIC的所有寄存器。

第5行GIC分发器端的寄存器,其相对于GIC基地址偏移 x01000(4KB),因此我们获取到GIC基地址以后只需要加上 0x1000 即可以访问 GIC分发器端寄存器。

第 51 行是GIC的CPU接口端相关寄存器,其相对于GIC的基地址偏移为0x2000(8KB),同样的获取到GIC的基地址之后值需要加上 0x2000 即可访问GIC的GPU接口寄存器。那么问题来了,GIC控制器的地址在哪里呢?这个就要用到 Cortex-A 的 CP15 协处理器了,下一节就讲解 CP15 协处理器。

1.4 CP15协处理器

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

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

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

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

        MCR{cond} p15, <opc1>, <Rt>, <CRn>, <CRm>, <opc2>

  • cond: 指令执行的条件码,如果忽略的话就表示无条件执行
  • opc1:协处理要执行的操作码。
  • Rt:ARM源寄存器,要写入到CP15协处理器寄存器的数据就保存在此寄存器中。
  • CRn:CP15协处理器的目标寄存器
  • CRm:协处理器中附加的目标寄存器或者源操作数寄存器,如果不需要附加信息就将CRm设置为C0,否则结果不可预测。
  • opc2:可选的协处理器特定操作码,当不需要的时候要设置0。

MRC的指令格式和MCR一样,只不过在MRC指令中的Rt就是目标寄存器,也就是从C15协处理器指定寄存器读出来的数据会保存在Rt中。而CRn就是源寄存器,也就是要读取的协处理器寄存器。

假如我们要将CP15协处理器中 C0 寄存器的值读取到 R0 寄存器中,那么可以使用如下的命令:

MCR{cond} p15, <opc1>, <Rt>, <CRn>, <CRm>, <opc2>

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

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

1. c0寄存器:

比如 c0 在不同搭配情况情况下含义如17.1.4.1 所示:

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

在图 17.1.4.2 中各位所代表的含义如下:

  • bit31:24:厂商编号, 0X41, ARM。
  • bit23:20:内核架构的主版本号, ARM 内核版本一般使用 rnpn 来表示,比如 r0p1,其中 r0 后面的 0 就是内核架构主版本号。
  • bit19:16:架构代码, 0XF, ARMv7 架构。
  • bit15:4:内核版本号, 0XC07, Cortex-A7 MPCore 内核。
  • bit3:0:内核架构的次版本号, rnpn 中的 pn,比如 r0p1 中 p1 后面的 1 就是次版本号。
2. c1寄存器

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

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

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

  • bit13: V , 中断向量表基地址选择位,为 0 的话中断向量表基地址为 0X00000000,软件可以使用 VBAR 来重映射此基地址,也就是中断向量表重定位。为 1 的话中断向量表基地址为 0XFFFF0000,此基地址不能被重映射。
  • bit12: I, I Cache 使能位,为 0 的话关闭 I Cache,为 1 的话使能 I Cache。
  • bit11: Z,分支预测使能位,如果开启 MMU 的话,此位也会使能。
  • bit10: SW, SWP 和 SWPB 使能位,当为 0 的话关闭 SWP 和 SWPB 指令,当为 1 的时候就使能 SWP 和 SWPB 指令。
  • bit9:3:未使用,保留。
  • bit2: C, D Cache 和缓存一致性使能位,为 0 的时候禁止 D Cache 和缓存一致性,为 1 时使能。
  • bit1: A,内存对齐检查使能位,为 0 的时候关闭内存对齐检查,为 1 的时候使能内存对齐检查。
  • bit0: M, MMU 使能位,为 0 的时候禁止 MMU,为 1 的时候使能 MMU。

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

MCR{cond} p15, <opc1>, <Rt>, <CRn>, <CRm>, <opc2>

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

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

在图 17.1.4.4 中当 MRC/MCR 指令中的 CRn=c12, opc1=0, CRm=c0, opc2=0 的时候就表示此时 c12 为 VBAR 寄存器(Vector Base Address Register),也就是向量表基地址寄存器。设置中断向量表偏移的时候就需要将新的中断向量表基地址写入 VBAR 中,比如在前面的例程中,代码链接的起始地址为0X87800000,而中断向量表肯定要放到最前面,也就是 0X87800000 这个地址处。所以就需要设置 VBAR 为 0X87800000,设置命令如下:

MCR{cond} p15, <opc1>, <Rt>, <CRn>, <CRm>, <opc2>

ldr r0, =0X87800000 ; r0=0X87800000
MCR p15, 0, r0, c12, c0, 0 ;将 r0 里面的数据写入到 c12 中,即 c12=0X87800000
4. c15 寄存器

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

MCR{cond} p15, <opc1>, <Rt>, <CRn>, <CRm>, <opc2>

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

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

MCR{cond} p15, <opc1>, <Rt>, <CRn>, <CRm>, <opc2>

MCR p15,4,r1, c15,c0,0    ;获取GIC的基地址
ADD r1, r1, #0x2000       ;GIC低地址+0x2000得到CPU接口端寄存器的起始地址
ADD r1, r1, #0xC          ;读取CPU接口端寄存器起始地址+0XC处的寄存器,
ldr r2, [r1]              ;也就是寄存器 GIC_IAR 的值

关于CP15协处理器就讲解到治理,简单总结一下

  • 通过c0寄存器可以获取到处理器内核信息
  • 通过c1寄存器可以使能或禁用MMU,I/D Cache等
  • 通过c12寄存器可以设置中断向量偏移
  • 通过c15寄存器可以获取到GIC基地址。

关于CP15协处理器寄的其它寄存器大家自行查阅本节前面列举的 2 份 ARM 官方资料。

1.5 中断使能

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

1. IRQ和FIQ总中断使能

IRQ和FIRQ分别是外部中断和快速中断的的总开关,就类似家里买的进户总电闸,然后 ID0~ID1019 这1020 个中断源就类似家里面的各个电器开关。要想开电视,那肯定要保证进户总电闸是打开的,因此要想使用I.MX6U上的外设中断就必须先打开 IRQ 中断(本教程不使用FIQ)。在“6.3.2 程序状态寄存器”小节已经讲过了,

寄存器 CPSR 的 I=1 禁止 IRQ,当 I=0 使能IRQ;F=1禁止FIQ,F=0使能FIQ。 

 我们还有更简单的指令来完成IRQ或FIQ的使能和禁止,图表 17.1.5.1 所示:

指令描述
cpsid i禁止IRQ中断
cpside i使能IR中断
cpsid f禁止FIQ中断
cpsid f使能FIQ中断
2. ID0~ID1029 中断使能和禁止

GIC寄存器 GICD_ISENABLERn 和 GICD_ICENABLERn 用完成外部中断的使能和禁止,对于 Cortex-A7 内核来说中断ID只使用了512个。一个bit控制一个中断ID的使能,那么就需要 512/32 = 16 个  GICD_ISENABLER 寄存器来完成中断的使能。同理,也需要16个 GICD_ICENABLER 寄存器完完成中断的禁止。

其中 GIC_ISENABLER0 的 bit[15:0] 对应 ID15~0 的SGI中断,GICD_ISENABLER0 的 bit[31:16] 对应 ID31~16 的 PPI中断。剩下的 GICD_ISENBALBER1~GICD_ISENABLER15就是控制SPI中断的。

1.6 中断优先级设置
1. 优先级数设置

学过STM32的都知道 Cortex-M 的中断优先级分为抢占优先级和子优先级,两者是可以配置的。同样的,Cortex-A7 的中断优先级也可以分为抢占优先级和子优先级,两者同样是可以配置的。

GIC控制器最多可以支持256个优先级,数字越小优先级越高!Conrtex-A7选择了32个优先级。

在使用中断的时候需要初始化 GICC_PMR 寄存器,此寄存器用来决定使用几级优先级,寄存器的结构如图 17.1.6.1 所示:

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

bit7:0优先级数
1111 1111256个优先级
1111 1110 128个优先级
1111 110064个优先级
1111 1000 32个优先级
1111 000016个优先级

I.MX6U 是 Cortex-A7 内核,所以支持32个优先级,一次 GICC_PMR 要设置为 0b1111 1000 。

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

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

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

Binary Point抢占优先级域子优先级域描述
0[7:1][0]7级抢占优先级,1级子优先级
1[7:2][1:0]6级抢占优先级,2级子优先级
2[7:3][2:0]5级抢占优先级,3级子优先级
3[7:4][3:0]4级抢占优先级,4级子优先级
4[7:5][4:0]3级抢占优先级,5级子优先级
5[7:6][5:0]2级抢占优先级,6级子优先级
6[7:7][6:0]1级抢占优先级,7级子优先级
7[7:0]0级抢占优先级,8级子优先级

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1673838.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

全自动发布小红薯思维导图笔记(附爆款AI提示词)

全自动电脑接管&#xff0c;帮你生成图片、文案&#xff0c;然后还帮你自动发布。 大家好&#xff0c;我是大胡子&#xff0c;专注于研究RPA实战与解决方案&#xff0c;今天来介绍一款全自动生产内容并发布小红薯的神器&#xff0c;最后附有AI提示词&#xff0c;记得收藏点赞…

【C#】学习获取程序执行路径,Gemini 帮助分析

一、前言&#xff1a; 在Delphi中&#xff0c;如果想要获取当前执行程序的目录&#xff0c;程序代码如下&#xff1a; ExtractFilePath(ParamStr(0)); 今天在分析一个别人做的C#程序时看到了一段C#代码&#xff0c;意思是获取执行程序所在的文件目录&#xff1a; public stat…

[图解]实现领域驱动设计译文暴露的问题04

0 00:00:00,960 --> 00:00:03,020 今天我们继续说一下 1 00:00:03,460 --> 00:00:05,350 实现领域驱动设计 2 00:00:05,630 --> 00:00:08,120 译文里面暴露的问题 3 00:00:10,630 --> 00:00:14,740 前面三个视频&#xff0c;我们提到了第①句 4 00:00:15,550 -…

国家网络与信息系统安全产品质量检验检测中心是什么机构?成立于一年?有什么用?

在当今信息化快速发展的时代&#xff0c;网络安全问题日益凸显其重要性&#xff0c;而检测中心则扮演着守护网络安全、保障信息系统稳定运行的关键角色。今天我们就来聊聊国家网络与信息系统安全产品质量检验检测中心是什么机构&#xff1f;成立于一年&#xff1f;有什么用&…

RedisTemplate操作Redis详解之连接Redis及自定义序列化

连接到Redis 使用Redis和Spring时的首要任务之一是通过IoC容器连接到Redis。为此&#xff0c;需要java连接器&#xff08;或绑定&#xff09;。无论选择哪种库&#xff0c;你都只需要使用一组Spring Data Redis API&#xff08;在所有连接器中行为一致&#xff09;&#xff1a;…

基础模型的推理:综述

24年1月论文“A Survey of Reasoning with Foundation Models”&#xff0c;来自香港中文大学、华为、香港大学、上海AI实验室、香港科技大学、大连理工、北京大学、清华大学、合肥工大、中国人民大学、复旦大学和香港科技大学广州分校。 推理是解决复杂问题的关键能力&#x…

Windows/Mailing

Mailing Enumeration nmap 使用 nmap 扫描系统&#xff0c;发现对外开放了如下端口 ┌──(kali㉿kali)-[~/vegetable/HTB] └─$ nmap -sC -sV -oA nmap 10.10.11.14 Starting Nmap 7.93 ( https://nmap.org ) at 2024-05-08 01:46 EDT Nmap scan report for 10.10.11.14 H…

软件各阶段资料(需求设计,系统架构,开发文档,测试文档,运维阶段的部署维护文档,概要设计,详细设计)

一、 引言 &#xff08;一&#xff09; 编写目的 &#xff08;二&#xff09; 范围 &#xff08;三&#xff09; 文档约定 &#xff08;四&#xff09; 术语 二、 项目概要 &#xff08;一&#xff09; 建设背景 &#xff08;二&#xff09; 建设目标 &#xff08;三&#xff0…

linux上用Jmter进行压测

在上一篇中安装好了Jmeter环境&#xff0c;在这一篇中将主要分享如何使用jmeter在linux中进行单机压测。 1.项目部署 在这里我们先简单部署一下测试环境&#xff0c;所用到的项目环境是个jar包&#xff0c;先在linux上home目录下新建app目录&#xff0c;然后通过rz命令将项目ja…

一些近来对内网攻防的思考

我知道我最近托更托了很久了&#xff0c;其实也不是小编懒啊 这小编也是一直在写&#xff0c;但是遇到的问题比较多&#xff08;我太菜了&#xff09;&#xff0c;所以一直拖着。 但是总不能不更吧 那就讲一下进来的一些内网攻防的思考吧 1.CrossC2上线Linux到CS(成功) …

程序设计文档—软件分析报告(Word)

第3章 技术要求 3.1 软件开发要求 第4章 项目建设内容 第5章 系统安全需求 5.1 物理设计安全 5.2 系统安全设计 5.3 网络安全设计 5.4 应用安全设计 5.5 对用户安全管理 5.6 其他信息安全措施 第6章 其他非功能需求 6.1 性能设计 6.2 稳定性设计 6.3 安全性设计 6.4 兼容性设计…

DriveWorld:通过自动驾驶世界模型进行 4D 预训练场景理解

24年5月北大论文“DriveWorld: 4D Pre-trained Scene Understanding via World Models for Autonomous Driving”。 近年来&#xff0c;以视觉为中心的自动驾驶因其较低的成本而受到广泛关注。预训练对于提取通用表示至关重要。然而&#xff0c;当前以视觉为中心的预训练通常依…

【Linux】进程信号(2万字)

目录 前言 一、生活角度的信号 1.1、我们来见一见信号&#xff1a; 1.2、模拟一下 kill 指令 二、信号的处理 三、产生信号的5种方法 3.1、kill命令 3.2、键盘可以产生信号 3.3、3种系统调用 3.4、软件条件 3.5、异常 四、比较 core 和 Term 五、键盘信号产生 六…

Docker安装、使用及常用命令

一、Docker是什么&#xff1f; Docker是一种开源的容器化技术&#xff0c;允许开发者将应用及其运行环境打包在一个轻量级、可移植的容器中。这样&#xff0c;不论在开发、测试还是生产环境中&#xff0c;应用都能在任何Docker支持的平台上无缝运行。Docker使用Dockerfile来自…

人形机器人场景应用全解析,2024睿抗 AI ROBOT创新挑战赛火热报名中!

人工智能&#xff08;AI&#xff09;已成为推动科技革命和产业变革的关键力量。随着大模型等AIGC技术的迅猛发展&#xff0c;AI正深刻改变我们的生活并重新定义生产方式。越来越多人期望将AI技术从纯粹的思维和计算扩展到与物理世界的互动中&#xff0c;即发展具身智能。 为了推…

网络库-libcurl介绍

1.简介 libcurl 是一个功能强大的库&#xff0c;支持多种协议&#xff0c;用于数据传输。它广泛应用于实现网络操作&#xff0c;如HTTP、HTTPS、FTP、FTPS、SCP、SFTP等。libcurl 提供了丰富的 API&#xff0c;可以在多种编程语言中使用。 libcurl 主要特点 支持多种协议&am…

812寸硅片为什么没有平边(flat)?

知识星球&#xff08;星球名&#xff1a;芯片制造与封测社区&#xff0c;星球号&#xff1a;63559049&#xff09;里的学员问&#xff1a;上期种说2&#xff0c;4&#xff0c;6寸硅片都有平边&#xff0c;那为什么8&12寸硅片只有一个notch&#xff1f;为什么不能像小尺寸晶…

抖店商家选品误区,看你中了几条?

我是王路飞。 作为抖店的核心&#xff0c;选品的重要性自然不言而喻。 你跟达人沟通的重点是产品&#xff0c;与厂家沟通的重点也是产品&#xff0c;产品不行&#xff0c;一切都白搭。 然而很多新手商家刚开始做抖店的时候&#xff0c;总是选不到比较好的品。 今天给你们总…

「51媒体」邀请媒体参会报道和媒体发稿有啥不同

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 媒体参会报道和媒体发稿是新闻报道的两种不同形式&#xff0c;它们的主要区别在于内容来源、报道方式和目的。 内容来源&#xff1a; 媒体参会报道&#xff1a;通常指的是记者或媒体代…

STM32:EXTI—外部中断的初始化

文章目录 1、中断1.2 中断系统1.3 中断执行流程 2、STM32中断2.2EXTI&#xff08;外部中断&#xff09;2.3 EXTI 的基本结构2.4 AFIO复用IO口 3、NVIC基本结构3.2 NVIC优先级分组 4、配置EXTI4.2 AFIO 库函数4.3 EXTI 库函数4.4 NVIC 库函数4.5 配置EXTI的步骤4.6 初始化EXTI 1…