zoukankan      html  css  js  c++  java
  • Linux设备驱动编程中的中断与定时器处理

       所谓中断是指CPU在执行过程中,出现某些突发时间急待处理,CPU必须暂停执行当前的程序,转去处理突发事件,处理完毕后CPU又返回原程序被中断的位置并继续执行。

      中断分为(根据中断源来分):  内部中断(软件中断指令,溢出,除法错误等)【例如操作系统从用户态切换到内核态需借助CPU内部的软件中断】。

                                外部中断(中断源来自CPU外部,由外设提出请求)。

      中断分为(根据是否可屏蔽):  可屏蔽中断   不可屏蔽中断

      中断分为 (根据中断入口跳转方法的不同): 向量中断:采用向量中断的CPU通常为不同的中断分配不同的中断号,不同中断号的中断有不同的入口地址。

                                         非向量中断:多个中断共享一个地址。 (由软件判断中断标志来识别具体是哪个中断)。

       非向量中断服务程序典型结构:

                               irq_handler()

                              {

                               ...

                               int int_src=read_int_status();        //读硬件的中断相关寄存器

                               switch(int_src)                       //判断中断源

                               {

                                case DEV_A:

                                          dev_a_handler();

                                          break;

                                

                                case DEV_B:

                                          dev_b_handler();

                                          break;

                                ...

                               default:

                                          break;

                               }

                         ...

                  }

      

                                                 Linux内核中断

    第一部分获取中断(开启硬件中断)
    一、中断的申请注销:
    1)中断的申请

    int request_irq(unsigned int irq,irq_handler_t handler,unsigned long irqflags,const char *devname,void *dev_id);
    2)中断的注销

    void free_irq(unsigned int irq,void *dev_id)

    3)中断处理函数

    static irqreturn_t irq_handle(int irq,void *dev_id);  

    参数:irq:表示中断号,这个参数还保留由于历史遗留问题,往后可能越来越没用了。由于第二个参数信息更强大
    dev__id:就是request_irq()中void *dev_id参数
    二、中断申请函数参数

      int request_irq(unsigned int irq,irq_handler_t handler,unsigned long irqflags,const char *devname,void *dev_id)

     1)参数:
       irq:是要申请的硬件中断号。
    handler:是向系统注册的中断处理函数,是一个回调函数,中断发生时,系统调用这个函数,dev_id参数将被传递给它
        irqflags:是中断处理的属性,
           a)若设置了IRQF_DISABLED,则表示中断处理程序是快速处理程序,快速处理程序被调用时屏蔽所有中断,慢速处理程序不屏蔽;
           b)若设置了    IRQF_SHARED,则表示多个设备共享中断;//在另一篇文章会提到
           c)若设置了IRQF_SAMPLE_RANDOM,表示对系统熵有贡献,对系统获取随机数有好处。
               Tip:(flag是可以通过或的方式同时使用的
       devname:设置中断名称,通常是设备驱动程序的名称  在cat /proc/interrupts中可以看到此名称。
       dev_id:在中断共享时会用到,一般设置为这个设备的设备结构体或者不使用时为NULL。因为在共享中断中同一个中断线(或可以说同一个中断号)可 能挂载好几个设备,当使用void free_irq(unsigned int irq, void *dev_id)时,根据irq和dev_id可以找到中断线为irq上的标识为dev_id的某个具体设备。dev_id也经常在不是共享中断中的驱动 传递数据

       2)返回值:
       a)request_irq()返回0表示成功;
       b)返回-EINVAL表示无效的参数,如果返回这个值,应该看看传递给request_irq()的参数是否正确;
       c)返回-EBUSY表示中断已经被占用且不能共享;
       d)返回ENOMEM表示内存不足。嵌入式系统由于内存资源有限,经常会发生这样的错误。

       3)扩展---unsigned long irqflags值
       在includelinuxinterrupt.h中


    /*
     * These correspond to the IORESOURCE_IRQ_* defines in
     * linux/ioport.h to select the interrupt line behaviour.  When
     * requesting an interrupt without specifying a IRQF_TRIGGER, the
     * setting should be assumed to be "as already configured", which
     * may be as per machine or firmware initialisation.
     */
    #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_TRIGGER_MASK    (IRQF_TRIGGER_HIGH | IRQF_TRIGGER_LOW |
                     IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)
    #define IRQF_TRIGGER_PROBE    0x00000010
    /*
     * These flags used only by the kernel as part of the
     * irq handling routines.
     *
     * IRQF_DISABLED - keep irqs disabled when calling the action handler
     * IRQF_SAMPLE_RANDOM - irq is used to feed the random generator
     * IRQF_SHARED - allow sharing the irq among several devices
     * IRQF_PROBE_SHARED - set by callers when they expect sharing mismatches to occur
     * IRQF_TIMER - Flag to mark this interrupt as timer interrupt
     * IRQF_PERCPU - Interrupt is per cpu
     * IRQF_NOBALANCING - Flag to exclude this interrupt from irq balancing
     * IRQF_IRQPOLL - Interrupt is used for polling (only the interrupt that is
     *                registered first in an shared interrupt is considered for
     *                performance reasons)
     */
    #define IRQF_DISABLED        0x00000020
    #define IRQF_SAMPLE_RANDOM    0x00000040
    #define IRQF_SHARED        0x00000080
    #define IRQF_PROBE_SHARED    0x00000100
    #define IRQF_TIMER        0x00000200
    #define IRQF_PERCPU        0x00000400
    #define IRQF_NOBALANCING    0x00000800
    #define IRQF_IRQPOLL        0x00001000


       Tip:下面是老版本(2.4内核irqflags的值),不要在新版本使用。(2.6 内核及2.6以上内核都为新内核)


    /*
     * Migration helpers. Scheduled for removal in 9/2007
     * Do not use for new code !//不要的新版本使用,2.6 内核及2.6以上内核都为新内核
     */
    static inline
    unsigned long __deprecated deprecated_irq_flag(unsigned long flag)
    {
        return flag;
    }
    #define SA_INTERRUPT        deprecated_irq_flag(IRQF_DISABLED)
    #define SA_SAMPLE_RANDOM    deprecated_irq_flag(IRQF_SAMPLE_RANDOM)
    #define SA_SHIRQ        deprecated_irq_flag(IRQF_SHARED)
    #define SA_PROBEIRQ        deprecated_irq_flag(IRQF_PROBE_SHARED)
    #define SA_PERCPU        deprecated_irq_flag(IRQF_PERCPU)
    #define SA_TRIGGER_LOW        deprecated_irq_flag(IRQF_TRIGGER_LOW)
    #define SA_TRIGGER_HIGH        deprecated_irq_flag(IRQF_TRIGGER_HIGH)
    #define SA_TRIGGER_FALLING    deprecated_irq_flag(IRQF_TRIGGER_FALLING)
    #define SA_TRIGGER_RISING    deprecated_irq_flag(IRQF_TRIGGER_RISING)
    #define SA_TRIGGER_MASK        deprecated_irq_flag(IRQF_TRIGGER_MASK)

    三、使用模板
       使用步骤:以外部中断为例
    a)定义结构体,相当于定义(void *dev_id)中的(void *)

     struct pin_desc  //声明一个引脚描述的结构体pin_desc

    {   unsigned int pin;    //引脚值,参考数据手册及板子电路原理图

        unsigned int key_val:  //值自己随便定义;看自己的项目需要

        //...

    };

    b)实例化结构体,相当于(void *dev_id)中的 dev_id

     struct pin_desc pins_desc[3]=

    {                                //实例化结构体

     {S3C2410_GPF0,0x01},   //S3C2410_GPFn在内核中定义好了

     {S3C2410_GPF2,0x02},

     {S3C2410_GPG3,0x03},

    };

    c)定义中断处理函数

    static irqreturn_t irq_handle(int irq,void *dev_id)

    {

      struct pin_desc *pindesc=(struct pin_desc *)dev_id;

      //...

      return IRQ_RETVAL(IRQ_HANDLED); //返回IRQ_HANDLED表示中断已经处理

    d)申请中断



    3
    request_irq(IRQ_EINT0, irq_handle, IRQ_TYPE_EDGE_BOTH, "s2", &pins_desc[0]);//IRQ_EINTn在内核中定义好了   request_irq(IRQ_EINT2, irq_handle, IRQ_TYPE_EDGE_BOTH, "s3", &pins_desc[1]);
       request_irq(IRQ_EINT11, irq_handle, IRQ_TYPE_EDGE_BOTH, "s4", &pins_desc[2]);

    e)释放内存


    free_irq(IRQ_EINT0, &pins_desc[0]);
    free_irq(IRQ_EINT2, &pins_desc[1]);

    free_irq(IRQ_EINT11, &pins_desc[2]);


    Tip:可以直接将IRQ_EINTn也在pins_desc定义,然后


    int i = 0;
       for(i = 0; i < 3; i++){
       free_irq(pins_desc[i].irqnum, &pins_desc[i]);
       }

      

     有一个函数很常用,需要留意:gpio_to_irq();等到中断号。

         

     

  • 相关阅读:
    [CSP-S模拟测试]:甜圈(线段树)
    BZOJ4539 [Hnoi2016]树 【倍增 + 主席树】
    Myhchael原创题系列 Mychael vs Kid 【题解】
    BZOJ2668 [cqoi2012]交换棋子 【费用流】
    BZOJ1596 [Usaco2008 Jan]电话网络 【树形dp】
    BZOJ3427 Poi2013 Bytecomputer 【dp】
    BZOJ3526 [Poi2014]Card 【线段树】
    BZOJ3542 DZY Loves March 【map + 线段树】
    BZOJ3832 [Poi2014]Rally 【拓扑序 + 堆】
    HDU 1083
  • 原文地址:https://www.cnblogs.com/God-boy1/p/3672805.html
Copyright © 2011-2022 走看看