一 按键初始化
在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,cpsrn"
"bic r0, r0, #0x80n"
"msr cpsr_c, r0n"
:
:
);
设置向量中断
向量中断没有统一的入口,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, #4n"
"stmfd sp!, {r0-r12, lr}n"
:
:
);
led_on();
/* 清除中断 */
EXT_INT_0_PEND = ~0x0;
VIC0ADDRESS = 0;
VIC1ADDRESS = 0;
__asm__(
"ldmfd sp!, {r0-r12, pc}^ n"
:
:
);
}
void key6_handle()
{
__asm__(
"sub lr, lr, #4n"
"stmfd sp!, {r0-r12, lr}n"
:
:
);
led_off();
/* 清除中断 */
EXT_INT_0_PEND = ~0x0;
VIC0ADDRESS = 0;
VIC1ADDRESS = 0;
__asm__(
"ldmfd sp!, {r0-r12, pc}^ n"
:
:
);
}
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,0n"
"orr r0,r0,#(1<<24)n"
"mcr p15,0,r0,c1,c0,0n"
"mrs r0,cpsrn"
"bic r0, r0, #0x80n"
"msr cpsr_c, r0n"
:
:
);
}
上一篇:DMA机制(基于S3C6410)
下一篇:S3C6410核心初始化
推荐阅读最新更新时间:2024-11-08 11:37
设计资源 培训 开发板 精华推荐
- 使用 ROHM Semiconductor 的 BD9A300MUV 的参考设计
- 黄淮学院创客空间立创杯电子设计大赛-狄胜军-1002028A
- 【ART-Pi】机械臂主控板+681604A
- ATXMEGAB1-XPLD、XMEGA-B1 Xplained 评估套件是用于评估 ATxmega128B1 AVR MCU 的硬件平台
- AS431可调精密并联稳压器的典型应用
- LT3470AEDDB 2.5V 降压转换器的典型应用电路
- LTC3260 的典型应用 - 低噪声双电源反相电荷泵
- 使用毫米波雷达传感器的交通监控物体检测与跟踪参考设计
- LTC3110HUF 铅酸电池备份/充电应用的典型应用电路
- 校园讲师随机转盘案例