正点原子 I.MX6ULL MINI 开发板学习笔记:ARM Cortex-A7 中断控制器 GIC

这篇笔记继续正点原子 I.MX6ULL MINI 开发板裸机学习,主题是ARM Cortex-A7 的中断系统。代码来自实际工程 /home/zhao/code/2026/touch_screen。
1. 完成什么实验?
理解 ARM Cortex-A7 中断响应流程,掌握 GIC(Generic Interrupt Controller)的初始化和中断注册方法。后续按键、EPIT、GPT、PWM、触摸屏等都依赖这套中断机制。
2. 什么是中断?
中断是外设或内部事件主动通知 CPU 的一种机制。当事件发生时,CPU 会暂停当前程序,跳转到预先设置好的中断处理函数执行;处理完后再返回原程序。相比轮询,中断能大大提高 CPU 效率。
3. ARM Cortex-A7 中断响应要经过哪几步?
- 外设产生中断请求,送到 GIC Distributor。
- Distributor 根据优先级选择一个最高优先级的中断,发给 CPU Interface。
- CPU Interface 向 CPU 发出 IRQ 信号。
- CPU 进入 IRQ 异常模式,从 VBAR 指向的向量表找到 IRQ 入口。
- 汇编入口保存现场,读取中断号,调用 C 层的
system_interrupt_handler(irq)。 - 根据中断号分发到用户注册的
key_handler、epit1_interrupt_handler等函数。 - 处理完后清除中断标志,恢复现场,返回原程序。

4. GIC 是什么?
GIC(Generic Interrupt Controller)是 ARM Cortex-A 系列处理器配套的中断控制器。它分为两部分:Distributor 负责接收和仲裁所有中断源;CPU Interface 负责把选中的中断发送给 CPU,并管理中断的使能、优先级和应答。
5. VBAR 向量表起什么作用?
Cortex-A7 发生异常(复位、未定义指令、IRQ、FIQ 等)时,硬件会从向量表取入口地址。代码中通过 <code>__set_VBAR(0x87800000)</code> 把向量表地址告诉 CPU;而 0x87800000 处正是 start.S 里放好的 IRQ 处理入口。
6. 真实可用的中断初始化代码
下面是工程中验证过的中断相关代码。
#include "interrupt.h"
#include "MCIMX6Y2.h"
#include "fsl_iomuxc.h"
#include "core_ca7.h"
static irq_handler_t interrupt_vector_table[160];
void system_interrupt_init(void)
{
__set_VBAR(0x87800000); /* 设置向量表基地址 */
GIC_Init(); /* 初始化 GIC */
}
void system_interrupt_register(irq_handler_t handler, int num)
{
interrupt_vector_table[num] = handler;
}
void system_interrupt_handler(int irq)
{
if (interrupt_vector_table[irq] != NULL)
{
interrupt_vector_table[irq]();
}
}
.global _start
_start:
ldr pc, =_reset_handler
ldr pc, =_undefined_handler
ldr pc, =_svc_handler
ldr pc, =_prefetch_handler
ldr pc, =_data_abort_handler
ldr pc, =_not_user_handler
ldr pc, =_irq_handler /* 中断入口 */
ldr pc, =_fiq_handler
_irq_handler:
subs lr, lr, #4
stmfd sp!, {r0-r12, lr}
mrc p15, 4, r1, c15, c0, 0
add r1, r1, #0x2000
ldr r0, [r1, #0x0C] /* 读取中断号 */
stmfd sp!, {r0, r1}
cps #0x1F
stmfd sp!, {lr}
bl system_interrupt_handler /* 调用 C 层分发函数 */
ldmfd sp!, {lr}
cps 0x12
ldmfd sp!, {r0, r1}
str r0, [r1, #0x10] /* 写 EOIR,通知 GIC 中断处理完成 */
ldmfd sp!, {r0-r12, pc}^ /* 恢复现场并返回 */
7. 关键点说明
- VBAR 必须在 GIC 之前设置:否则 CPU 找不到 IRQ 入口,程序会跑飞。
- 中断号:I.MX6ULL 为每个中断源分配了唯一中断号(如 GPIO1_Combined_16_31_IRQn、EPIT1_IRQn),注册和使能时要一致。
- 使能中断两步走:外设自身使能中断(如 GPIO IMR)+ GIC 使能(
GIC_EnableIRQ)。 - 清中断标志:外设状态寄存器要写 1 清除,否则中断会反复触发。
- 现场保护:start.S 中保存了 r0-r12、lr,C 函数里如果用到浮点等还要额外保存。
8. 实验现象
正确初始化中断后,按下 KEY0 会立即进入 key_handler 并翻转 LED;EPIT/GPT 定时器到点会进入对应中断服务函数。如果 VBAR 没设或 GIC 没初始化,中断来了程序会卡死或跑飞。
总结
| 问题 | 答案 |
|---|---|
| 什么是中断? | 外设主动通知 CPU 事件的机制,比轮询高效 |
| GIC 分哪两部分? | Distributor(分发/仲裁)和 CPU Interface(向 CPU 发 IRQ) |
| VBAR 作用? | 异常向量表基地址,告诉 CPU 异常入口在哪里 |
| 中断处理分几步? | 外设请求 → GIC 仲裁 → CPU 响应 → 向量表 → C 分发 → 用户 handler |
| 使能中断要做什么? | 外设使能中断源 + GIC_EnableIRQ + 必要时设置优先级 |
掌握了中断,就可以用定时器、按键、触摸屏等事件驱动的方式来写程序了。下一篇介绍 EPIT 定时器。