对s3c2440的硬件操作无非就是配置寄存器,中断也不例外:
需要设置的寄存器:
GPGCON :引脚配置寄存器,设置为第二功能,中断引脚;
EINTPEND:中断挂起寄存器,当有中断发生且没有被屏蔽,相应位会自动置1,在进入中断服务程序后必须用软件将其相应位清0以免发生错误中断;
SRCPND:源挂起寄存器由32位组成,其每一位都涉及一个中断源。如果中断源产生了中断则相应的位被置1并且等待中断服务。此寄存器指示出是哪个中断源正在等待请求服务。
注意:此寄存器不顾INTMAST的屏蔽位,由硬件自动将相应中断位置1,在进入中断服务程序后必须通过写1清除相应位,以防发生错误中断。
EINTMASK:外部中断屏蔽寄存器,若相应位置1;则相应中断被屏蔽不会产生下一级请求;
INTPND:中断挂起寄存器中32位的每一位都表明了是否相应位未被屏蔽并且正在等待中断服务的中断请求具有最高的优先级。
注意:在多个中断共用一个中断服务程序时可能通过判断INPND的相应位知道是哪个中断发生(比如本次实验),但确定相应位以后必须对其写1防止引发错误中断。
如果中断源产生了中断则SRCPND和INTPND相应的位被置1,前提是SUBMASK和MASK相应位不使能(即中断开启),MODE决定是IRQ还是FIQ,PRIORITY决定中断优先级
具体编程流程如下:
要想正确地执行2440的外部中断,一般需要完成两个部分内容:中断初始化和中断处理函数。
1,具体执行中断之前,要初始化好要用的中断。2440的外部中断引脚EINT与通用IO引脚F和G复用,要想使用中断功能,就要把相应的引脚配置成中断模式。
- rGPGCON = rGPGCON & (~((3<<22)|(3<<6)|(3<<0)|(3<<10)|(3<<12)|(3<<14))) | //相应位清零
- ((2<<22)|(2<<6)|(2<<0)|(2<<10)|(2<<12)|(2<<14)) ; //GPG11,3,0,5,6,7set EINT第二功能
配置完引脚后,还需要配置具体的中断功能。我们要打开某一中断的屏蔽,这样才能响应该中断,相对应的寄存器为INTMSK;如:
- rEINTMASK &= ~((1<<8)|(1<<11)|(1<<13)|(1<<14)|(1<<15)|(1<<19)); //enable eint8, 11,13,14,15,19
还要设置外部中断的触发方式,如低电平、高电平、上升沿、下降沿等,相对应的寄存器为EXTINTn。如:
- rEXTINT1 &= ~(7|(7<<0));//clear 3 bits
- rEXTINT1 |= (0|(0<<0)); //set eint8 low level int
另外由于EINT4到EINT7共用一个中断向量,EINT8到EINT23也共用一个中断向量,而INTMSK只负责总的中断向量的屏蔽,要具体打开某一具体的中断屏蔽,还需要设置EINTMASK。如:
- rEINTMASK &= ~((1<<8)|(1<<11)|(1<<13)|(1<<14)|(1<<15)|(1<<19)); //enable eint8, 11,13,14,15,19
上面介绍的是最基本的初始化,当然还有一些其他的配置,如当需要用到快速中断时,要使用INTMOD,当需要配置中断优先级时,要使用PRIORITY等。
2. 中断处理函数负责执行具体的中断指令,除此以外还需要把SRCPND和INTPND中的相应的位清零(通过置1来清零),因为当中断发生时,2440会自动把这两个寄存器中相对应的位置1,以表示某一中断发生,如果不在中断处理函数内把它们清零,系统会一直执行该中断函数。如:
- <span style="font-family:SimSun;">#define BIT_EINT0 (0x1)
- #define BIT_EINT2 (0x1<<2)
- #define BIT_EINT8_23 (0x1<<5)
- ClearPending(BIT_EINT0|BIT_EINT2|BIT_EINT8_23); //SRCPND和INTPND中的相应的位清零(通过置1来清零)
- __inline void ClearPending(int bit)
- {
- register i;
- rSRCPND = bit;
- rINTPND = bit;
- i = rINTPND;
- }</span>
另外还是由于前面介绍过的,有一些中断是共用一个中断向量的,而一个中断向量只能有一个中断执行函数,因此具体是哪个外部中断,还需要EINTPEND来判断,并同样还要通过置1的方式把相应的位清零。
- rEINTPEND |= (1<<8)|(1<<11)|(1<<13)|(1<<14)|(1<<15)|(1<<19); //clear eint8, 11,13,14,15,19
keysan.c源码:
- /**************************************************************
- 4*4 Key Scan
- **************************************************************/
- #include "def.h"
- #include "option.h"
- #include "2440addr.h"
- #include "2440lib.h"
- #include "2440slib.h"
- /******************************************************************************
- 1X6 矩阵键盘
- 六个输入引脚: EINT8 -----( GPG0 )
- EINT11 -----( GPG3 )
- EINT13-----( GPG5 )
- EINT14-----( GPG6 )
- EINT15-----( GPG7 )
- EINT19-----( GPG11 )
- ******************************************************************************/
- U8 Key_Scan( void )
- {
- Delay( 80 ) ;
- if( (rGPGDAT&(1<< 0)) == 0 ) //按下后IO口为低电平
- return 1 ;
- else if( (rGPGDAT&(1<< 3)) == 0 )
- return 2;
- else if( (rGPGDAT&(1<< 5)) == 0 )
- return 3 ;
- else if( (rGPGDAT&(1<< 6)) == 0 )
- return 4 ;
- else if( (rGPGDAT&(1<< 7)) == 0 )
- return 5 ;
- else if( (rGPGDAT&(1<<11)) == 0 )
- return 6 ;
- else
- return 0xff;
- }
- static void __irq Key_ISR(void)
- {
- U8 key;
- U32 r;
- EnterCritical(&r); //设置相应cpsr的值
- if(rINTPND==BIT_EINT8_23) { //为1表示8~23号中有中断
- ClearPending(BIT_EINT8_23);//清除INTPND中断标志位
- if(rEINTPEND&(1<<8)) { //通过EINTPEND查看具体是哪一个中断源
- //eint8 occur!
- rEINTPEND |= 1<< 8;
- }
- if(rEINTPEND&(1<<11)) {
- //eint11 occur!
- rEINTPEND |= 1<< 11;
- }
- if(rEINTPEND&(1<<13)) {
- //eint13 occur!
- rEINTPEND |= 1<< 13;
- }
- if(rEINTPEND&(1<<14)) {
- //eint14 occur!
- rEINTPEND |= 1<< 14;
- }
- if(rEINTPEND&(1<<15)) {
- //eint15 occur!
- rEINTPEND |= 1<< 15;
- }
- if(rEINTPEND&(1<<19)) {
- //eint19 occur!
- rEINTPEND |= 1<< 19;
- }
- }
- key=Key_Scan();//按键扫描,读取按键键值
- if( key == 0xff )
- Uart_Printf( "Interrupt occur... Key is released!\n") ;
- else
- Uart_Printf( "Interrupt occur... K%d is pressed!\n", key) ;//打印信息
- ExitCritical(&r);//恢复相应的cpsr位
- }
- void KeyScan_Test(void)
- {
- Uart_Printf("\nKey Scan Test, press ESC key to exit !\n"); //串口打印
- rGPGCON = rGPGCON & (~((3<<22)|(3<<6)|(3<<0)|(3<<10)|(3<<12)|(3<<14))) | //相应位清零
- ((2<<22)|(2<<6)|(2<<0)|(2<<10)|(2<<12)|(2<<14)) ; //GPG11,3,0,5,6,7set EINT第二功能
- rEXTINT1 &= ~(7|(7<<0));//clear 3 bits
- rEXTINT1 |= (0|(0<<0)); //set eint8 low level int
- rEXTINT1 &= ~(7<<12);
- rEXTINT1 |= (0<<12); //set eint11 low level int
- rEXTINT1 &= ~(7<<20);
- rEXTINT1 |= (0<<20); //set eint13 low level int
- rEXTINT1 &= ~(7<<24);
- rEXTINT1 |= (0<<24); //set eint14 low level int
- rEXTINT1 &= ~(7<<28);
- rEXTINT1 |= (0<<28); //set eint15 low level int
- rEXTINT2 &= ~(0xf<<12);
- rEXTINT2 |= (0<<12); //set eint19 low level int
- rEINTPEND |= (1<<8)|(1<<11)|(1<<13)|(1<<14)|(1<<15)|(1<<19); //clear eint8, 11,13,14,15,19
- rEINTMASK &= ~((1<<8)|(1<<11)|(1<<13)|(1<<14)|(1<<15)|(1<<19)); //enable eint8, 11,13,14,15,19
- ClearPending(BIT_EINT0|BIT_EINT2|BIT_EINT8_23); //清除相应中断源的位
- pISR_EINT0 = pISR_EINT2 = pISR_EINT8_23 = (U32)Key_ISR;//得到相应中断信息
- EnableIrq(BIT_EINT0|BIT_EINT2|BIT_EINT8_23); //打开相应中断源eint0,2,8~23
- while( Uart_GetKey() != ESC_KEY ) ;//使能中断后在此等待,直到按键中断产生,跳到Key_ISR();
- DisableIrq(BIT_EINT0|BIT_EINT2|BIT_EINT8_23);//关闭相应中断源eint0,2,8~23,中断已发生,禁止再次中断
- }
效果图: