S3C6410通过按键玩中断

2019-07-12 14:55发布

一 按键初始化

在S3C6410中,底板上通过开发板手册可以看出按键有六个,从S2到S7依次对应的为GPN0到GPN5,且控制GPN的寄存器为GPNCON,地址为0X7F008830。
这里写图片描述
这里写图片描述
这里写图片描述
由上图可知,只要设置相应位为10,就可以设置相应的寄存器为外部中断功能,按键的初始化代码如下 #define GPNCON (volatile unsigned long*)0x7f008830 void button_init() { *(GPNCON) = 0b10 | (0b10<<10); //设置按键S2与按键S7 }

二 堆栈初始化

这里写图片描述
这里写图片描述
这里写图片描述
之前的初始化都是在svc模式下的,现在执行中断需要添加一个IRQ模式,根据手册上可以看出改变cpsr的M[4:0]位即可改变不同的模式,IRQ模式为b10010,设置好栈,就是当运行在中断模式下,sp指针指向正确的栈,同理在svc模式下sp指针指向正确的栈。
代码如下 init_stack: msr cpsr_c, #0xd2 ldr sp, =0x53000000 //初始化r13_irq msr cpsr_c, #0xd3 ldr sp, =0x54000000 //初始化R13_svc 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; /* 用户按下key时,CPU就会自动的将VIC0VECTADDR0的值赋给VIC0ADDRESS并跳转到这个地址去执 */ 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 " : : ); }