中断IRQ总结

中断

中断是指计算机运行过程中,出现某些意外情况需主机干预时,机器能自动停止正在运行的程序并转入处理新情况的程序,处理完毕后又返回原被暂停的程序继续运行

1 cpu处理处理事情的方式

  1. 轮询:不断查询是否有事情需要处理,如果有则处理。由于需要不断的轮询,效率较低
  2. 中断:当需要CPU处理的时候,产生一个信号,打断CPU正在做的事情,让CPU处理另一件事情,等另一件事情处理完以后,回到打断之前的地方接着执行。

中断处理需要注意的地方:

  • 打断了其他程序的执行,所以中断处理的时候需要尽可能的快,不能在中断处理过程中做耗时很长的事情。
  • 打断了其他程序的执行,所以在中断处理的时候,需要先保存现场(CPU的状态和CPU内部寄存器的值:压栈保存),在中断处理结束的时候,需要恢复现场。

2 arm中断处理过程

1、中断也是一种异常,arm核异常处理过程:
在这里插入图片描述

当异常产生的时候,ARM核自动做的事情:

  1. 将CPSR的值拷贝到异常模式的SPSR寄存器
  2. 设置CPSR相应位
    1. 进入ARM状态
    2. 进入对应的异常模式
    3. 禁止中断
  3. 保存pc的值到异常模式的lr
  4. 将pc设置异常向量表的相应位置

程序员需要做的事情:

  1. 编写异常向量表 (在异常向量表中写跳转指令,跳转指定异常处理函数)

  2. 设置异常向量表的基地址:告诉ARM核异常向量表的基地址
    [1]cortex-A系列之前,异常向量表可以存放在0x0000,0000(低地址) 或0xffff,0000(高地址) cp15(协处理器).c1(寄存器) 决定异常向量存放在高地址还是低地址
    [2]cortex-A系列之后,异常向量表可以存放在任意位置 cp15(协处理器).c12(寄存器)保存异常向量表的基地址

  3. 编写异常处理函数
    [1]设置sp寄存器
    [2]将通用的寄存器(r0-12)进行压栈保护
    [3]调用异常处理函数,处理异常
    [4]异常返回 A.恢复r0-r12 (出栈) B.恢复cpsr (spsr->cpsr) C.恢复pc (lr ->pc)

2、异常处理函数中的中断处理过程:

  1. 获取中断号
  2. 根据中断号,从中断向量表中找到对应的处理函数
  3. 执行处理函数

异常处理函数中,获取到中断号后,从中断向量表中查找中断处理函数。

3 中断相关概念

SOC内部的中断源的编号,就是中断号
在芯片设计时,就确定了可以产生中断的中断源设备。
一个中断号对应的一个中断处理函数。

中断控制器:控制中断的优先级、中断是否允许被处理。

  • A、B、C三个中断源都想产生中断,而中断控制器来决定谁来产生中断。

内部中断和外部中断

  • SOC内部控制器产生的中断,是内部中断
  • SOC芯片外部管脚通过电平触发的中断,是外部中断:高电平触发、低电平触发、上升沿触发、下降沿触发、双边沿触发

4 arm GIC中断控制器

4.1 GIC支持的中断类型

支持的最常见的三种中断:

  1. Peripheral interrupt:外设中断

    • Private Peripheral Interrupt (PPI) (专用外设中断):只能对特定的单个处理器产生的中断
    • Shared Peripheral Interrupt (SPI):通用公共中断,可以将中断路由到任何指定的处理器组合
  2. Software-generated interrupt:SGI,软中断:通过软件向GIC中的GICD_SGIR寄存器写入数据产生的中断。主要是系统内核使用SGIs进行处理器间通信

还支持:Virtual interrupt (虚拟中断)、Maintenance interrupt(维护中断)

4.2 GIC支持的中断源个数

GIC分配中断ID号ID0-ID1019,共1020个中断源。

  • 中断号ID32-ID1019用于SPI
  • 中断号ID0-ID31用于CPU接口专用的中断。这些中断存储在中断分发器中:ID0-ID15用于SGI,ID16-ID31用于PPI

4.3 Distributor(中断分发器)和CPU interface block(CPU接口单元)

GIC可分为四个部分构成
中断源 --> 中断分发器(保安) --> CPU接口单元(秘书) --> 处理器核(老板)
在这里插入图片描述

所有的中断源,都要先经过中断分发器。

  • 中断分发器确定中断优先级,并根据优先级转发中断到CPU接口单元

  • 每个CPU接口块都为连接到GIC的处理器提供接口

4.4 中断分组

  • 每个中断可以配置为group0或group1。
  • group0可以是IRQ或FRQ
  • group1只能是IRQ
  • group0的中断都是安全中断
  • group1中断都是非安全的中断

4.5 中断优先级

GIC中,可以配置8位无符号二进制的中断优先级

  • 较低的数字具有较高的优先级,即分配的优先级值越低,中断的优先级越高

5 通过IMX6ULL按键测试中断处理流程

在这里插入图片描述

-(1)gpio控制器的初始化(外部中断需要)

void key_irp_gpio_init(void)
{
    // Initialize GPIO pins for IR receiver
    /* clock enable */
    CCM_CCGR1 |= (0x3 << 26);

    /* GPIO mode */
    IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO26 &= ~(0xf << 0);
    IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO26 |= (0x5 << 0);

    /* IRQ register:配置为低电平中断 */
    GPIO1->ICR2 &= ~(0x3 << 20);

    /* GPIO enable IRQ*/
    GPIO1->IMR |= (0x1 << 26);

    /* clear status */
    GPIO1->ISR |= (0x1 << 26);
}

  • (2)GIC中断控制器的初始化,并注册中断处理函数
typedef unsigned int uint32_t;
typedef int (*handler_t)(int id);

//用来记录,每个中断源对应的中断处理函数入口地址
handler_t function_table[NUMBER_OF_INT_VECTORS];

//只能向CPU0注册中断
void request_irq(int irq_num,handler_t handler)
{
    int index, nbit;
    //使能GIC中断分发器转发给CPU接口单元
    GIC->D_CTLR |= (1 << 0);

    //使能每个中断ID,让中断分发器转发到CPU接口
    index = irq_num >> 5;//index = irq_num / 32
    nbit = irq_num - 32 * index;//nbit = irq_num % 32
    GIC->D_ISENABLER[index] |= (1 << nbit);
    
    //中断分发器收到中断后,转发给CPU0
    GIC->D_ITARGETSR[irq_num] |= (1 << 0);
    
    //允许任意优先级的中断到达CPU,优先级的值越大,级别越低
    GIC->C_PMR = (0x1f << 3);
    
    //使能 CPU interface转发给CPU核
    GIC->C_CTLR |= (1 << 0);
    
    //记录中断处理函数
    function_table[irq_num] = handler;
    return;
}

/* 供start/start.S跳转到此中断处理函数 */
void do_irq(void)
{
    int irq_num;
    handler_t handler;
    /* 获取中断号 */
    irq_num = (GIC->C_IAR & 0x1FF);

    //通知中断结束
    GIC->C_EOIR = (GIC->C_EOIR & ~(0x1FF)) | irq_num;

    // 调用中断处理函数
    handler = function_table[irq_num];
    handler(irq_num);
    
    return;
}

  • (3) CPSR的IRQ使能:通过C调用汇编指令
int enable_irq(void)
{
    int status;
    asm(
        "mrs r0,cpsr\n"
        "mov r1,#1\n"
        "bic r0,r0,r1,lsl #7\n"
        "msr cpsr,r0\n"
        "mov %0,r0\n"
        :"=r"(status)
        :
        :"r0","r1"
    );

    return status;
}

int disable_irq(void)
{
    int status;
    asm(
        "mrs r0,cpsr\n"
        "mov r1,#1\n"
        "orr r0,r0,r1,lsl #7\n"
        "msr cpsr,r0\n"
        "mov %0,r0\n"
        :"=r"(status)
        :
        :"r0","r1"
    );

    return status;
}

  • (4)按下按键产生中断,查看中断处理函数的输出情况
void key_interrupt_test(void)
{
    int irq_num = GPIO1_Combined_16_31_IRQn; // imx6ull参考手册chapter3查到gpio1_io26的中断号
    key_irp_gpio_init();
    request_irq(irq_num, key_interrupt_handler); // 初始化GIC中断控制器;同时注册中断处理函数
    enable_irq(); // 使能cpsr的irq

    test_timer(); // 调用led,GPIO_IO26高电平,循环开关;此时按下按键,管脚变为低电平,硬中断
}

注意void do_irq(void)是异常处理函数,在汇编irq异常处理中,通过指令bl do_irq,跳转到此函数的地址,执行此函数。

资料:https://qmkd58bf2i.feishu.cn/docx/B7qHdnOd1oLjsYx8hZBcH5Qqndb

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一个两个四个三

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值