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