S5PV210中断控制器详解(一):概述和使用中断

来源:互联网 发布:php网络验证源码post 编辑:程序博客网 时间:2024/06/04 23:22
1 S5PV210的Interrupt Controller简介
S5PV210是三星推出的一款基于Cortex-A8的Soc,其内部集成的中断控制器由4个ARM PrimeCell PL192矢量中断控制器级连(daisy-chain)而成,每个PL192 VIC(Vectored Interrupt Controller)支持32个中断源,所以最多支持128个。S5PV210使用了其中的93个。所谓“矢量”是指当中断发生时,软件可以直接从VIC得到提前设好的中断服务程序ISR(Interrupt Service Routine),对于S5PV210这样的单核CPU来说,PL192是一种比较高效的VIC。硬件上的连接图大体如下所示:


 
在图中,各个VIC之间连接的比较重要重要的信号,楼主都已经标注出来,最终连接到ARM CPU上的输入信号只有两个,IRQ和FIQ

2 什么样的中断会被送到CPU处理?
中断分为两种,一种是真实的外部硬件触发的中断,另一种叫软中断softInt,它是由软件写寄存器而触发。对应的寄存器为VICSOFTINT,当其中的某个bit位为非0,时,VIC就收到了一个softInt,softInt一般都是用在调试中,用于手动产生一个中断
下面这张图清楚的描述了中断请求的步骤:

左边的或门的输入是VICINTSOURCE和VICSoftInt,VICINTSOURCE来自外部,是其它Soc内部模块或者Soc外部产生的真实中断;VICSoftInt在框图的内部,是有VIC自己产生的。无论这两者哪个发生了,在VICRawInterrupt处都会看到这个中断源的存在。VICRawInterrupt对应的寄存器为:
这里三星官方给出的描述似乎有点问题,status of FIQ interrupt before masking,事实上,IRQ的status也是能看到的。
再看Interrupt Requst Logic图,中间的与门,其输入是从左边过来的VICRawInterrupt和VICIntEnable,VICIntEnable表明了已经使能的中断源,与之对应的寄存器有两个,如下所示
给VICENABLE寄存器里的某个bit写1,表明使能某个中断,而给VICINTCLEAR里的某个bit写1,表明是要disable某个中断。这两个寄存器都有一个特点,给对应的bit写0无效。不知道是为什么,许多中断控制器都采用这种方式,完全可以用一个VICENABLE寄存器来完成,写1为enable,写0为disable
VICIntSelect决定了Interrupt Requst Logic图最右边的选择器是输出IRQ和FIQ,这很好理解,对应的寄存器为:
默认情况下,所有的中断源都设置为IRQ interrupt
3 收到中断后,应该做些什么?
在ARM CPU收到中断的触发之后,硬件会自动将中断前的CPSR到SPSR_irq,保存PC到LR_irq,将CPSR的低5位设置为0x12(IRQ模式),并且关闭IRQ使能位(CPSR bit 7置1),然后ARM会将PC转到中断向量表的0x18偏移处,开始执行IRQ的入口函数。IRQ Handler在开始是要保存寄存器现场,然后跳转到真正的IRQ Handler。以上的这些内容对于所有的ARM CPU来说,都是一样的,固定动作。
到了IRQ Handler后,首先软件需要知道,哪个中断发生了,S5PV210的做法就是遍历VIC0IRQSTATUS~VIC3IRQSTATUS,不为0,代表该VIC有中断发生(VICIRQSTATUS也就是Interrupt request logic图中最右边的输出信号)。
再去读取发生中断的VIC对应的VICADDRESS,此时中断控制器硬件已经替我们选好了优先级最高的中断,并将其ISR推送到VICADDRESS寄存器里,我们可以直接拿到就执行,不用再像老式的方法,遍历VICIRQSTATUS里的每个bit位,找到不为0的那个,映射到具体的ISR,效率要高不少。
在ISR的结尾,需要将中断清除,以告诉硬件(Uart0和Interrupt controller),这次中断我处理完了,可以接收下个中断了。三星官方要求将All VICADDRESS都写0,不用担心误清了VIC0,2,3的中断,因为中断发生的源头还在,还会再次触发
When user clears interrupt pending, user must write 0 to all the VICADDRESS registers (VIC0ADDRESS, VIC1ADDRESS, VIC2ADDRESS, and VIC3ADDRESS).
关于矢量和优先级,请参考这篇博文S5PV210中断控制器详解(二):矢量和优先级。
4 编程使用中断
有了前面的理论知识后,编程使用中断就会水到渠成。以UART0为例,它是连接在VIC1的的第10号中断源上。
初始化代码如下:
void uart0_irq_init(void){       VIC1INTSELECT &= ~(1<<10);             /* 设置为IRQ中断 */       VIC1INTENABLE |= 1<<10;                /* 使能中断 */       VIC1VECTADDR10 = (unsigned int)Uart0_ISR;   /* 设置ISR */}
中断向量表处的代码为:
IRQ_Handler:sub lr, lr, #4                /* 1.计算返回地址 */stmfd sp!, {r0-r12, lr}       /* 2.保护现场 */bl do_irq                     /* 3. 处理异常 */ldmfd sp!, {r0-r12, pc}^      /* 4. 恢复现场  ^表示把spsr恢复到cpsr */
void do_irq(void){    void (*isr)(void) = NULL;    if(0 != VIC0IRQSTATUS)        isr = VIC0ADDRESS;    else if(0 != VIC1IRQSTATUS)   //如果uart0中断发生,VIC1IRQSTATUS不为0        isr = VIC1ADDRESS;            //VIC1ADDRESS给出的就是之前给VIC1VECTADDR10写入的内容    else if(0 != VIC2IRQSTATUS)        isr = VIC2ADDRESS;    else if(0 != VIC3IRQSTATUS)        isr = VIC3ADDRESS;       if (isr)    {        (*isr)();        VIC0ADDRESS = 0;  /* 清中断向量 */        VIC1ADDRESS = 0;        VIC2ADDRESS = 0;         VIC3ADDRESS = 0;     }}


最后是Uar0IRQ的中断服务函数Uart0_ISR
void Uart0_ISR(void){      /* Check the exactly reason for uart0,tx rx or error        Do something for it */        URP0 = 0xf;       /* 清UART0里的中断源,URP0寄存器地址是0xE2900030  */}



原创粉丝点击