S3C2440外部中断系统详解
S3C2440A中的中断控制器接受来自60个中断源的请求。提供这些中断源的是内部外设,如DMA控制器、UART、IIC等等。在这些中断源中,UARTn、AC97和EINTn中断对于中断控制器而言是“或”关系。任意一个中断发生都会触发总中断
当从内部外设和外部中断请求引脚收到多个中断请求时,中断控制器在仲裁步骤后请求ARM920T内核的FIQ或IRQ。
仲裁步骤由硬件优先级逻辑决定并且写入结果到帮助用户通告是各种中断源中的哪个中断发生了的中断挂起寄存器中。
中断源有两种,一种是直接中断源,比如触摸屏中断,还有一种是带子中断的中断,类似于串口带有子终端入RXTX中断,通过SUBMASK也就是中断允许之后挂起到系统,系统根据用户设置确定是否响应该中断,然后依靠优先级分批响应,中断优先级依靠硬件决定
至于中断的处理过程,在解析启动代码的时候有讲到,请自行查阅
下面以按键的外部中断为例讲解中断的使用方法
1. 首先,要使用外部中断需要在rGPXCON里面将引脚模式设置为中断功能,对应是0x10
2. 需要在对应的寄存器中设置中断触发模式(EXINTx),例如GPF7中断,关联的中断引脚是EINT7,而EINT7是属于EXTINT0的,如下
所以对EXTINT0赋值选择相应中断触发模式
3. 此时,中断还不能被触发,因为还没有设置上图的MASK,mode,接下来在INTMOD中选择中断属于那个分组,如下
一般选择为IRQ中断,关于FIQ中断相关资料后期说明
4. 接下来使能相关的中断服务,寄存器为INTMSK
5. 现在就可以进行中断了,但是为了保险起见,再打开中断之前最好将中断标志位都清除掉,中断标志位有两个,两个系统级一个子中断级,系统级里面分别是SRCPND和INTPND
子中断的意思就是现在开的中断代表EINT4-7那到底是哪一个还能确定,依靠INTPEND
注意,只有多个中断公用一个通道的时候才有这个,比如EINT0-3是独立中断,直接在系统中断寄存器里面清除就好了
最后,开启中断
同样,这个也是多个中断公用通道的时候使用
另外,针对外部中断可以设置滤波过程,请查阅手册
现在我们来看,差不多的对应关系是
EINTMASK , ---------------------------SUBMASK子中断开关
INTMASK-----------------------------MASK总中断开关
INTMODE-------------------------------MODE模式开关
SPRPND-----------------------------源挂起标志
INTPND----------------------------中断请求标志
EINTPEND----------------------子中断挂起
当一个通道对应多个中断的时候要依靠子中断挂起来判定到底是哪一个中断发生了
以下是按键中断代码
Exit.c
#include "exti.h" //按键中断处理函数 void __irq IRQ_KEY1(void) { rSRCPND |=(1<<1); //清除中断标志位 rINTPND |=(1<<1); keyValue = KEY_UP; } void __irq IRQ_KEY2(void) { rSRCPND |=(1<<4); //清除中断标志位 rINTPND |=(1<<4); if(rEINTPEND & (1<<4))//EINT4包含4-7四个中断源 { rEINTPEND |=(1<<4); //清除ENIT4的中断标志位 keyValue = KEY_DOWN; } } void __irq IRQ_KEY3(void) { rSRCPND |=(1<<2); //清除中断标志位 rINTPND |=(1<<2); keyValue = KEY_LEFT; } void __irq IRQ_KEY4(void) { rSRCPND |=1<<0; //清除中断标志位 rINTPND |=1<<0; keyValue = KEY_RIGHT; } void ExtiInit(void) { rGPFCON &= ~((3<<0)|(3<<2)|(3<<4)|(3<<8));//0 1 2 4清零 rGPFCON |= ((2<<0)|(2<<2)|(2<<4)|(2<<8));//选择中断复用 rEXTINT0 &= ~((7<<0)|(7<<4)|(7<<8)|(7<<16));//清除中断模式 rEXTINT0 |= ((2<<0)|(2<<4)|(2<<8)|(2<<16));//选择下降沿触发 rSRCPND |= ((1<<0)|(1<<1)|(1<<2)|(1<<4));//清除中断标志 rINTPND |= ((1<<0)|(1<<1)|(1<<2)|(1<<4));//清除中断挂起 rINTMOD &= ~((1<<0)|(1<<1)|(1<<2)|(1<<4));//设置中断为IRQ中断 rINTMSK &= ~((1<<0)|(1<<1)|(1<<2)|(1<<4));//去除中断屏蔽,打开中断 rEINTPEND |= (1<<4);//EINT4中断服务有效//对于EINT4这种带子中断的中断的额外操作,清除子中断 rEINTMASK &= ~(1<<4); //EINT4中断服务有效//对于EINT4这种带子中断的中断的额外操作,打开子中断 //建立中断函数连接 pISR_EINT1 = (unsigned)IRQ_KEY1; //建立中断服务函数链接 pISR_EINT4_7 = (unsigned)IRQ_KEY2; pISR_EINT2 = (unsigned)IRQ_KEY3; pISR_EINT0 = (unsigned)IRQ_KEY4; }
Exit.h
#ifndef __EXTI_H_ #define __EXTI_H_ #include "2440addr.h" #include "def.h" #include "key.h" void ExtiInit(void);//使用GPIOF 0 1 2 4 #endif