二、中断原理分析
本文主要框架为:
1)中断概述
2)中断优先级
3)中断的打开和屏蔽
4)中断使用步骤及编程实例
CPU和外设构成了计算机系统,CPU和外设之间通过总线进行连接,用于数据通信和控制,CPU管理监视计算机系统中所有硬件,通常以两种方式来对硬件进行管理监视:
查询方式:CPU不停的去查询每一个硬件的当前状态,根据硬件的状态决定处理与否。
中断方式:当某个硬件产生需要CPU处理的事件时,主动通过一根信号线“告知”CPU,同时设置某个寄存器里对应的位,CPU一旦发现这根信号线上的电平有变化,就会中断当前程序,然后去处理发出该中断请求。
中断是嵌入式硬件实时地处理内部或外部事件的一种机制。对于不同CPU而言,中断的处理只是细节不同,大体处理流程都一样,对于实时性要求比较高的系统来说,不管是外部中断还是内部中断都是必不可少的一种机制,对于2440来说,其中断控制器结构图如下:
在上图中的最右边可以看出来,2440有两种中断模式FIQ(Fast Interrupt Request)和IRQ(Interrupt Request),其中FIQ比IRQ处理速度要比IRQ要快,相比IRQ FIQ有更高优先级,如果FIQ和IRQ同时产生,那么FIQ先处理。2440提供了INTMOD寄存器来设定相应的中断是使用FIQ还是使用IRQ。
表中可以看得出来没一种中断都对应一该寄存器的一个BIT,默认情况下该位设置的是0,但是在同一时间下,至多只能有一位设置成1,也就是说,这么多中断,同一时间下只能有一种类型的中断可以设置成FIQ模式,并且在FIQ模式下,INTPND和INTOFFSET是无效的(下面介绍这两个寄存器)。
设置完中断模式之后。就可以是设置的中断在不同的模式下得到相应,2440用60个中断源,其中外部中断就有24个之多,具体的可以查看数据手册有关中断源的介绍,对于中断的寄存器2440主要包括有中断选择寄存器(选择是FIQ还是IRQ),中断挂起寄存器(主要是判断是否响应已触发的中断),中断屏蔽寄存器(根据个人要求屏蔽有关中断)。
就如刚才所说,中断有60位之多。这些中断肯定会产生竞争关系,因日CPU需要对这些中断设定优先级,中断控制器采用优先级仲裁比较的方式进行选择,2440将中断分成了七组,包括6个一级仲裁,1个二级仲裁,其原理可用下图表示:
图中可以看出,这个体育比赛有些类似,ARBITER0~ARBITER5为一级仲裁,有些类似足球中的小组赛,也就会通过ARBITER0~ARBITER5这6个寄存器,每个寄存器选出每组优先级最高的中断然后交给ARBITER5寄存器进行决赛阶段,通过ARBITER5寄存器然后再从小组优先级最高的一个中断选出来总优先级最高的中断,交给中断服务程序。
至于到底哪个中断的优先级比较高,2440是交给用户自定义的,可以通过PRIORITY寄存器来设定中断的优先级。看下该寄存器的说明图:
先看ARB-MODEn这是是对应的选择是否打开中断轮转方式进行中单判定,所谓的中断轮转方式就是当前中断信号被选择处理之后,再次产生中断请求时,它的优先级自动轮转到该组最低(也不一定最低,具体的看ARB-SELn的分析),这样可以保证优先级低的中断信号可以被及时处理,不至于出现优先级高且中断请求频繁的中断每次都被优先处理,而优先级低的一直不被处理的情况。轮种模式默认是打开的。
接下来就是ARB-SELn,这里做简要说明:
如果ARB-SELn设置为00: 优先级先后顺序是REQ0, REQ1 , REQ2, REQ3, REQ4,REQ5.
如果ARB-SELn设置为01: 优先级先后顺序是REQ0, REQ2, REQ3, REQ4, REQ1 ,REQ5
如果ARB-SELn设置为10: 优先级先后顺序是REQ0, REQ3, REQ4, REQ1 , REQ2,REQ5
如果ARB-SELn设置为11: 优先级先后顺序是REQ0, REQ4, REQ1 , REQ2, REQ3,REQ5
这里要注意的是,假如采用的非轮转模式(ARB-MODEn=0),ARB-SELn的值是固定不变的,假如采用的是轮转模式(ARB-MODEn=1),ARB-SELn的值是会变化的,变化的规律是:
如果REQ0 或者REQ5 被中断相应,ARB_SELn是不会变化的.
如果 REQ1被中断相应, ARB_SEL 会变化为01 .
如果 REQ2被中断相应, ARB_SEL会变化为10
如果 REQ3被中断相应, ARB_SEL会变化为11
如果 REQ4被中断相应, ARB_SEL会变化为00
刚才已经提到,中断有优先级之分,当高优先级中断和低优先级中断同时发生时,低优先级级中断就会得不到及时的相应,此时低优先级就会处于中断挂起阶段,也就是说低优先级中断处于等待阶段,等到自己得到cpu的相应,对于挂起,2440有相应的寄存器SRCPND,看下图:
该寄存器告诉用户某个中断是否产生,假如某个中断产生,与之对应的SRCPND寄存器的位就是置1,值得注意的是,该寄存器一旦置1后,就会一直保持,不会自动的清除,需要用户程序编程去清除相应位。特别注意的是,想入要清除SRCPND某一位是向该为写1,而不是写0,写入0对该寄存寄存器是无效的。比如假如产生TIMER0(定时器0)中断,SRCPND【10】就会置1,清除的时候是程序写入SRCPND【10】=1。
相应的还需要子中断寄存器,举个例子说明什么是子中断。现在假如发生了UART0中断,此时中断挂起寄存器的SRCPND【28】就会置1,但是UART0中断包括接收数据中断,发送数据中断,还有错误中断这三个中断,到底是发生的这三个中断中的哪一个,通过SRCPND无法看出,因为只要这三个中断其中的任何一个发生,SRCPND【28】就会置1,此时就需要借助另外一个寄存器,叫做子中断挂起寄存器SUBSRCPND来说明到底是哪一个触发了中断,具体见下表:
通过读取该寄存器就可以知道是哪一个子中断发生,SUBSRCPND与SRCPND寄存器原理相同,当需要清除的时候向相应的位写1。
有了SUBSRCPND与SRCPND寄存器就可以知道哪一个中断发出了中断请求,2440为了方便用户查询中断请求,还有INTPND寄存器,该寄存器里存放的是经过优先级仲裁出的中断信号对应的中断号,看下图:
首先说明的是INTPND只对IRQ有效,对FIQ无效,该寄存器出现的中断挂起位为已经判定完的最高优先级的中断,所以说,在统一时刻,之多只能有其中的一位被置1,其清除方法跟SRCPND寄存器类似,向对应的为写1即可清除中断。
这里还有一个本人称为辅助寄存器的一个寄存器,该寄存器陈伟中断偏移寄存器INTOFFSET,先看下面这个图:
INTOFFSET是一个只读寄存器,该寄存器存放的是一个具体的数值,其值就是对应的INTPND的第几位产生中断请求,举个例子:假如产生TIMER0(定时器0)中断,并且TIMER0相比其他定时器优先级比较高且得到了IRQ中断的相应,此时INTPND【10】就会置1,那么对应的INTOFFSET的值就是10,值的注意的是,当清除INTPND寄存器的时候,INTOFFSET寄存器将自动的清除。
但是有些中断对于用户来说是非必要产生的,也就是说有些中断信号用户是可以屏蔽掉的,对于屏蔽中断有相应的寄存器INTSUBMSK(子中断屏蔽寄存器)与INTMSK(中断屏蔽寄存器)。具体见下图:
可以看到每个中断源都有对应的子中断,默认情况下,所有的中断都是被屏蔽的,平时所说的打开或使能某个中断对于2440来说就是将INTMSK寄存器相应位设置为0。相应的对应的子中断屏蔽寄存器INTSUBMSK:
到此,有关内部中断的全部已经介绍完毕,刚才是说2440有23个外部中断,对于外部中断还需要配置几个相关的寄存器来使能外部中断(对应的寄存器为EINTMASK,仅适用于外部中断4~23),外部中断挂起寄存器(EINTPEND ,仅适用于外部中断4~23)),还有外部中断触发方式寄存器(EXTINTn(n可以取0,1,2))该寄存器也可以使能部分外部中断有滤波功能。有些引脚比较特殊,可选择滤波的带宽与时钟寄存器(EINTPEND ,仅适用于外部中断16~23)
对于这些寄存器跟内部中断的寄存器设置方式完全相同,不在赘述,详情可参考数据手册。
到这里,有关中断的部分就介绍完毕,现在总结一下:
假如要使用中断有如下步骤:
A、假如使用外部中断:
1、根据具体要求设定那个引脚使用使用外部中断,可通过寄存器GPnCON来设置
2、这里还可以部分特殊外部中断引脚的滤波时钟选择,是否滤波及其触发方式 EXTINTn EINTFLT2 EINTFLT3
3、使能对应的外部中断 EINTMASK
4、选择是中断模式 FIQ或者IRQ INTMOD
5、假如有多个中断,可设置中断的优先级 PRIORITY
6、打开相应的中断源使能 INTMSK
在中断相应完之后,读取rINTOFFSET在中断服务程序里还需要清除相应的中断挂起寄存器的相应位SRCPND INTPND
这里假如使用的外部中断4到23还需要清除外部中断挂起寄存器 EINTPEND 这里假如使用的外部中断4到23还需要清除外部中断挂起寄存器 EINTPEND
举例:
void interrupt_init ()
{
//A、假如使用外部中断:
// 1、根据具体要求设定那个引脚使用使用外部中断,可通过寄存器GPnCON来设置
//这里使用按键S2S3 S4,分别对应GPF0(EINT0) GPF2(EINT2) GPG3(EINT11)
rGPGCON&= ~(3<<(3*2)); //清除 GPFCON的6位 7 位
rGPGCON|=2<<(3*2); //设置中S4位外部中断EINT11
rGPFCON&=~( (3<<0)|(3<<(2*2)) );
rGPFCON|=((2<<0)|(2<<(2*2))); //设置中S2 S3位外部中断EINT0 EINT2
// 2、这里还可以部分特殊外部中断引脚的滤波时钟选择,是否滤波及其触发方式 EXTINTn EINTFLT2 EINTFLT3
rEXTINT0 &= ~((7<<0) | (7<<8));//EINT0和EINT2为低电平触发
rEXTINT1 &= ~(7<<12) ; //EINT11为低电平触发
rEXTINT1 &= ~(1<<15); //EINT11不使用滤波
//EINTFLT2 EINTFLT2仅对EINT16到EINT23有效
// 3、使能对应的外部中断EINTMASK
rEINTMASK &=~(1<<11); //使能EINT11中断
// 4、选择是中断模式 FIQ或者IRQ INTMOD
rINTMOD &= ~( (1<<0)|(1<<2)|(1<<5));//使用的IRQ中断
// 5、假如有多个中断,可设置中断的优先级 PRIORITY
rPRIORITY &=~(1<<0); //EINT0 EINT2不使用轮转
rPRIORITY &=~(3<<7); //优先级 EINT0>EINT2
rPRIORITY &=~(3<<19); //优先级EINT0>EINT2>EINT11也就是S2>S3>S4
// 6、打开相应的中断源使能 INTMSK
rINTMSK &= (~(1<<0));
rINTMSK &=(~(1<<2));
rINTMSK &=(~(1<<5)); // EINT0、EINT2、EINT8_23使能
*/
}
外部中断服务函数实例:
void __irq Eint8_23_Isr(void)
{
/*7、在中断相应完之后,读取rINTOFFSET,在中断服务程序里还需要清除相应的中断挂起寄存器的相应位SRCPND INTPND
这里假如使用的外部中断4到23还需要清除外部中断挂起寄存器 EINTPEND
rEINTPEND |= (1<<11); // EINT8_23合用IRQ5,清除外部中断控制位
rSRCPND |= 1 << 4
rINTPND |= 1 << 4 ;
}
B、假如使用的是内部中断,就比较简单了:
1、选择是中断模式 FIQ或者IRQ INTMOD
2、假如有多个中断,可设置中断的优先级 PRIORITY
3、打开相应的中断源使能 INTMSK
4、在中断响应完之后,在中断服务程序里还需要清除相应的中断挂起寄存器的相应位SRCPND INTPND
最后一点要注意的是在中断函数里面不要忘记清除中断标记为,对于内部中断要清楚SRCPND和INTPND相应的位,对于外部中断,额外的还需要清除EINTPEND。
参考: