handle_level_irq 与handle_edge_irq 的区别【转】

时间:2021-09-03 15:54:11

转自:http://blog.csdn.net/xavierxiao/article/details/6087277

Linux 里,

handle_level_irq

 *    Level type interrupts are active as long as the hardware line has
 *    the active level. This may require to mask the interrupt and unmask
 *    it after the associated handler has acknowledged the device, so the
 *    interrupt line is back to inactive.

     当中断线电平达到激活电平,中断一直会被激活。 所以需要刚进中断处理函数就要屏蔽掉中断,

等handler 处理完后再打开中断(unmask)

 

 Pesudo code

[c-sharp] view plain copy
  1. handle_level_irq()  
  2. {  
  3.   mask( irq );  
  4.   ack( irq );  
  5.   status |=IRQ_INPROGRESS;  
  6.   handle_IRQ_event();   
  7.   status &=~IRQ_INPROGRESS;   
  8.   unmask( irq );  
  9. }  

      由于irq在整个处理过程中都被屏蔽,所以需要handle_level_irq里的action要尽量简短

 

handle_edge_irq

 *    Interrupt occures on the falling and/or rising edge of a hardware
 *    signal. The occurence is latched into the irq controller hardware
 *    and must be acked in order to be reenabled. After the ack another
 *    interrupt can happen on the same source even before the first one
 *    is handled by the assosiacted event handler. If this happens it
 *    might be necessary to disable (mask) the interrupt depending on the
 *    controller hardware. This requires to reenable the interrupt inside
 *    of the loop which handles the interrupts which have arrived while
 *    the handler was running. If all pending interrupts are handled, the
 *    loop is left.

    中断发生在上升沿/下降沿, 它会被中断控制器锁存起来,需要ack 后才能重新使能。 Ack 后新的

中断可以在前一个中断正在被处理时产生,如果这种情况发生,则需要屏蔽中断。同时,需要用一个loop

来处理中断处理过程中又有中断产生的情况,在这个loop中重新把中断屏蔽打开。 如果所有pending的

中断都处理完了,loop就可以离开。

Pesudo code

[c-sharp] view plain copy
  1. handle_edge_irq()  
  2. {  
  3.    if( status & IRQ_INPROGRESS ) {  
  4.       status |= (IRQ_PENDING | IRQ_MASKED);  
  5.       mask();  
  6.       ack();  
  7.       return;  
  8.    }  
  9.      
  10.    ack();  
  11.    status |= IRQ_INPROGRESS;  
  12.    do{  
  13.        if( status & (IRQ_PENDING | IRQ_MASKED ) )  
  14.          umask();  
  15.        handle_IRQ_event();  
  16.    }while( status & IRQ_PENDING );   
  17.      
  18.    status &= ~IRQ_INPROGRESS;  
  19. }  

 

中断触发方式的比较

http://blog.21ic.com/user1/2662/archives/2007/37347.html

    沿触发: 这是很最常见的触发方式,我们可以用数字电路的方法来解释它的特性。沿触发应该应触发器来描述:  输入引脚(当作触发器的CLK) ----> 触发器------> 中断控制器 ,当输入引脚的相应的沿到来时,就会将触发器置1,并触发中断,触发器会一直保持电平1除非在ISR中用一条语句清0,否则会不断的触发中断,这也就是每 次触发中断都要清0的原因。当有高优先级的中断运行后退出时,处理器检测到触发器的值为1,所以依然会进入中断服务程序。
    电平触发: 有的时候,边沿触发很容易产生毛刺并导致误中断,这时候就要使用电平触发,电平触发是持续触发,可以用数字电路的缓冲器来描述
     输入引脚 ----> 缓冲器 ----> 中断控制器  , 缓冲器的作用就是对信号整形,并增加驱动能力,缓冲器输出的数据和输入的数据相同,可以看出输入引脚的电平直接放映到输出引脚,以高电平触发为例,只要输 入引脚的电平为高就立即触发中断,当ISR退出时如果电平依然为高则会再次触发中断,这也就是持续触发的来由,所以采用电平触发时必须保证电平的持续时间 不能太长,在ISR中可能需要适当的延时操作保证退出时电平为低,或者读出电平值,电平变低时才退出。 在带用 OS的系统中,很多关键的数据或者代码区(临界区)都需要关闭中断,那么它对中断有什么影响呢?  电平触发如果电平的持续时间比较短,很可能在关闭中断后再开中断之前电平已经变低,结果开中断后中断就没有触发,结果是这次中断被漏掉了,所以在带OS的 系统中一定不能关闭中断太久,在允许中断嵌套的情况下必须保证高优先级的中断执行时间不能超过电平的持续时间。 综合考虑,电平触发的持续时间不能太短也不能太长,在自己的系统中要仔细地考虑好中断地持续时间。
      另外,开关中断也是很讲究的,在我的开发中我就发现一种“ISR优先级翻转现象”,比如我有三个ISR,按照优先级的高低次序一次是 ISR0   ISR1  ISR2,我在ISR3 关闭ISR0的中断(因为共享数据需要互斥),可知ISR3 运行时ISR0不能得到响应,然而ISR1的优先级高于ISR2,所以在支持嵌套的情况下ISR1会打断ISR2的执行,显然这时即使ISR0中断到来也 不会得到响应,这也就是我遇到的ISR优先级翻转问题,当然这可能是我编写程序的风格不好,但是分析起来也是很有趣的,类似于任务的优先级翻转。