I.MX6ULL中断程序编写

中断简介

中断系统是一个处理器重要的组成部分,中断系统极大的提高了 CPU 的执行效率,当发生某些异常的时候可以触发中断来让CPU中途处理其它事务。

中断系统的几个关键点

STM32 的中断系统主要有以下几个关键点:
①、中断向量表。
②、NVIC(内嵌向量中断控制器)。
③、中断使能。
④、中断服务函数。

I.MX6ULL也是一样,主要有:
①、中断向量表。
②、GIC中断控制器
③、中断使能。
④、中断服务函数。

中断向量表

stm32中断向量表

1 __Vectors DCD __initial_sp ; Top of Stack
2 DCD Reset_Handler ; Reset Handler
3 DCD NMI_Handler ; NMI Handler
4 DCD HardFault_Handler ; Hard Fault Handler
5 DCD MemManage_Handler ; MPU Fault Handler
6 DCD BusFault_Handler ; Bus Fault Handler
7 DCD UsageFault_Handler ; Usage Fault Handler
8 DCD 0 ; Reserved
9 DCD 0 ; Reserved
10 DCD 0 ; Reserved
11 DCD 0 ; Reserved
12 DCD SVC_Handler ; SVCall Handler
13 DCD DebugMon_Handler ; Debug Monitor Handler
14 DCD 0 ; Reserved
15 DCD PendSV_Handler ; PendSV Handler
16 DCD SysTick_Handler ; SysTick Handler
17
18 ; External Interrupts
19 DCD WWDG_IRQHandler ; Window Watchdog
20 DCD PVD_IRQHandler ; PVD through EXTI Line detect
21 DCD TAMPER_IRQHandler ; Tamper
22 DCD RTC_IRQHandler ; RTC
23 DCD FLASH_IRQHandler ; Flash
24
25 /* 省略掉其它代码 */
26
27 DCD DMA2_Channel4_5_IRQHandler ; DMA2 Channel4 & l5
28 __Vectors_End

cortex-a7中断向量表

中断向量表就像一个函数指针数组,存放各种中断服务程序的地址(函数指针)。
这些中断服务程序(函数)在中断向量表中的位置是由半导体厂商定好的,当某个中断被触发以后就会自动跳转到中断向量表中对应的中断服务程序(函数)入口地址处,以此在中断发生的时候调用该函数。
I.MX6ULL中断程序编写

中断向量表里面都是中断服务函数的入口地址,因此一款芯片有什么中断都是可以从中断向量表看出来的。从表 17.1.2.1 中可以看出,Cortex-A7 一共有 8 个中断,而且还有一个中断向量未使用,实际只有 7 个中断。和“示例代码 17.1.1.1”中的 STM32F103 中断向量表比起来少了很多!
这个就是 Cortex-A 和 Cotex-M 在中断向量表这一块的区别,对于 Cortex-M 内核来说,中断向量表列举出了一款芯片所有的中断向量,包括芯片外设的所有中断。 对于 CotexA 内核来说并没有这么做,在表 17.1.2.1 中有个 IRQ 中断, Cortex-A 内核 CPU 的所有外部中断都属于这个 IQR 中断当任意一个外部中断发生的时候都会触发 IRQ 中断。在 IRQ 中断服务函数里面就可以读取指定的寄存器(中断ID)来判断发生的具体是什么中断,进而根据具体的中断做出相应的处理。

这些外部中断和 IQR 中断的关系如图 17.1.2.1 所示:
I.MX6ULL中断程序编写
在表 17.1.2.1 中一共有 7 个中断,简单介绍一下这 7 个中断:
①、复位中断(Rest),CPU 复位以后就会进入复位中断,我们可以在复位中断服务函数里面
做一些初始化工作,比如初始化 SP 指针、DDR 等等。
②、未定义指令中断(Undefined Instruction),如果指令不能识别的话就会产生此中断。
③、软中断(Software Interrupt,SWI),由 SWI 指令引起的中断,Linux 的系统调用会用 SWI
指令来引起软中断,通过软中断来陷入到内核空间。
④、指令预取中止中断(Prefetch Abort),预取指令的出错的时候会产生此中断。
⑤、数据访问中止中断(Data Abort),访问数据出错的时候会产生此中断。
⑥、IRQ 中断(IRQ Interrupt),外部中断,前面已经说了,芯片内部的外设中断都会引起此
中断的发生。
⑦、FIQ 中断(FIQ Interrupt),快速中断,如果需要快速处理中断的话就可以使用此中。

中断向量表偏移

中断向量表都是链接到代码的最前面,比如一般 ARM 处理器都是从地址 0X00000000 开始执行指令的,那么中断向量表就是从 0X00000000 开始存放的。

我们说 ARM 处理器都是从地址 0X00000000 开始运行的,但是我们学习 STM32 的时候代码是下载到 0X8000000 开始的存储区域中。因此中断向量表是存放到 0X8000000 地址处的,而不是 0X00000000,这样不是就出错了吗?为了解决这个问题,Cortex-M 架构引入了一个新的概念——中断向量表偏移,通过中断向量表偏移就可以将中断向量表存放到任意地址处。
我们的程序是从0X87800000,也是需要设置中断向量偏移的。

GIC控制器

1、GIC 控制器总览
STM32(Cortex-M)的中断控制器叫做 NVIC,I.MX6U(Cortex-A)的中断控制器叫做 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 等,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 接收到外部中断信号以后就会报给 ARM 内核,但是ARM 内核只提供了四个信号给 GIC 来汇报中断情况:VFIQ、VIRQ、FIQ 和 IRQ,他们之间的关系如图 17.1.3.1 所示:
I.MX6ULL中断程序编写
在图 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 所示:

I.MX6ULL中断程序编写
图 17.1.3.2 中左侧部分就是中断源,中间部分就是 GIC 控制器,最右侧就是中断控制器向处理器内核发送中断信息。我们重点要看的肯定是中间的 GIC 部分,GIC 将众多的中断源分为分为三类:
①、SPI(Shared Peripheral Interrupt),共享中断,顾名思义,所有 Core 共享的中断,这个是最常见的,那些外部中断都属于SPI 中断(注意!不是 SPI 总线那个中断) 。比如按键中断、串口中断等等,这些中断所有的 Core 都可以处理,不限定特定 Core。
②、PPI(Private Peripheral Interrupt),私有中断,我们说了 GIC 是支持多核的,每个核肯定有自己独有的中断。这些独有的中断肯定是要指定的核心处理,因此这些中断就叫做私有中断。
③、SGI(Software-generated Interrupt),软件中断,由软件触发引起的中断,通过向寄存器GICD_SGIR 写入数据来触发,系统会使用 SGI 中断来完成多核之间的通信。

中断ID

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 CortexA7 interrupts”小节,中断源如表 17.1.3.1 所示:
I.MX6ULL中断程序编写

上一篇:uboot irq流程理解


下一篇:nginx配置