分类: 嵌入式
2009-09-22 21:07:39
下面我们一S3C2410为例来讲解一下对外部中断的处理过程。
前面讲过了一般中断的处理过程,现在我们来详细的看以下这个过程:
1、 保护现场:当中断发生时,我们首先要保存现场。我们要将当前PC值保存到lr寄存器中,保存cpsr到相应的spsr中,以及一些寄存器。提示:在操作PC指针时一定要注意体系是采用何种流水线体系的。
2、 处理完保护现场之后的便会进入相应的中断模式,PC被强制赋值,程序跳转到0x00000018出开始执行,这是一个固定地址----IRQ模式中断的入口地址。通常情况下我们都是在这个地址放置一条跳转指令,进一步跳转到我们的中断程序中,在这我们将通过查表等一系列的操作来获取相应中断处理程序的入口地址,并调用该函数。这样我们就进入了设备服务子程序中了。
3、 恢复现场,中断返回:前面已经讲过了,但还是要注意对PC的操作。
下面我们来看一个简单的处理过程
0x00000018: LDR pc,=0x30000018
…………….
0x30000018: b HandlerIRQ
HandlerIRQ:
sub sp,sp,#4
stmfd sp!,{r0}
ldr r0,=HandlerIRQ
ldr r0,[r0]
str r0,[sp,#4]
ldmfd sp!,{r0,px}
注意如果我们在前面已经做了一下工作
ldr r0,=HandlerIRQ
ldr r1,=IsrIRQ
str r1,[r0]
即在HandlerIRQ地址处放置了中断程序的入口地址
那么现在我们就可以跳到该中断程序中了,在改程序中我们要通过一系列操作获取中断服务
子程序的入口地址。
我们可以在IsrIRQ中放置一下代码:
IsrIRQ:
sub sp,sp,#4
stmfd sp!,{r8-r9}
ldr r9,=INTOFFSET
ldr r9,[r9]
ldr r8,=HandleEINT0
add r8,r8,r9,lsl #2
ldr r8,[r8]
str r8,[sp,#8]
ldmfd sp!,{r8-r9,pc}
之所以要采取这样的操作是要大家对中断向量表有所了解,中断向量表从HandleEINT0处开始,每4个字节保存一个中断服务函数的入口地址,这个地址通常是在注册中断时由应用程序指定的。
当然这个表不全大家可以自己参考相关书籍,我真感觉自己有点懒了,连个表都不舍的画了O(∩_∩)O~
与中断向量表中地址对应的函数必须 使用关键字__attribute__((interrupt(“IRQ”)))来修饰
例如我们可以定义一个外部中断2的服务子程序
void eint2_isr(void) __attribute__ ((interrupt("IRQ")));;
然后在定义改程序的时候就可以不用修饰了
void eint2_isr(void)
{
Irq_Clear(IRQ_EINT2);
if(dither_count2 > 5)
{
dither_count2 = 0;
Led_Display(nLed);
nLed = (nLed ^ 0x01);
}
}
在主函数中我们有初始化处理器等一系列操做后,便可以注册中断了
我们使用自定义函数Irq_Request(IRQ_EINT2, eint2_isr);
下面是该函数的有关定义,时间问题,我就不再详细介绍了!
// Function name : Isr_Request
// Description : 注册中断函数
// Return type : void
// Argument : int irq_no
// #define IRQ_EINT0 1
// #define IRQ_EINT1 2
// #define IRQ_EINT2 3
// .
.
.
.
.
void Irq_Request(int irq_no, void* irq_routine)
{
if(irq_no >= IRQ_MIN && irq_no <= IRQ_MAX)
*(unsigned int*)((irq_no - 1) * sizeof(unsigned int) + (unsigned int)(_ISR_STARTADDRESS+0x20)) = (unsigned int)irq_routine;
}
通过这个函数我们便将外部中断2与服务处理程序关联了起来,接下来就需要打开相应中断的中断。我们定义了一个函数
void Irq_Enable(int irq_no)
{
if(irq_no >= IRQ_MIN && irq_no <= IRQ_MAX)
rINTMSK &= ~(1 << (irq_no - 1));
}
Irq_Enable(IRQ_EINT2);这样我们就可以接受外部中断2发来的中断请求,并且跳到相应的中断处理函数中来执行。
这篇文章我做了将近4个小时,希望对大家能有些帮助!
由于时间问题,对于这些程序我没时间跟大家详细讲解了,如果大家感兴趣的话我可以通过邮箱发给大家,在后面我会把邮箱留给大家。
这篇文章参考了《ARM9嵌入式技术及Linux高级实践教程》中有关的知识,小孟在此感谢本书的作者!
由于个人水平有限,难免会有不足之处,还敬请指正!在此小孟先谢过了!
最后小孟还是要感谢大家的支持!