1、ARM处理器执行中断时会自动进入IRQ或FIQ模式,因此需要提前设置好该模式下的椎栈指针SP。开机启动芯片进入SVC安全模式,因此可以直接通过改变CPSR值进入IRQ或FIQ模式,并设置CP15寄存器使中断向量地址由VIC决定。参考汇编代码:
LDR sp,=0x0C0003FC /*SVC模式堆栈*/
MRS r0,cpsr
BIC r0,r0,#0x02
MSR CPSR,r0 /*进入FIQ模式*/
LDR sp,=0x0C0001FC /*FIQ模式堆栈*/
ADD r0,r0,#0x01
MSR cpsr,r0 /*进入IRQ模式*/
LDR sp,=0x0c000FFC /*IRQ模式堆栈*/
ADD r0,r0,#0x01
MSR cpsr,r0 /*返回SVC模式*/
MRC p15,0,r0,c1,c0,0
ORR r0,r0,#0x01000000
MCR p15,0,r0,c1,c0,0 /*中断向量由VIC接口决定*/
2、配置和使能中断。写VICXINTSELECT确定相关中断是IRQ还是FIQ中断;将中断函数地址写入对应中断向量地址寄存器;置VICXINTENABLE中相应中断位为1 使能中断(当然还要清除CPSR中的I或F位,不列举代码了)。以下是我写的配置并使能中断的一个函数,编写好中断函数后调用配置函数即可使能中断:
void set_interrupt(unsigned int VEC_NUM,unsigned int IF,void (*fun)())
{ //设置并使能中断,中断号0~63,IF为0为IRQ中断,否则为FIQ中断
unsigned int *p;
if(IF>0)
IF=1;
if(VEC_NUM>63)
return;
if(VEC_NUM<32)
{
VIC0INTSELECT|=(IF<<VEC_NUM);
p=(unsigned int*)(0x71200100+4*VEC_NUM );
*p=(unsigned int)fun;
VIC0INTENABLE|=(1<<VEC_NUM);
}
else
{
VEC_NUM=VEC_NUM-32;
VIC1INTSELECT|=(IF<<VEC_NUM);
p=(unsigned int*)(0x71300100+4*VEC_NUM);
*p=(unsigned int)fun;
VIC1INTENABLE|=(1<<VEC_NUM);
}
}
3、编写中断函数。
GCC中中断函数的声明:
void isr () __attribute__ ((interrupt ("IRQ"))); //isr为函数名,自己随便写(写入上面配置函数中的最后一个参数),interrupt后面的说明符可为: IRQ, FIQ, SWI, ABORT 和 UNDEF,定义可不用加后面的属性说明。如:
void __attribute__ ((interrupt ("IRQ"))) isr()
{
//处理程序代码
VICXADDRESS=0; (注:好像是两个ADDRESS寄存器都要写入0)
}
注意中断函数最后要写VICXADDRESS清除当前中断。
原文地址:S3C6410裸机中断编程
http://bbs.witech.com.cn/thread-46644-1-1.html