Ok6410硬件操作之中断


中断概念

CPU在工作的过程中,经常需要与外设进行交互,交互的方式包括”轮询方式”,”中断方式”。

1. 轮询方式:

CPU不断地查询设备的状态并作出相应的反应。该方式实现比较简单,但占用 CPU 资源过高,CPU利用率很低,不适合多任务的系统。

2. 中断方式:

当某件事发生了,硬件会设置某个寄存器;CPU在每执行完一个指令时,通过硬件查看这个寄存器,如果发现所关注的事件发生了,则中断当前程序流程,跳转到一个固定地址处理这件事,最后返回继续执行被中断的程序。它的实现复杂,但是效率很高,是常用的方法。

中断生命周期


中断源

在中断的生命周期中,中断源的作用是负责产生中断信号。S3C6410支持64个中断源; (通过芯片手册浏览中断源)

Ok6410硬件操作之中断_第1张图片Ok6410硬件操作之中断_第2张图片Ok6410硬件操作之中断_第3张图片

从上图可以看出,S3C6410的中断分为VIC0和VIC1两组,每一组32个中断。

外部中断:

No

Source

Desciption

Group

0

INT_EINT0

External interrupt 0~ 3

VIC0

1

INT_EINT1

External interrupt 4 ~ 11

VIC0

32

INT_EINT2

External interrupt 12 ~ 19

VIC1

33

INT_EINT3

External interrupt 20 ~ 27

VIC1

53

INT_EINT4

External interrupt Group 1 ~ Group 9

VIC1

 

中断控制器

Ok6410硬件操作之中断_第4张图片

InterruptController in S3C6410X

 

中断处理

S3C6410中断处理有向量模式和非向量方式。向量中断就是不同的中断有不同的入口地址,非向量中断就只有一个入口地址,进去了在判断中断标志来识别具体是哪个中断。向量中断实时性好,非向量中断简单。

向量中断------由硬件提供中断服务程序入口地址;

非向量中断------由软件提供中断服务程序入口地址;

非向量中断方式:

 Ok6410硬件操作之中断_第5张图片

向量中断方式:

 

不论何种CPU,中断处理过程是相似的。

1)        中断控制器汇集各类外设发出的中断信号,然后告诉CPU。

2)        CPU保存当前程序的运行环境(各个寄存器等),调用中断服务程序(ISR)来处理这些中断。

3)        在ISR中进行相应的处理。

4)        清除中断

5)        最后恢复被中断程序的运行环境,继续执行。

对于不同的CPU而言,中断的处理只是细节不同。

中断控制器操作示例:

下面我们实现按键中断,这里采用的是向量中断的方式。

在ok6410的开发板上按键S2---S7对应的引脚为GPN0-----GPN5,LED1-LED4对应的引脚为GPM0----GPM3

一  设置GPN0引脚为外部中断

 Ok6410硬件操作之中断_第6张图片

#define GPNCON (volatile unsigned long*)0x7f008830
void button_init()
{
         *(GPNCON) = 0b10 ;        //设置按键S2
}


二   初始化中断控制寄存器 

定义各个寄存器的地址:

/*interrupt registes*/
#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 VIC0ADDRESS         *((volatile unsigned int *)0x71200f00)  

1  设置触发方式

外部中断配置寄存器:

 

设置按键S2下降沿触发方式:

EXT_INT_0_CON = 0b010;

2  取消屏蔽外部中断 

 

EXT_INT_0_MASK = 0;

3  使能外部中断 


VIC0INTENABLE |= (0b1);                     /* 使能外部中断*/

因为S3C6410是采用向量中断,所以就需要配置中断的入口地址。这个入口地址就是靠VICxVECTADDRy寄存器来配置的。

当按下S2时,CPU就会自动的将VIC0VECTADDR0的值赋给VIC0ADDRESS并跳转到这个地址去执行。


EINT0_VECTADDR = (int)key_handle;         /*设置入口地址*/

 Key_handle是中断处理程序的函数名。


4  使能向量中断和打开总中断

__asm__(
//打开向量中断方式
    "mrc p15,0,r0,c1,c0,0\n"
    "orr r0,r0,#(1<<24)\n"
    "mcr p15,0,r0,c1,c0,0\n"
//打开总中断,将CPRS的I位清零
    "mrs r0,cpsr\n"
    "bic r0, r0, #0x80\n"
    "msr cpsr_c, r0\n"           
    :
    :
  );

三 编写中断处理函数

void key1_handle()
{
    __asm__(
   
    "sub lr, lr, #4\n" 
    "stmfd sp!, {r0-r12, lr}\n"      
    :
    :
   );
    led_on();
        
    /* 清除中断 */
    EXT_INT_0_PEND = ~0x0; 
    VIC0ADDRESS = 0;
  
    __asm__(
    "ldmfd sp!, {r0-r12, pc}^ \n"      
    :
    :
  );
  
}

"sub lr, lr, #4\n" 计算中断处理完毕后的返回地址 

中断跳转的时候,会将pc的值给lr,pc的值为当前执行程序地址+4,lr的值就是pc的值。而返回的地址应该是执行阶段的下一条地址,也就是当前执行程序地址+4,所以直接返回lr的值就不对了,应该返回lr-4的值。

"stmfd sp!, {r0-r12, lr}\n" 保存被中断程序的运行环境,即各个寄存器。

"ldmfd sp!, {r0-r12, pc}^ \n"  恢复被中断程序的运行环境

 

Last but not least!!!

中断处理函数的代码是用c代码写的,需要栈来环境保护和恢复运行环境了。ARM有7中不同工作模式,不同的工作模式有自己的备份寄存器。其中,栈SP是每个模式都有自己的。所以需要设置下irq模式下的栈。将模式切换为irq模式,再设置sp。

init_stack:
msr cpsr_c, #0xd2
ldr sp, =0x53000000 //初始化r13_irq
msr cpsr_c, #0xd3
ldr sp, =0x54000000  //初始化R13_svc      
mov pc, lr



参考资料:《嵌入式开发完全手册》

                    http://comm.chinaaet.com/adi/blogdetail/40071.html



  

你可能感兴趣的:(中断,ARM,s3c6410)