ARM-05-中断

1.C中断初始化和按键初始化

第一步:设置异常向量表基地址(VBAR)

__set_VBAR是一个封装了 ARM 协处理器指令 MCR​ 的函数,作用是设置 VBAR(Vector Base Address Register,异常向量表基地址寄存器)。

地址在lds里面,是0x87800000.

第二步:初始化GIC

所以中断初始化函数写成下面这样子:

2.按键中断初始化

第一步:配置引脚功能和方向,因为键盘初始化上次设置过了 所以直接搬过来。

第二步:配置中断触发方式,通过查手册找到GPIO_ICR2 因为是下降沿触发,所以 ICR18 设置为11,则GPIO1->ICR2 |= (0x3 << 4);

第三步:设置使能IMR中断掩码(第18位置1)

第四步:设置中断使能和中断优先级

因为用的是IO18,在引脚16到31的范围内,所以在MCIMX6Y2.h里面找到 GPIO1_Combined_16_31_IRQn,并且设置为0,因为0的优先级最高

完整代码为:

cs 复制代码
void key_irq_init(void)
{
    // 1. 配置引脚复用:将 UART1_CTS_B 引脚复用为 GPIO1_IO18(按键输入引脚)
    IOMUXC_SetPinMux(IOMUXC_UART1_CTS_B_GPIO1_IO18, 0);
    
    // 2. 配置引脚属性:设置 GPIO1_IO18 的上拉/下拉、驱动能力、速率等(0x10B0 是芯片特定的配置值)
    IOMUXC_SetPinConfig(IOMUXC_UART1_CTS_B_GPIO1_IO18, 0x10b0);
    
    // 3. 配置 GPIO 方向:GDIR 是 GPIO 方向寄存器,&= ~(1<<18) 表示将第 18 位清 0 → 输入模式(按键是输入)
    GPIO1->GDIR &= ~(1 << 18);
    
    // 4. 配置中断触发方式:ICR2 是 GPIO 中断配置寄存器2,(0x3 << 4) 表示"下降沿触发"(因为 0x3 对应下降沿)
    GPIO1->ICR2 |= (0x3 << 4);
    
    // 5. 使能 GPIO 中断:IMR 是中断屏蔽寄存器,|= (1<<18) 表示将第 18 位设为 1 → 使能 GPIO1_IO18 的中断
    GPIO1->IMR |= (1 << 18);
    
    // 6. 使能 GIC 中断:告诉 GIC 控制器,允许"GPIO1_Combined_16_31_IRQn"这个中断分发到 CPU
    GIC_EnableIRQ(GPIO1_Combined_16_31_IRQn);
    
    // 7. 设置中断优先级:将这个中断的优先级设为 0(数值越小,优先级越高;0 是最高优先级之一)
    GIC_SetPriority(GPIO1_Combined_16_31_IRQn, 0);
}

2.C 函数 system_irq_handler(系统级中断处理,由汇编调用)

cs 复制代码
void system_irq_handler(IRQn_Type irq_num)
{
    // 判断是否是"GPIO1_Combined_16_31_IRQn"这个中断(即 GPIO1 的 16~31 引脚共享的中断)
    if (irq_num == GPIO1_Combined_16_31_IRQn)
    {
        // 检查 GPIO1 的 ISR(中断状态寄存器)的第 18 位(对应 GPIO1_IO18 引脚)
        if (GPIO1->ISR & (1 << 18))
        {
            led_on();   // 点亮 LED(自定义函数,控制 LED 引脚输出高/低)
            beep_on();  // 打开蜂鸣器(自定义函数,控制蜂鸣器引脚输出高/低)
            
            // 清除 GPIO1 的中断标志:向 ISR 的第 18 位写 1,清除中断状态(否则中断会一直触发)
            GPIO1->ISR |= (1 << 18);
        }
    }
}

三,修改start.c(汇编部分)

中断汇编入口与IAR读取机制

  • 中断触发流程:当GPIO中断发生,CPU跳转至汇编异常入口。
  • 核心操作 :通过 MRC p15, 0, r0, c12, c0, 0 读取GIC的IAR(Interrupt Acknowledge Register),获取当前中断号。
  • 后续处理 :根据中断号计算GIC寄存器偏移(+0x200C),读取中断状态;若为GPIO1_IO18中断,则调用C语言处理函数 system_irq_handler,处理完毕后写入EOIR(偏移0x10)清除中断。

翻cortex-A7手册 找到System Control Reguster

1. 设置异常向量表基地址(VBAR)为0

2. 配置 SCTLR 寄存器(系统控制寄存器)

  • 目的:启用指令缓存、禁用 MMU,确保在无操作系统环境下能正确执行代码。
  • 关键位设置
    • 第 12 位(I 位) :置 1 → 启用指令缓存
    • 第 13 位(C 位) :清 0 → 禁用 MMU(内存管理单元)
  • 实现方式
    1. 使用 MRC 读取 SCTLR 当前值到寄存器 R1;
    2. 使用 ORR 将第 12 位置 1;
    3. 使用 BIC 将第 13 位清 0;
    4. 使用 MCR 写回 SCTLR。
  1. 设置中断

调用这个函数去C 东西放R0里面

获取基地址(手册)

**获取基地址(**头文件里面)

找到的GIC是结构体的 实际的IAR有偏移 如下所示

汇编文件 start.S中的 _irq_handler(IRQ 中断处理汇编代码)

cs 复制代码
_irq_handler:
    sub lr, lr, #4               ; 修正返回地址(LR是中断时CPU自动存的PC+4,减4才是正确返回位置)
    stmfd sp!, {r0-r12, lr}      ; 保存R0-R12和LR到栈(保护现场)
    
    mrc p15, 4, r1, c15, c0, 0   ; 通过协处理器读取GIC基地址到R1
    add r1, r1, #0x2000          ; 加上0x2000偏移(芯片特定,指向GIC的CPU接口区)
    ldr r0, [r1, #0xc]           ; 读取GIC_IAR(中断确认寄存器),获取当前中断号
    stmfd sp!, {r0,r1}           ; 暂存中断号和GIC地址到栈
    
    cps #0x1f                    ; 切换到System模式(方便执行C代码)
    stmfd sp!, {r0-r12, lr}      ; 在System模式下再次保存现场
    
    bl system_irq_handler        ; 调用C语言中断处理函数(R0已包含中断号)
    ldmfd sp!, {r0-r12, pc}      ; 恢复System模式现场并返回
    
    cps #0x12                    ; 切换回IRQ模式(GIC操作必须在IRQ模式)
    
    ldmfd sp!, {r0, r1}          ; 恢复中断号和GIC地址
    str r0, [r1, #0x10]          ; 写GIC_EOIR(中断结束寄存器),通知GIC中断已处理
    
    ldmfd sp!, {r0-r12, pc}^     ; 恢复IRQ模式现场,^表示恢复CPSR(返回被中断的程序)
相关推荐
2401_858936882 小时前
ARM 汇编核心知识点精讲:从基础指令到实战应用
汇编·arm开发
蜕变的小白3 小时前
嵌入式硬件的学习----ARM
arm开发·嵌入式硬件·学习·arm
’长谷深风‘3 小时前
嵌入式ARM开发入门解析2
汇编·arm开发·arm指令集·立即数
ZPC82103 小时前
x86 与 FPGA 网卡通信实时性
arm开发·fpga开发
-Try hard-15 小时前
ARM | 内核架构、寄存器组、工作模式
arm开发
AI+程序员在路上16 小时前
嵌入式软件技术大全
linux·开发语言·arm开发·单片机
黄昏晓x20 小时前
Linux----网络
linux·网络·arm开发
莎士比亚的文学花园20 小时前
硬件(4)——ARM体系架构
arm开发
平凡的阳阳1 天前
OpenClaw 2026.3.23 重大更新:千里通 Arm 架构 Linux 小主机完配“小龙虾”,开启轻量级 AI 新纪元
linux·arm开发·openclaw·小龙虾