正点原子[第二期]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个优先级位全部为抢占优先级。

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

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

相关文章

C--贪吃蛇

前言 贪吃蛇游戏是一个耳熟能详的小游戏,本次我们讲解他的简单的实现,需要掌握基本的API知识(http://t.csdnimg.cn/uHH6y),简单的C语言知识和基本的数据结构链表 简单的准备工作 蛇的节点 在游戏运⾏的过程中&#xff0c;蛇每次吃⼀个⻝物&#xff0c;蛇的⾝体就会变⻓⼀节&a…

力扣HOT100 - 45. 跳跃游戏 II

解题思路&#xff1a; 贪心 class Solution {public int jump(int[] nums) {int end 0;int maxPosition 0;int steps 0;for (int i 0; i < nums.length - 1; i) {maxPosition Math.max(maxPosition, i nums[i]);if (i end) {end maxPosition;steps;}}return steps;…

华为配置带反射器的iNOF功能实验

配置带反射器的iNOF功能示例 适用产品和版本 安装了SAN系列单板的CE16800系列交换机V300R020C10或更高版本。 安装了P系列单板的CE16800系列交换机V300R021C00或更高版本。 CE6866、CE6866K、CE8851-32CQ8DQ-P、CE8851K系列交换机V300R020C00或更高版本。 CE6860-SAN、CE8850-S…

2024OD机试卷-求满足条件的最长子串的长度 (java\python\c++)

题目:求满足条件的最长子串的长度 题目描述 给定一个 字符串 ,只包含字母和数字,按要求找出字符串中的最长(连续)子串的长度,字符串本身是其最长的子串,子串要求: 1、 只包含1个字母(a~z, A~Z),其余必须是数字; 2、 字母可以在子串中的任意位置; 如果找不到满足要…

9. 学习distribute by rand()

文章目录 1、rand()和rand(int seed)2、distribute by3、distribute by rand和生成文件数的关系set hive.exec.reducers.max 对比 set mapred.reduce.tasks 4、distribute by rand的风险5、hive 中什么场景下会使用 distirbute by rand() 呢&#xff1f;学习链接 1、rand()和ra…

wordpress增加谷歌分析

wordpress增加谷歌分析 为了更好的浏览体验&#xff0c;欢迎光顾勤奋的凯尔森同学个人博客 http://www.huerpu.cc:7000 一、创建谷歌分析账号与媒体应用 谷歌分析地址&#xff1a;https://analytics.google.com/analytics 创建一个账号&#xff0c;如果你没有的话。 在该账…

基于 Ubuntu22.04 安装 SSH 服务

文章目录 一、Ubuntu22.04 安装 SSH 服务二、配置 OpenSSH&#xff08;安全性&#xff09;1. 更改 OpenSSH 端口2. 限制使用 SSH 登录尝试次数3. 禁止 SSH 以 root 身份连接 三、设置防火墙&#xff08;UFW&#xff09;锁定 SSH四、远程终端软件通过 SSH 连接 Ubuntu22.041. 远…

函数和数组

一、函数 1.函数使用方法 定义函数再引用函数 2.基本函数格式 基本格式1&#xff1a; function 函数名{ ​ 命令序列 } 基本格式2&#xff1a; 函数名&#xff08;&#xff09;{ 命令序列 } 基本格式3&#xff1a; function func_name &#xff08;&#xff09; {…

自学32单片机两个周了,感觉非常懵逼怎么办?

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

[初学rust] 02_rust 中的变量和数据类型

rust 中的变量和数据类型 变量 变量声明 使用let来声明变量并且必须指定类型默认定义的变量都是i32类型使用 mut关键字(mutable缩写),来指定变量为可变的 let a 1;println!("a is {}", a);let b 2i32;let c 3_i32;let mut d 4;println!("b is {}, c is {…

如何使用Shortemall自动扫描URL短链接中的隐藏内容

关于Shortemall Shortemall是一款针对URL地址安全与Web内容安全的强大工具&#xff0c;该工具基于纯Python开发&#xff0c;专为Web安全方向设计&#xff0c;可以帮助广大研究人员以自动化的形式扫描URL短链接中的隐藏内容。 Shortemall的全名为ShortEm All&#xff0c;该工具…

【大比武05】多方主体参与下的工程档案资料数据化实现路径探究

关注我们 - 数字罗塞塔计划 - 数据化&#xff0c;是以数据为基础&#xff0c;以信息技术为手段&#xff0c;以数据分析为切入点&#xff0c;通过数据发现并分析问题&#xff0c;实现科学决策。而工程档案资料的数据化是实现工程全生命周期管理智慧化&#xff0c;发挥数据生产…

机器学习1——线性回归、误差推导

有监督——分类、回归 一、线性回归 对于一个线性方程&#xff0c;没办法拟合所有的数据点&#xff0c;但是要尽可能的覆盖尽可能多的点。 在下面的图中&#xff0c;x01。添加这一项的目的是&#xff1a;将数据矩阵补全&#xff08;比如年龄是x1、工资是x2&#xff0c;那么x0手…

“等保测评实施策略:保障企业信息安全合规“

等保测评&#xff0c;即网络安全等级保护测评&#xff0c;是企业保障信息安全合规的重要实施策略。以下是企业实施等保测评的一些关键策略&#xff1a; 理解等保测评的重要性&#xff1a; 等保测评有助于企业识别和评价信息系统的安全性能&#xff0c;提供改进建议&#xff0c;…

可重构柔性装配产线:为工业制造领域注入了新的活力

随着科技的飞速发展&#xff0c;智能制造正逐渐成为引领工业革新的重要力量。在这一浪潮中&#xff0c;可重构柔性装配产线以其独特的技术优势和创新理念&#xff0c;为工业制造领域注入了新的活力&#xff0c;开启了创新驱动的智能制造新篇章。 可重构柔性装配产线是基于富唯智…

代码随想录算法训练营第四十六天|139.单词拆分,多重背包,背包问题总结

目录 139.单词拆分思路代码 多重背包思路代码 背包问题总结 139.单词拆分 题目链接&#xff1a;704. 二分查找 文档讲解&#xff1a;代码随想录 视频讲解&#xff1a;动态规划之完全背包&#xff0c;你的背包如何装满&#xff1f;| LeetCode&#xff1a;139.单词拆分 思路 dp数…

面试常见手撕代码

目录 1.线程池 and 数据库连接池 2.生产者&#xff0c;消费者问题 3.排序算法 1.线程池 and 数据库连接池 线程池 #include <iostream> #include <vector> #include <queue> #include <thread> #include <mutex> #include <condition_va…

2024第二届智慧教育和人类发展国际会议(ICSEHD2024)

2024第二届智慧教育和人类发展国际会议(ICSEHD2024) 会议简介 智慧教育对于提升教育质量、促进教育公平、推动教育现代化和数字化转型、培养创新人才以及推动教育理论的发展都具有重要的意义&#xff0c;对人类发展产生着深远的影响&#xff0c;人类发展是智慧教育的最终目的…

易图讯科技数字武装三维电子沙盘

深圳易图讯科技(www.3dgis.top)集成了高清卫星影像、地形数据、实景三维模型、基干民兵、普通民兵、重要目标、兵要地志、企业潜力 、行业潜力 、社会组织潜力 、特种装备器材潜力、敌情数据、现场环境数据、物联感知信息&#xff0c;构建一体化的数字孪生空间&#xff0c;实现…

backtrader笔记摘录

策略 在next()里接收当前行情&#xff0c;作出买卖判断&#xff0c;通过buy()和sell()函数下单。 信号 用来通知买和卖&#xff0c;有空头信号、多头信号、空多头信号之分。 指示器 Indicators are always instantiated during __init__ in the StrategyIndicator values …