32 linux内核里的中断处理

中断: CPU在执行过程中, 硬件发生状态变化时, 打断CPU程序的执行,先做硬件状态变化时需要处理,再接着执行原程序.
中断其实就是由硬件主动来告诉我们它的状态发生改变了, 而不需要一直轮询硬件状态 .

arm里有异常向量表,当发生中断异常,不是执行0x18就是执行0xffff0018上的代码指令.也就是不管是什么中断,都是由在这地址上的代码来处理.

arm里只有一个中断异常功能,都由SOC里的中断控制器来扩展中断线(用于实现多个硬件的中断功能)和管理中断线的功能.
在手册里的P206. GIC的图表里可以看到, 只有PA组,PG组的IO口有中断功能.
除此之外还有很多控制器的中断号.

内部中断:指SOC里的控制器的中断线只在芯片内部,不会引出芯片外的中断.
外部中断:指SOC里会引出芯片外的中断线, 也就是指有中断功能的GPIO.

内部中断什么情况下中断CPU已经是固定的,但外部中断什么情况下中断CPU是由我们来指定在GPIO什么电平状态下产生中断.
一个GPIO的电平状态: 高电平, 低电平, 上升沿, 下降沿, 双边沿

GPIO_INT -->  GIC --->  arm IRQ

在linux内核里已实现好arm的中断异常处理,芯片厂商已驱动好中断控制器,定义好中断号(在arch/arm/mach-sunxi/include/mach/irqs.h).
因我们用最多的是外部中断, 可以根据IO口来获取指定的中断号(gpio_to_irq(int gpio)).

我们只需使用一个函数来请求使用中断即可.

#include <linux/interrupt.h>

int request_irq(unsigned int irq,
        irq_handler_t handler,
        unsigned long flags, const char * name, void *dev)
//irq为中断号, handler为中断处理函数, flags可设触发方式或中断方式, 
    name为中断设备名字(cat /proc/interrupts), dev用于中断处理函数执行的参数

//中断处理函数的原形:
irqreturn_t (*irq_handler_t)(int irqno, void *arg);
    //irqreturn_t是返回值类型,通常是IRQ_HANDLED表示已处理中断了.
    // irqno表示当前发生中断的中断号, arg为request_irq时的dev参数.

//中断触发方式:
#define IRQF_TRIGGER_NONE   0x00000000
#define IRQF_TRIGGER_RISING 0x00000001
#define IRQF_TRIGGER_FALLING    0x00000002
#define IRQF_TRIGGER_HIGH   0x00000004
#define IRQF_TRIGGER_LOW    0x00000008

#define IRQF_DISABLED       0x00000020  //当中断处理函数执行时不会被打断
#define IRQF_SAMPLE_RANDOM  0x00000040  //帮助产生随机数种子
#define IRQF_SHARED     0x00000080      //共享中断,即一个中断号,多个处理函数. 但一般都是一个中断号一个处理函数的.

可通过”cat /proc/interrupts”查看系统里所用的中断信息(如中断触发次数等)

/
PA(7)接烟雾传感器.感应到烟雾时输出低电平,正常高电平.
中断的触发方式使用下降沿.

test.c

#include <linux/init.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <mach/gpio.h>
#include <linux/gpio.h>

#define DETECT_IO  GPIOA(7)  //PA(7)

irqreturn_t irq_func(int irqno, void *arg)
{
    printk("smoke detected ...\n");
    return IRQ_HANDLED;
}

static int __init test_init(void)
{
    int ret;

    ret = request_irq(gpio_to_irq(DETECT_IO), irq_func, IRQF_TRIGGER_FALLING, "detector", NULL);
    return ret;
}

static void __exit test_exit(void)
{
    free_irq(gpio_to_irq(DETECT_IO), NULL);
}

module_init(test_init);
module_exit(test_exit);


MODULE_LICENSE("GPL");


内核还提供了中断的管理函数, 可用于临时性的关闭或开启中断功能:

void disable_irq(unsigned int irq) //关闭指定中断号的中断功能,调用函数会堵塞直到关闭为止
        //注意不可以在中断处理函数里调用此函数

void disable_irq_nosync(unsigned int irq) //关闭指定中断号的中断功能,调用此函数不会堵塞。可在中断处理函数里调用此函数.

void enable_irq(unsigned int irq) //开始指定中断号的中断功能

local_irq_enable();   // cpsr[7] = 0, 恢复arm核心的中断功能;
local_irq_disable();  //关闭arm核心里的中断功能, cpsr[7] = 1

local_irq_save(flags);    //备份cpsr寄存器内容到flags变量后, 关闭arm核心里的中断功能 
local_irq_restore(flags); //恢复arm核心的中断功能, cpsr = flags
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值