S3C2440的中断控制器

来源:互联网 发布:淘宝哪家化妆品是正品 编辑:程序博客网 时间:2024/06/10 07:10

S3C2440的中断控制器

S3C244060个中断源。这些中断源是由诸如DMA控制器、UARTIIC等片内外设提供的。

当从片内外设和外部中断请求引脚获得多个中断请求时,在仲裁程序完成之后,中断控制器向核ARM920T发出FIQIRQ请求。

这个仲裁程序取决于硬件优先逻辑并将仲裁结果写入中断请求寄存器(interrupt pending registerINTPND)。

 

中断控制器的操作

ARM提供FIQIRQ异常中断用于外部设备向CPU请求中断服务,一般情况下都采用IRQ中断.那么FIQIRQ与什么寄存器有关呢?包括PSRINTMOD

 

程序状态寄存器Program Status RegisterPSR)的F位和I位,这两位是用来控制FIQIRQ的。

如果CPU ARM920TPSR寄存器中F位置1CPU就不接受来自中断控制器的快速中断请求(Fast Interrupt RequestFIQ)。类似的如果I位置1CPU就不接受来自中断控制器的中断请求(Interrupt Resquest)。因此,我们可以通过将PSRF位或者I位清零,同时将INTMSK相应的位清零使中断控制器可以接收到对应的中断请求

中断模式寄存器——INTMOD(INTERRUPT MODE)

中断模式寄存器有32位,每一位都对应一个中断源,INTMOD相应的位置1ARM核就已FIQ模式响应中断;同样的,INTMOD相应的位置0,就已IRQ模式响应中断。

 

中断优先级

每一个仲裁机构依赖于一位的仲裁模式控制器(ARB_MODE)和两位的选择控制器信号(ARB_SEL)来对6路中断请求进行处理。具体参见S3C2440_datasheet

 

中断控制器

SRCPND(SOURCE PENDING)——源中断指示寄存器

SRCPND寄存器32位中每一位对应着一个中断源,哪一位置1,则相应的中断源产生了中断请求并且等待中断服务。要注意,SRCPND寄存器每一位的置位与INTMSK寄存器中的屏蔽位是否置1无关,是由中断源自动置位的,但要清除该位,即将该位清零,是需要手动操作的。这就是说在响应中断之后,SRCPND寄存器相应的位必须被清除,也就是清零,这样才能正确的再次响应同一中断源的中断请求,如果没有这么做,那就会一直响应该中断,出现如图1所示情况,即这种不停响应中断的情况并不是用户所期望的。

 

这里要注意,如何清除指定位呢?方法是向指定位写1,没错是写1,这样相应的位就被清零了。

例如:               

rSRCPND |= 0xFFFFFFFF;

这条语句执行完之后,rSRCPND的值就是0

 

1未清除制定位导致错误的中断响应

 

SRCPND地址

 

SRCPND每一位所代表的中断源

 

 

INTPND(INTERRUPT PENDING)——中断请求寄存器

中断请求寄存器每一位对应着相应的中断请求,经过优先级逻辑后,INTPND只能有一位被置1,并向CPU产生中断请求,在IRQ中断服务子程序中,读取该寄存器值来决定响应哪一个中断。

SRCPND类似,在响应中断后,相应的位需要清零,也是向寄存器相应位写1,来清除指定位。

例如:

rINTPND |= bit;

这里的bit就是相应的位,此条语句执行完之后,rINTPND值为0。如果响应中断后不清除相应的位,那么出现如图1同样的错误,即不断响应该中断。

 

同样我们要注意到,只有在IRQ模式下的中断发生,INTPND相应的位才置1,如果FIQ模式的中断发生了,不会对INTPND相应的位产生影响。

 

INTPND地址

INTPND每一位对应的中断源与SRCPND相同

 

INTMSK(INTERRUPT MASK)——中断屏蔽寄存器

INTMSK寄存器中,32位一次对应着每个中断源,如果某一位被置1CPU将不会响应该中断源的中断请求,即SRCPND被置1INTPND不变。如果每一位都为0,那么所有中断请求都会被响应。

 

INTMSK地址

INTMSK每一位对应的中断源与SRCPND相同

 

INTOFFSET(INTERRUPT OFFSET)——中断偏移寄存器

中断偏移寄存器INTOFFSET中的值显示了INTPND寄存器中的哪一个IRQ被响应,这个位在清除SRCPNDINTPND后将自动被清除。

这里要注意,与INTPND寄存器相似,FIQ模式的中断并不影响INTOFFSET寄存器,INTOFFSET只对IRQ有效。

 

SUBSRCPND(SUB SOURCE PENDING)——次级中断指示寄存器

其用法与注意事项与SRCPND相同。用完清零,方法同样为写1,但要记住,先清除SUBSRCPND,再清除SRCPND,如果先清除SRCPNDCPU会以为有一次发生了中断。

 

 

 

SUBSRCPND地址

 

SUBSRCPND对应位

 

SUBSRCPND与SRCPND对应

 

INTSUBMSK(INTERRUPT SUB MASK)——次级中断屏蔽器

INTMSK相似,哪一位置1CPU不响应该中断请求。

 

INTSUBMSK地址

每一位对应地址与SUBSRCPND相同,只是除了保留位之外,其他位的初始值是1。

PRIORITY(PRIORITY REGISTER)——优先级寄存器

 

 

 

 

 

 

 

 

 

 

 

 

 

REQn所代表中断源如下图

 

EXTINTn(External Interrupt Filter Register n)——外部中断控制寄存器

外部中断控制寄存器可以控制外部中断信号的有效方式,外部中断信号有效方式可以设置为电平触发和边沿触犯,具体内容如下:

 

 

 

 

 

 

 

 

 

 

 

 

EXTINT0

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

EXTINT1

 

 

 

 

 

 

 

 

 

 

 

 

 

EXTINT2

 

EINTPND(External Interrupt Pending Register)——外部中断判断寄存器

EINTPND用来判断外部的20个中断源(EINT[23:4],清除该位的方法同样是向其相应位写1。其中3:0位是保留位。可以说这个寄存器是专门针对外部中断4-7,8-23来设计的。例如当外部中断8-23其中一个发生中断请求,在中断源没有被屏蔽的情况下,SRCPNDINTPND5位(INT8_23)均被置1,当CPU响应中断进而寻找到底是哪一个外部中断发出请求时,就要在EINTPND中寻找了,而外部中断0123就不需要这一过程,直接通过SRCPNDINTPND就能判断。

EINTMASK(External Interrupt Mask Resgister)——外部中断屏蔽寄存器

同样3:0位为保留位。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

EINTFLTn(External Interrupt Filter Register n)——外部中断滤波寄存器n

为识别外部中断,EXTINTn引脚上的逻辑电平至少要保持40ns

 

 

中断服务起始地址(_ISR_STARTADDRESS)定义在option.inc中:

_ISR_STARTADDRESS   EQU 0x33ffff00

中断服务向量表定义在2440addr.h中:

#define pISR_EINT0         (*(unsigned *)(_ISR_STARTADDRESS+0x20))

#define pISR_EINT1         (*(unsigned *)(_ISR_STARTADDRESS+0x24))

#define pISR_EINT2         (*(unsigned *)(_ISR_STARTADDRESS+0x28))

#define pISR_EINT3         (*(unsigned *)(_ISR_STARTADDRESS+0x2c))

#define pISR_EINT4_7     (*(unsigned *)(_ISR_STARTADDRESS+0x30))

#define pISR_EINT8_23   (*(unsigned *)(_ISR_STARTADDRESS+0x34))

#define pISR_CAM           (*(unsigned *)(_ISR_STARTADDRESS+0x38))         

#define pISR_BAT_FLT     (*(unsigned *)(_ISR_STARTADDRESS+0x3c))

#define pISR_TICK           (*(unsigned *)(_ISR_STARTADDRESS+0x40))

#define pISR_WDT_AC97              (*(unsigned *)(_ISR_STARTADDRESS+0x44))  

#define pISR_TIMER0           (*(unsigned *)(_ISR_STARTADDRESS+0x48))

#define pISR_TIMER1           (*(unsigned *)(_ISR_STARTADDRESS+0x4c))

#define pISR_TIMER2             (*(unsigned *)(_ISR_STARTADDRESS+0x50))

#define pISR_TIMER3             (*(unsigned *)(_ISR_STARTADDRESS+0x54))

#define pISR_TIMER4             (*(unsigned *)(_ISR_STARTADDRESS+0x58))

#define pISR_UART2        (*(unsigned *)(_ISR_STARTADDRESS+0x5c))

#define pISR_LCD            (*(unsigned *)(_ISR_STARTADDRESS+0x60))

#define pISR_DMA0         (*(unsigned *)(_ISR_STARTADDRESS+0x64))

#define pISR_DMA1         (*(unsigned *)(_ISR_STARTADDRESS+0x68))

#define pISR_DMA2         (*(unsigned *)(_ISR_STARTADDRESS+0x6c))

#define pISR_DMA3         (*(unsigned *)(_ISR_STARTADDRESS+0x70))

#define pISR_SDI              (*(unsigned *)(_ISR_STARTADDRESS+0x74))

#define pISR_SPI0            (*(unsigned *)(_ISR_STARTADDRESS+0x78))

#define pISR_UART1        (*(unsigned *)(_ISR_STARTADDRESS+0x7c))

#define pISR_NFCON             (*(unsigned *)(_ISR_STARTADDRESS+0x80))  

#define pISR_USBD          (*(unsigned *)(_ISR_STARTADDRESS+0x84))

#define pISR_USBH          (*(unsigned *)(_ISR_STARTADDRESS+0x88))

#define pISR_IIC        (*(unsigned *)(_ISR_STARTADDRESS+0x8c))

#define pISR_UART0        (*(unsigned *)(_ISR_STARTADDRESS+0x90))

#define pISR_SPI1            (*(unsigned *)(_ISR_STARTADDRESS+0x94))

#define pISR_RTC             (*(unsigned *)(_ISR_STARTADDRESS+0x98))

#define pISR_ADC            (*(unsigned *)(_ISR_STARTADDRESS+0x9c))

 

 

举例来说:

#include "def.h"

#include "option.h"

#include "2440addr.h"

#include "2440lib.h"

 

//外部中断0的中断服务程序,__irq是必须的,Eint0_ISR是中断服务函数名,可以随便取,看个人喜好,void加不加均可。

static void __irq Eint0_ISR(void)                                 

{

ClearPending(BIT_EINT0);            

//这个函数用来清除SCRPNDINTPND相应位,在2440addr.h中有定义

 

    Uart_Printf("EINT0  is occurred./n");

}

 

static void __irq Eint2_ISR(void)

{

    ClearPending(BIT_EINT2);

    Uart_Printf("EINT2 is occurred./n");

}

 

//外部中断8-23中的某个产生了中断请求,判断是哪个,n823,看你自己的程序中用到了哪个,这里只判断了两个,同样以你的程序为准。

static void __irq Eint11_8_23_ISR(void)

{

    if(rEINTPEND & (1<<n))

   { 

       Uart_Printf("EINT11 is occurred./n");

       rEINTPEND=(1<<11);                           //已响应该中断,清除此中断标志,写1                     

ClearPending(BIT_EINT8_23);

}

    else if(rEINTPEND & (1<<n))

    {

       Uart_Printf("EINT19 is occurred./n");

       rEINTPEND=(1<<19);

    ClearPending(BIT_EINT8_23);

    }

    else

    {

       Uart_Printf("others ENTs are occurred/n");

       rEINTPEND=0xffffff;

    ClearPending(BIT_EINT8_23);

    }

}

 

 

void xmain(void)

{           

.

.

.

.

.

//这里要写时钟初始化程序,初始化中断,串口,同样要将用到的GPFGPG口的GPFCONCPGCON寄存器相应位初始化

      

       rEXTINT0 = (rEXTINT0 & ~(7<<8))|(2<<8);

       rEXTINT0 = (rEXTINT0 & ~(7<<0))|(2<<0);

//EINT02下降沿触发,启用滤波器,注意是rEXTINT0先与7取反相与,再和2或。如果看不习惯的话话,可以这么写rEXTINT0 |= (1<<3)|(2<<0);

      

rEXTINT1 = (rEXTINT1 & ~(7<<12))|(0x2<<12);

//EINT11下降沿触发,启用滤波器

 

       rEXTINT2 = (rEXTINT2 & ~(7<<12))|(0x2<<12);

//EINT19下降沿触发,启用滤波器  

 

pISR_EINT0=(U32)Eint0_ISR;                          

pISR_EINT2=(U32)Eint2_ISR;                                 

pISR_EINT8_23=(U32)Eint11_8_23_ISR;

//EINT0EINT2EINT8_23中断服务程序起始地址定位到正确的位置,同时要将Eint0_ISR强制转化为无符号int型,U32def.h中有定义#define U32 unsigned int

 

      

      

       rEINTPEND = 0xffffff;

rSRCPND |= BIT_EINT0|BIT_EINT2|BIT_EINT8_23;

//清除之前的判断标志

    rINTPND |= BIT_EINT0|BIT_EINT2|BIT_EINT8_23;

   

rEINTMASK=~( (1<<11)|(1<<19) );                        

//不屏蔽外部中断1119,同时不改变其他中断屏蔽状态

    rINTMSK=~(BIT_EINT0|BIT_EINT2|BIT_EINT8_23);

   

    while(1)

    {

    Uart_Printf("the main is running/n");

    Delay(10000000);

    }

}

 

要注意到,此程序段并不能直接运行,并不只因为那几个初始化语句没有给出,同时也因为你可能没有添加那几个必要的头文件和C文件。程序段中同样没有对中断优先级进行配置,使用的是默认中断优先级。在此仅提供一种写断服务程序的思路,供大家参考。

 

 

 

 

原创粉丝点击