S3C6410通过按键玩中断

本文介绍S3C6410平台下的按键初始化、堆栈初始化及中断初始化过程。详细讲解了如何配置按键为外部中断功能、设置IRQ与svc模式下的堆栈、配置按键中断为下降沿触发等关键技术点。

一 按键初始化

在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\n"
    "bic r0, r0, #0x80\n"
    "msr cpsr_c, r0\n"            
    : 
    : 
  );

设置向量中断

向量中断没有统一的入口,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\n"  
    "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, #4\n"  
    "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,0\n"
    "orr r0,r0,#(1<<24)\n"
    "mcr p15,0,r0,c1,c0,0\n"

    "mrs r0,cpsr\n"
    "bic r0, r0, #0x80\n"
    "msr cpsr_c, r0\n"            
    : 
    : 
  );
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值