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

前言:

本文是根据哔哩哔哩网站上“正点原子[第二期]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个优先级位全部为抢占优先级。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

山姆·奥特曼接受All-in Podcast采访

前言 在“All-in Podcast”播客中&#xff0c;OpenAI的CEO山姆奥特曼广泛讨论了人工智能的多个关键议题。他涉及了推理计算、开源模型的发展、GPT-5语言模型的进展&#xff0c;并对AI监管、全民基本收入&#xff08;UBI&#xff09;政策、智能体如何改变应用交互&#xff0c;以…

Springboot自动装配源码分析

版本 <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.3.4.RELEASE</version><relativePath/> <!-- lookup parent from repository --> </par…

GPT搜索鸽了!改升级GPT-4

最近OpenAI太反常&#xff0c;消息一会一变&#xff0c;直让人摸不着头脑。 奥特曼最新宣布&#xff1a;5月13日开发布会&#xff0c;不是GPT-5&#xff0c;也不是盛传的GPT搜索引擎&#xff0c;改成对ChatGP和GPT-4的升级&#xff5e; 消息一出&#xff0c;大伙儿都蒙了。 之…

【cocos creator】2.4.0 import android.support.v4.app.ActivityCompat;失败的解决方案

时间是2024年5月&#xff0c;某cocos creator项目用的是2.4.0编辑器。需求是获取录音权限&#xff0c;需要import ActivityCompat。但是失败&#xff0c;提示Cannot resolve symbol app。 尝试了一些方案失败之后&#xff0c;决定升级cocos creator编辑器版本。升级到2.4.10。…

Maven:继承和聚合

Maven高级 分模块设计和开发 如果在我们自己的项目中全部功能在同一个项目中开发,在其他项目中想要使用我们封装的组件和工具类并不方便 不方便项目的维护和管理 项目中的通用组件难以复用 所以我们需要使用分模块设计 分模块设计 在项目设计阶段,可以将大的项目拆分成若…

【快捷上手】UnrealEngine 的 关卡流 LevelStreaming 的三种加载方式

关键词&#xff1a; Unreal Engine&#xff0c;UE&#xff0c; LevelStreaming&#xff0c;动态&#xff0c;关卡&#xff0c;加载&#xff0c;切换关卡&#xff0c;换地图&#xff0c;子地图&#xff0c;子场景&#xff0c;子关卡&#xff0c;分包加载&#xff0c;动态载入 …

IT服务台的演变趋势

在技术进步和用户期望变化的推动下&#xff0c;IT服务台正在经历重大变化。IT服务台的未来将主要受到以下趋势的推动&#xff1a; 先进的人工智能和认知技术 预计高级人工智能 &#xff08;AI&#xff09; 和认知技术在 IT 服务台中的集成度会更高。通过将 IT 服务台集成到 IT…

点是否在三角形内C++源码实现

原理 思路&#xff1a; 面积和&#xff1a; abc obcaocabo,应该有更简洁的方法&#xff0c;但是这个方法思路更简单 代码实现: 注意二维向量的叉乘后&#xff0c;是垂直于平面的向量&#xff0c;相当于z为0三维向量叉乘&#xff0c;所以只有z维度有值&#xff0c;xy0. flo…

BMS-HiL系统方案设计

系统集成了业内著名 NI 公司的软硬件平台。 系统设计采用分布式设计模式。主控上位机作为整个实验的管理者主要设计软件交互和 流程管理的业务&#xff1b;下位机主要业务为序列执行与设备调用&#xff0c;各模块详细测试方案如下所示。 系统搭建使用 PXI 系统技术&#xff0c;…

98%!汽车贷款行业合成身份欺诈案激增

近年来&#xff0c;合成身份欺诈者以汽车贷款行业为最大目标&#xff0c;导致 2023 年汽车贷款行业的欺诈尝试增加了 98%&#xff0c;损失高达 79 亿美元。Point Predictive 对 1.8 亿份贷款申请的研究发现&#xff0c;收入和就业信息不实、合成身份和信用洗白几乎占汽车贷款机…

vs2017编译libjpeg的32和64位的库

1.下载libjpeg源码&#xff1a;http://www.ijg.org/files/ 2. 我下载的版本是&#xff1a;jpegsr9c.zip 3. 解压jpegsr9c.zip &#xff0c;解压目录&#xff1a;D:\libjpeg\jpeg-9c 4. 将C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Include目录下的Win32.Mak文件拷贝…

netty配置SSL、netty配置https(生产环境)

netty配置SSL、netty配置https&#xff08;生产环境&#xff09; 上一篇提到了如何在开发环境使用SSL&#xff1a;https://lingkang.top/archives/netty-pei-zhi-ssl 转自&#xff1a;https://lingkang.top/archives/netty-pei-zhi-https 那么netty如何使用可信任的证书呢&a…

排除对象属性序列化的三种方式

说明&#xff1a;在项目里&#xff0c;经常可以看到以下日志内容&#xff0c;将对象序列化后直接打印出来&#xff0c;观察对象数据&#xff0c;判断当前处理逻辑正确与否。 &#xff08;以下信息来自&#xff1a;https://www.tl.beer/randbankcard.html生成器&#xff0c;信息…

优秀的 Java 项目,代码都是如何分层的?

在Java中&#xff0c;常见的分层结构通常是基于MVC&#xff08;Model-View-Controller&#xff09;或者MVP&#xff08;Model-View-Presenter&#xff09;等设计模式。 1. 模型&#xff08;Model&#xff09;层 模型层主要负责处理数据的逻辑和操作&#xff0c;通常包括以下内…

大学c语言基础很差,能不能学51单片机?会不会很困难?

开始前我分享下我的经历&#xff0c;我刚入行时遇到一个好公司和师父&#xff0c;给了我机会&#xff0c;一年时间从3k薪资涨到18k的&#xff0c; 我师父给了一些51单片机学习方法和资料&#xff0c;让我不断提升自己&#xff0c;感谢帮助过我的人&#xff0c; 如大家和我一样…

小米/红米手机刷机错误:Missmatching image and device

报错&#xff1a; Missmatching image and device。 场景&#xff1a; 该解决方法只适用于手机是通过EMT解锁的。 解决方法&#xff1a; 打开刷机脚本&#xff0c;并注释检测脚本&#xff1a; 刷机脚本根据不同的刷机方式&#xff0c;选择编辑不同的脚本&#xff0c;例如&am…

地图在数字孪生中的7个价值,领导也得点头认可。

地图在数字孪生大屏中扮演着重要的角色&#xff0c;具有以下几个作用&#xff1a; 空间可视化 地图可以将数据在空间上进行可视化展示&#xff0c;将各种信息和指标与地理位置相结合。通过地图的展示&#xff0c;用户可以直观地了解数据在不同地区的分布情况&#xff0c;帮助…

Stable Diffusion拓展Deforum AI视频生成

X轴平移值Z轴位移3D翻转 透视翻转

使用System.Drawing进行几何图形绘制

1.概要 使用System.Drawing进行几何图形绘制 System.Drawing 是.NET框架中的一个命名空间&#xff0c;提供了基本的绘图功能&#xff0c;包括绘制几何图形&#xff08;如矩形、椭圆、线条等&#xff09;。它通常用于Windows Forms应用程序中的绘图。你可以使用 Graphics 类来…

企业级WEB服务Nginx安装

企业级WEB服务Nginx安装 1. Nginx版本和安装方式 Mainline version 主要开发版本,一般为奇数版本号,比如1.19Stable version 当前最新稳定版,一般为偶数版本,如:1.20Legacy versions 旧的稳定版,一般为偶数版本,如:1.18Nginx安装可以使用yum或源码安装,但是推荐使用源码编译安…