韦东山嵌入式Linux学习笔记08--中断体系结构

   举个栗子, 系统怎么知道你什么时候插入鼠标这个设备? 可以有两种处理方式:

1. 查询方式:

  轮询去检测是否有设备插入;

2. 中断的方式

  当鼠标插入这个事件发生时, 置位某个寄存器,告诉CPU去处理这个事件.

对于查询方式, 我们需要一直去监控想要知道的状态, 而中断的处理方式, 使得CPU有空去处理其他的事情, 当插入鼠标这个时间发生时才来处理这个事件, 这样下来,

处理效率会高很多,中断的作用也可见一斑.

下面介绍s3c2440的中断控制器

s3c2440有60个中断源, 这么多中断源, 怎么处理? 下面是中断处理的一个框图:

 上面框图中寄存器的介绍:

SUBSRCPND, 它包含的中断源如下, 当这些中断发生时,对应的位会被自动置1.我们可以往某位写入1来令此位为0,写入0无效果,数据保持不变.

 SUBSRCPND寄存器后面是SUBMASK寄存器, 这个寄存器用作屏蔽中断, 这个寄存器的对应的位与SUBSRCPND对应. 当这里相应的

位被置一之后,即使相应中断发生了,也会被屏蔽掉. 这就是这个寄存器的作用.

 

SRCPND寄存器, 这里包含了SUBSRCPND中没有的一些中断源, 同样地,当中断被相应之后,相应的位会被置一,如果需要清除中断,往相应的位写入1就可以实现清0的效果.

 

 

 INTMOD寄存器

这个寄存器同样由32位组成,每一位对应于一种中断源,如果某一位被设置为一,那么这个中断源就会被当做是快速中断来处理.且只有一个位可以被设置成快速中断,其他都为普通中断.

 

 INTMASK寄存器, 这个寄存器也是用于屏蔽某一种中断源.与SRCPND对应.

 

 出现多个普通中断时有可能同时出现的,这时候就需要告诉CPU那种中断源优先级更高,CPU根据优先级高低先后处理中断.

 上图中的ARB_SELN(n:0-6)时什么来的?原来CPU有一个仲裁器,用来对中断源进行仲裁, 如下图, 有6个一级仲裁器和1个二级仲裁器

REQ0总是有最高的优先级, REQ5总是有最低的优先级. REQ1-REQ4可以根据上面的寄存器进行设置.  当ARB_MODEn被设置为0时,

当这个中断被处理之后,REQn的优先级不会发生变化,当ARB_MODEn被设置为1时,当这个中断被处理之后,REQn优先级会被置为最低,

INTPND寄存器, 经过中断优先级仲裁器选出优先级最高的中断后,这个中断的相应的位会被置1, 如果想要清除中断,往这个位写1

测试代码: head.S

.extern     main
.text                                 @表明这里为代码段
.global _start 
_start:                              @系统一上电先从这里开始跑

    b   Reset                       @这条语句的地址为0x00
HandleUndef:                 
    b   HandleUndef             @ 0x04: 这条语句在地址0x04处, 标号就在它上方,实际这里什么都不干
HandleSWI:                   
    b   HandleSWI                @ 0x08:同0x04
HandlePrefetchAbort:       
    b   HandlePrefetchAbort  @ 0x0c:同0x04
HandleDataAbort:            
    b   HandleDataAbort       @ 0x10:同0x04
HandleNotUsed:              
    b   HandleNotUsed          @ 0x14:同0x04
    b   HandleIRQ                 @ 0x18: 这里实际是有相关的代码实现的
HandleFIQ:                     
    b   HandleFIQ                 @ 0x1c:同0x04

Reset:                                @系统复位,会自动执行0x00地址的b reset跳转到这里
    ldr sp, =4096                 @下面是调用c函数,所以要先设置栈指针,由于CPU的内部RAM只有4k,所以是指成4096
    bl  disable_watch_dog     @这里只是往控制看门够的一个寄存器写值关闭看门狗
    
    msr cpsr_c, #0xd2          @ 进入中断模式
    ldr sp, =3072                  @ 然后设置中断模式的栈指针

    msr cpsr_c, #0xd5           @进入系统模式
    ldr sp, =4096                   @设置系统模式栈指针
                          @ 其实系统复位就处于系统模式
    bl  init_led                        @初始化LED相关的GPIO引脚
    bl  init_irq                        @ 中断初始化函数
    msr cpsr_c, #0x5f            @ 开IRQ中断
    
    ldr lr, =halt_loop               @ 设置返回地址
    ldr pc, =main                   @ 调用main函数
halt_loop:
    b   halt_loop

HandleIRQ:
    sub lr, lr, #4                     @计算返回地址?
    stmdb   sp!,    { r0-r12,lr }   @保存使用到的寄存器
                                           @
                                           @
    
    ldr lr, =int_return             @ 设置函数的返回地址
    ldr pc, =EINT_Handle            @ 调用EINT_Handle函数
int_return:
    ldmia   sp!,    { r0-r12,pc }^  @ 中断返回, ^表示将SPSR的值复制到CPSR中
                    

发现上面的代码多了一些陌生的知识,比如系统的模式, 

ARM体系CPU有7中工作模式:

1.用户模式: ARM处理器正常的程序执行状态. (usr)

2.快速中断模式: 用于高速数据传输或通道处理; (fiq)

3.中断模式: 用于通用的中断处理; (irq)

4.管理模式: 操作系统使用的保护模式; (svc)

5.数据访问终止模式: 当数据或指令预取终止时进入该模式,用于虚拟存储及存储保护; (abt)

6.系统模式:运行具有特权的操作系统任务; (sys)

7.未定义指令终止模式: 当未定义的指令执行时进入该模式,可用于支持硬件协处理器的软件仿真. (und)

这些模式的切换可以通过软件设置来进行切换, 或者当CPU发生中断或者异常时自动进入相应的模式. 除用户模式外,其他6种模式都属于特权模式.大多数程序运行与用户模式,进入特权模式是为了处理中断, 异常或者访问被保护的系统资源.

比如, CPU复位上电也属于一种异常, 会自动跳转到0x00地址执行指令, 当CPU发生通用中断时, 会自动进入中断模式并且跳转到0x18地址处执行指令.

 如上图, 每种模式都有一些"备份寄存器", 这些寄存器是每种模式下与其他模式不同的寄存器,是独立的. 

R13被称为栈指针寄存器,又叫SP

R14被称为程序链接寄存器

R15被称为程序计数器

比如你在fiq模式下设置了SP的地址, 又可以切换到irq模式下设置SP的地址,这两个SP地址是互相独立的.

关于切换CPU模式,我们可以更改寄存器CPSR(Current Program Status Register)的值,

CPSR各个位的意义如下:

 

 

 进入异常模式时应该按照以下步骤执行:(CPU核自动执行)

 1.  在异常工作模式的R14中保存前一个工作模式的下一条指令. 对于ARM状态,这个值是当前PC值加4或者加8,参考下表

  2. 将CPSR的值复制到异常模式的SPSR(Saved Program Status Register)

 3. 将CPSR设置为相应的异常对应的工作模式.

4.将PC值等于这个异常在异常向量表中的地址(这里的异常向量表指的上面代码0x00-0x1c地址的指令)

退出异常模式的操作步骤:(软件完成)

1.将前面保存在R14中的值,将它减去一个值,参考上表

2.将SPSR的值复制回CPSR

猜你喜欢

转载自www.cnblogs.com/cheyihaosky/p/11938886.html