一 按键初始化
在S3C6410中,底板上通过开发板手册可以看出按键有六个,从S2到S7依次对应的为GPN0到GPN5,且控制GPN的寄存器为GPNCON,地址为0X7F008830。
由上图可知,只要设置相应位为10,就可以设置相应的寄存器为外部中断功能,按键的初始化代码如下
#define GPNCON (volatile unsigned long*)0x7f008830
void button_init()
{
*(GPNCON) = 0b10 | (0b10<<10);
}
二 堆栈初始化
之前的初始化都是在svc模式下的,现在执行中断需要添加一个IRQ模式,根据手册上可以看出改变cpsr的M[4:0]位即可改变不同的模式,IRQ模式为b10010,设置好栈,就是当运行在中断模式下,sp指针指向正确的栈,同理在svc模式下sp指针指向正确的栈。
代码如下
init_stack:
msr cpsr_c, #0xd2
ldr sp, =0x53000000
msr cpsr_c, #0xd3
ldr sp, =0x54000000
mov pc ,lr
三 中断初始化
配置按键中断为下降沿触发
找到外部中断控制器,ENT0CON0控制EINT0到EINT5分别设置相应的位为01x,即为下降沿触发,设置EINT0MASK屏蔽寄存器,把相应的位设置为0即可。
使能中断,s3c6410有多个中断源,以下为按键所用到的中断源(只显示部分中断源)。
使能按键中断
这里用到的按键中断源都属于VIC0,通过设置VIC0INTABLE来使能相应的中断源,由于在这只用到VIC0,所以只要设置VIC0即可,按键S2和按键S7分别用到External Interrupt0和External Interrupt5,所以用到中断源0和1,故设置VIC0INTABLE最低位0和1两位为1即可。
由于之前在start.s中中断被屏蔽掉了,现在需要打开,代码如下
__asm__(
"mrs r0,cpsr
"
"bic r0, r0, #0x80
"
"msr cpsr_c, r0
"
:
:
);
设置向量中断
向量中断没有统一的入口,64个寄存器对应相应的中断源,每个寄存器存放中断源的中断处理程序地址,当中断产生的时候,硬件直接从寄存器中取出中断源中断处理程序的地址,只需要相应的中断处理程序写入到相应的寄存器中,就可以硬件直接处理。
按键中断采用的中断源为VIC0VECTADDR第0位和第1位,故设置EINT0_VECTADDR 为0x712000100,EINT5_VECTADDR设置为0x712000104,通过将函数名赋值给相应的中断源,如EINT0_VECTADDR = (int)key1_handle;就等于把中断处理程序的地址赋值给中断源,6410还需要设置一下是否为向量中断方式,默认的位非向量中断方式,所以在此需要将其设置一下。
清除外部中断PEND
当中断处理完之后,需要将其写入1清除,才能继续进行后面的中断,除此之外还需要清除VICXADDRESS,因为当中断产生的时候,除了调用处理函数之外,还把中断源记录的地址放到VICXADDRESS中,所以中断处理完之后,需要将其清零。
关于ARM流水线结构地址
ARM采取流水线结构运行,取码译码执行,所以PC指针一直指向当前执行地址+8,加入当前执行地址为0
● 当前代码执行地址: 0
● 即将要执行的代码地址: 0+4
● 此时PC指针值: 0+8
如果执行当前代码时发生了中断,我们需要保存即将要执行的代码地址到LR寄存器,而此时LR指针的值其实为PC指针值,因此需要将LR寄存器的值减去4之后再保存到LR中,才是保存的的即将要执行的代码地址。
中断程序代码如下
#define EXT_INT_0_CON *((volatile unsigned int *)0x7f008900)
#define EXT_INT_0_MASK *((volatile unsigned int *)0x7f008920)
#define EXT_INT_0_PEND *((volatile unsigned int *)0x7f008924)
#define VIC0INTENABLE *((volatile unsigned int *)0x71200010)
#define EINT0_VECTADDR *((volatile unsigned int *)0x71200100)
#define EINT5_VECTADDR *((volatile unsigned int *)0x71200104)
#define VIC0ADDRESS *((volatile unsigned int *)0x71200f00)
#define VIC1ADDRESS *((volatile unsigned int *)0x71300f00)
void key1_handle()
{
__asm__(
"sub lr, lr, #4
"
"stmfd sp!, {r0-r12, lr}
"
:
:
);
led_on();
EXT_INT_0_PEND = ~0x0;
VIC0ADDRESS = 0;
VIC1ADDRESS = 0;
__asm__(
"ldmfd sp!, {r0-r12, pc}^
"
:
:
);
}
void key6_handle()
{
__asm__(
"sub lr, lr, #4
"
"stmfd sp!, {r0-r12, lr}
"
:
:
);
led_off();
EXT_INT_0_PEND = ~0x0;
VIC0ADDRESS = 0;
VIC1ADDRESS = 0;
__asm__(
"ldmfd sp!, {r0-r12, pc}^
"
:
:
);
}
void init_irq()
{
EXT_INT_0_CON = (0b010)|(0b010<<8);
EXT_INT_0_MASK = 0;
VIC0INTENABLE |= (0b1)|(0b10);
EINT0_VECTADDR = (int)key1_handle;
EINT5_VECTADDR = (int)key6_handle;
__asm__(
"mrc p15,0,r0,c1,c0,0
"
"orr r0,r0,#(1<<24)
"
"mcr p15,0,r0,c1,c0,0
"
"mrs r0,cpsr
"
"bic r0, r0, #0x80
"
"msr cpsr_c, r0
"
:
:
);
}