今天整理IMX6ULL的中断体系,和之前51单片机的中断对比下来,架构上复杂不少,核心差别就是多了一层GIC通用中断控制器。
一、GIC是什么
GIC全称通用中断控制器,是ARM专门为Cortex-A系列处理器设计的中断管理外设,相当于所有中断的总调度室。和内核、片内外设不同,GIC是ARM的设计,而IMX6ULL的片内外设是NXP设计的。
我们用的IMX6ULL搭载的是GIC V2版本,型号GIC 400。不同版本的适用场景差别很明确:
GIC V1:老款嵌入式芯片,比如Cortex-A5
GIC V2:支持虚拟化、8核处理器,最多1020个中断,用在32位Cortex-A7平台,IMX6ULL、树莓派都属于这一类
GIC V3/V4:支持8核以上,用在64位处理器,比如手机Soc
GIC V5:重新架构,支持数百核,用于大型服务器、车载算力芯片
二、GIC的三类中断
GIC把所有中断分成了三类,各自用途完全不同:
1. SPI(共享中断):外设产生的中断,所有CPU核都可以处理,平时用的GPIO、定时器、串口中断都属于这一类
2. PPI(私有中断):CPU核与核之间通信用的中断,和外部外设无关
3. SGI(软件中断):由软件程序主动触发的中断
三、中断数量
规格上GIC控制器最多支持1020个中断,但具体到芯片会做裁剪,IMX6ULL实际只支持160个中断,优先级编号范围是0~159。
四、从中断触发到处理完成的完整流程
从外设产生中断,到内核处理完返回,整个流程是分层走的:
1. 外设端:配置引脚中断触发方式(比如下降沿),打开外设中断使能,满足条件时外设发出中断信号
2. GIC端:接收中断信号,比较优先级,把中断分发给对应的CPU核
3. CPU端:收到中断请求,跳转到异常向量表,切换到IRQ工作模式
4. 内核读取GIC的中断通知寄存器,拿到中断号,找到对应的中断服务函数执行
5. 处理完成后,往中断结束寄存器写入中断号,通知GIC本次中断处理完毕
6. CPU恢复之前的工作模式,回到正常程序流程
对比51单片机的中断,IMX6ULL多了GIC分发这一层,还要处理多核的中断分发,逻辑上更完整。
五、关键寄存器
外设端(GPIO为例)
GPIO1_ICR2:配置中断触发方式,比如设置18号引脚为下降沿触发
GPIO1_IMR:中断屏蔽寄存器,用来使能对应引脚的中断
GPIO1_ISR:中断状态寄存器,读取可以判断对应引脚是否产生中断,写1清除中断标记
GIC端
C_IAR:中断通知寄存器,只读,里面存放当前触发的中断号
C_EOIR:中断结束寄存器,只写,处理完中断必须把中断号写进去
六、协处理器与汇编指令
操作GIC和系统配置要用到CP15协处理器,对应的汇编指令有两个:
mrc :把CP15寄存器的数据读到通用寄存器
mcr :把通用寄存器的数据写入CP15寄存器
举个操作SCTLR寄存器的例子:
asm
读取SCTLR寄存器到R0
mrc p15, 0, r0, c1, c0, 0
清除第13位,打开icache
bic r0, r0, #(1 << 13)
orr r0, r0, #(1 << 12)
写回SCTLR寄存器
mcr p15, 0, r0, c1, c0, 0
读取GIC基地址:
asm
mrc p15, 4, r0, c15, c0, 0
另外提一下内联函数inline,本质还是函数,编译时会在调用位置展开,提升执行效率,调用前必须先有函数定义。





