Chinaunix首页 | 论坛 | 博客
  • 博客访问: 97799
  • 博文数量: 24
  • 博客积分: 431
  • 博客等级: 一等列兵
  • 技术积分: 245
  • 用 户 组: 普通用户
  • 注册时间: 2012-05-24 09:44
文章分类
文章存档

2013年(1)

2012年(23)

分类: 嵌入式

2012-10-07 17:45:26

ARM处理器程序的执行流程共分3种:
     1.正常执行:每执行一条ARM指令,程序计数器PC的值自动加4。程序顺序执行。
     2.跳转执行:通过B、BL跳转执行,实现程序在一定范围内的跳转执行。
     3.中断处理:在应用程序执行过程中,发送中断后,ARM处理器在执行完当前指令后,跳转到上述中断对应的中断处理程序处去执行。异常中断的响应情况。
S3C2440中断系统:实现方法:1、查询形式(实时性差,浪费处理器时间)。
                          2、中断方式(内部控制逻辑)。
ARM处理器工作模式分为用户模式和特权模式,除用户模式外的其他6种工作模式为特权模式
    此外,除用户模式和系统模式外的其他5种工作模式为异常模式。工作模式可以通过软件改变,也可以通过外部中断或异常处理来改变处理器的工作模式。大多数的应用程序运行在用户模式下,当处理器运行在用户模式下时,某些被保护的系统资源是不能被访问的。
    ARM寄存器共有37个寄存器,其中包括31个通用寄存器和6个状态寄存器,这些寄存器都是32位的。ARM处理器共有7种工作模式,每种工作模式都有对应的寄存器,在程序执行过程中,ARM处理器肯定为7种工作模式中的一种,主要有15个通用寄存器(R0~R14)、程序状态寄存器(CPSR或SPSR)、程序计数器R15(PC)。当工作模式切换时,有些寄存器是公用的,有些寄存器是各个模式拥有独立的物理寄存器模式。
1.当进行工作模式的切换时,哪些寄存器的值需要保存呢?为什么快速中断模式比外部中断模式中断响应的速度要快?
   假设用户模式(User模式)切换到外部中断模式(IRQ模式),对比ARM处理器的寄存器图,可以看到用户模式的寄存器R13~R14和IRQ模式的寄存器R13_irq、R14_irq不是同一个寄存器,说名两个是独立的寄存器,因此,当从用户模式切换到IRQ模式时不需要保存这两个寄存器的值,需要保存R0~R12共13个寄存器。
   还可以注意到,用户模式和快速中断模式(FIQ模式)公用的寄存器是R0~R7,在FIQ模式中,R8_fiq~R14_fiq是独立的。因此,当用户模式切换到快速中断模式(FIQ)时不需要保存这几个寄存器的值,只需要保存R0~R7的值即可。
   S3C2440中断控制器可以接受60个中断源的中断请求,当中断发生时,中断请求并不是直接发送给CPU,而是发送给中断控制器(中端控制器需要用户进行初始化),中断控制器进行裁决后,选择出当晚最需要处理的中断请求发送给你CPU,这样可以降低CPU的负担。
   当某事件发生时,硬件会设置某个寄存器,CPU在执行完一个指令时,通过硬件查看这个寄存器,如果发现所关注的事件发生了,则中断当前程序流程,跳转到一个固定的地址处理这个事件,最后返回继续执行被中断的程序。

中断处理的过程

    ①中断控制器汇集各类外设发出的中断信号,告诉CPU  ;    

    ②CPU保存当前程序的运行环境,调用中断服务程序(ISR)来处理这些中断

    ③在ISR中通过读取中断控制器、外设的相关寄存器来识别时哪个中断,并进行相应处理

    ④清除中断:通过读写中断控制器和外设的相关寄存器来实现

    ⑤最后恢复被中断程序的运行环境(恢复寄存器),继续执行

s3c2440的中断控制器结构如上图所示:

①request sources(without sub-register)中的中断源被触发后,SRCPND寄存器中相应位被置1,如果此中断没有被INTMSK寄存器屏蔽或者快速中断的话,它将被进一步处理。

② 对于request sources(with sub-register)中的中断源被触发后,SUBSRCPEND寄存器中的相应位被置1,如果此中断没有被INTSUBMSK寄存器屏蔽的话,它在 SRCPND寄存器中的相应位也被置1,以后的处理过程就和①步骤类似。

③如果被触发的中断中有快速中断,INTMOD寄存器中为1的位对应的中断是FIQ,则CPU进入快速中断模式进行处理

④ 对于一般的中断IRQ,可能同时有几个中断被触发,未被INTMSK寄存器屏蔽的中断经过比较后,选出优先级最高的中断,此中断在INTPND寄存器中的 相应位被置1,然后CPU进入中断模式进行处理。中断服务程序通过读取INTPND或者INTOFFSET来确定中断源。

技巧:到此为止,不难发现,这里用了一个很简单的思路:分类汇总。

  Request sources(with sub-register):同种设备可能会对应几种中断,S3C2440采取的措施是:SRCPND存储的是所有大类的中断,具体这一大类中断中哪种类型的子中断发生了,需要再查询SUBSRCPND寄存器才能得到。

  Request sources(without sub-register):这种类型的中断只有一种情况,当外部中断的触发条件满足时就产生中断,这类中断没有子类。

   如何屏蔽中断请求:最简单的情况是将该中断屏蔽掉,因此这里就涉及到一个中断屏蔽寄存器,只要向该寄存器中某一位写1,就可以将改为对应的中断屏蔽掉。

   INTMSK(需要屏蔽某一个子类中断)和INTMSK(需要屏蔽某一大类中断)。例如:寄存器INTMSK中有单独的位来屏蔽外部中断0~3,外部中断4~7是公用一位来屏蔽,主要原因是外部中断太多了,因此需要另外一寄存器EINTMASK来实现中断屏蔽。具体屏蔽哪一位,需要由寄存器EINTMASK来确定的。由上图可知,中断发生后,寄存器SRCPND中的相应位会置1,然后,如果该中断不被屏蔽,则寄存器INTPND中的相应位也会被置1。

中断模式寄存器INTMODE。

点击(此处)折叠或打开

  1. button.h
  2. #ifndef __BUTTON_H__
  3. #define __BUTTON_H__

  4. extern void Key_Init() ;
  5. extern int Key_Scan() ;


  6. #endif

button.c

点击(此处)折叠或打开

  1. #include "button.h"
  2. #include "config.h"

  3. #define KEY1 (2 << 2) //GPF1
  4. #define KEY2 (2 << 8) //GPF4
  5. #define KEY3 (2 << 4) //GPF2
  6. #define KEY4 (2 << 0) //GPF0

  7. void Key_Init(void)
  8. {
  9.     rGPFCON &= ~((3 << 0) | (3 << 2) | (3 << 4) | (3 << 8)) ;
  10.     rGPFCON |= KEY1 | KEY2 | KEY3 | KEY4 ;
  11.     rGPFDAT |= (1 << 0) | (1 << 1) | (1 << 2 ) | (1 << 4) ;//将键盘对应的四个引脚置为高电平,完成初始化工作    
  12. }


  13. int Key_Scan() //该函数在本次试验中没有用到
  14. {
  15.     int keynum = 0 ;
  16.     if((rGPFDAT & (0 << 1)) == 0 )
  17.     {
  18.         keynum = 1 ;
  19.     }
  20.     if((rGPFDAT & (0 << 4)) == 0 )
  21.     {
  22.         keynum = 2 ;
  23.     }    
  24.     if((rGPFDAT & (0 << 2)) == 0 )
  25.     {
  26.         keynum = 3 ;
  27.     }    
  28.     if((rGPFDAT & (1 << 0)) == 0 )
  29.     {
  30.         keynum = 4 ;
  31.     }    
  32.     return keynum ;    
  33. }

中断执行流程:

   系统启动后,系统进入管理模式(SVC模式,ARM处理器默认的),在发生中断后,ARM处理器会自动切换到外部中断模式(假设外部发送外部中断0,IRQ模式),每种工作模式都有对应一组可以访问的寄存器。

   2.ARM处理器做了哪些事情,还有哪些事情需要用户编程来实现?

   发生中断后,ARM处理器需要执行完当前指令,然后自动完成以下事情:

   A.将当前程序状态寄存器CPSR保存到IRQ模式下的备份程序状态寄存器SPSR_irq中(执行中断返回时,其逆过程不能自动完成)。
   B.将程序计数器PC值减4(这个地方要注意)存放到IRQ模式下的链接寄存器R14_irq中,即R14_irq=PC-4(执行完中断处理程序以后,需要返回的地址是发生中断的指令的下一条指令的地址,即PC-8处,然后将PC值设为0x00000018,接着就是访问异常中断向量表,查找到中断处理函数并执行,最后执行中断返回)。

   C.最后将PC值强制设为0x00000018(这正是异常中断向量表中IRQ的入口地址)。

  程序员需要做的事情是:

   A.根据需要,有选择的保存寄存器R0~R12的值(一般是将上述寄存器的值入栈保护)。

   B.中断发生后,ARM处理器自动将程序计数器PC的值设为0x00000018.因此,用户需要将中断处理函数放在这个地址处,一般是放置一条跳转指令,然后就可以找到中断处理函数。

  C.计算程序的返回地址,因为ARM9处理器是5级流水线,但是程序的执行阶段是处在流水线的第三级。因此,程序寄存器PC始终指向当前正在执行指令的下两条指令处。

  中断返回执行的操作是:(1)将被中断程序的处理器状态(寄存器的内容)恢复,即从IRQ模式恢复到SVC模式。(2)返回到发生异常中断的指令的下一条指令执行。 subs pc,lr,#4
  此外,也可以利用入栈和出栈指令实现:

  1. subs lr, lr, #4
  2. stmfd {r0-r12,lr}
  3. .........
  4. ldmfd {r0-r12,lr}^

   进入中断后,PC-4的值自动存储在R14_irq中,则将其减4即可得到实际的返回地址,然后将寄存器R0~R12和寄存器lr入栈(注意,此时是入的IRQ模式的堆栈,保存公用寄存器中用到的寄存器,返回恢复)。最后返回时将上述寄存器出栈即可,^表示SPSR_irq复制到SVC模式的寄存器CPSR中。注意,发生中断是,CPSR寄存器的值是由ARM处理器自动复制到IRQ模式下的SPSR_irq寄存器的,但是中断返回,需要用户手动恢复该寄存器的值。
   使用_ _irq关键字时,编译器会自动完成对寄存器的保存以及中断返回地址的计算。

 

阅读(1476) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~