嵌入式RTOS---异常和中断处理流程

ARM中断体系

以S3C2440讲解

1 中断体系硬件原理

中断处理分为统一的中断处理和独立的中断处理;

1.1 统一的异常和中断处理

1.1.1 ARM的异常模式

所谓异常,指的是中止了程序正常的执行过程而不得不完成一些特殊的工作(异常工作)。

中断也是一种异常,中断包括由外部硬件产生的外部中断和内部硬件产生的内部中断。

异常分为同步异常(SWI 软件指令产生的异常)和异步异常(IRQ/FIQ中断,由外部硬件产生);

1.1.2 异常模式及寄存器

ARM一共37个寄存器,7种工作模式,除了用户模式和系统模式外,其余5个为异常模式;除了用户模式外,其余6个为特权模式。

每种模式都拥有自己的私有寄存器和共有寄存器,如图所示,

R15—PC:程序计数器,代表当前程序的运行位置。多级流水线时情况复杂一些。

R14—LR:链接寄存器,保存上一程序的返回地址,当某种特权模式被动发生,那么CPU会将上一个模式下R15(PC)寄存器的值保存到相应的特权模式的私有寄存器R14_mode(LR_mode)中。

R13—SP:堆栈指针,每种异常模式下均有堆栈指针SP_mode,这样,堆栈指针保证了各种模式下堆栈的独立性,避免了相互干扰。

 

注意,共有寄存器在各个模式下都是允许访问的。由于共有寄存器中还保存了上一个异常模式下的使用值,因此,该模式能够使用的寄存器只有该模式私有寄存器对应的共有寄存器,如果在该异常模式下需要使用某些共有寄存器,则使用之前需将这些寄存器保存到该模式的堆栈中。压栈是需要时间的。

 

CPSR/SPSR

CPSR—当前程序状态寄存器;

SPSR—现场保存程序状态寄存器

 

知识拓展:

FIQ与IRQ区别

  1. 进入异常模式时,保存的寄存器数量不同。FIQ有更多的寄存器可以保存现场数据,因此,中断切换时更加快速。同时,可以使用的共用寄存器更多,无需再对用到的共用寄存器进行压栈处理,因此,效率更高;
  2. FIQ一般占用独立的中断线,没有中断等待,屏蔽,优先级最高,没有子中断等;

 

1.1.3 统一的异常处理过程

当异常发生时,硬件会自动执行以下动作:

  1. 将CPSR保存到相应模式的SPSR中;
  2. 将PC寄存器保存到相应模式的LR中;
  3. 将CPSR设置成相应的异常模式(这一步会关闭中断);
  4. 设置PC寄存器的值为相应的异常处理程序的入口地址;

说明:中断发生后,一般硬件会自动屏蔽CPU对中断的响应,而软件层面上,直到IRQ HANDLER做完,才会重新开启中断。比如,对于ARM处理器而言,exception进来的时候,硬件都会自动屏蔽中断:

 

 

 

执行完上述步骤,程序便进入到软件控制部分,软件会从相应的入口地址处运行第一条指令

由于指令执行多级流水线的问题,各种异常模式下PC的指向位置也不相同,因此,异常返回时LR的偏移也不一样。

 

1.1.4 异常向量表

每种异常模式都有一个唯一的入口地址,彼此相邻,称为异常向量表。

 

(1)异常向量表通常是从物理地址0x00000000开始的,当然也可以通过MMU重映射到其它物理地址处处。

(2)异常向量表是一段出现在固定位置的内存空间,当某一异常发生时,程序最终到达相应的异常入口去执行存放在那里的指令。

(3)拿中断IRQ来讲,IRQ里面通常存放的是一些跳转指令,跳转到相应的中断分发函数。

 

 

 

 

1.2 独立的中断处理

所谓独立的中断处理,指的是不同的外设路由到同一中断的方式不大相同,需要单独进行处理。

1.2.1 中断路由

首先,当有中断请求时,SUBSRCPND或者SRCPND中的相应位会被置1
然后,根据SUBMASK和MASK寄存器的设置值进行相应的屏蔽,如果一个中断请求发生但被屏蔽了,中断信号传递停止
最后,根据MODE寄存器判断该中断源的模式,如果是快中断模式(系统只有一个中断源为快中断其他的都为普通中断)直接执行,如果是普通中断则跟其他普通中断角逐出一个优先级最高的送到INTPND寄存器

 

1.2.2 中断控制器

在ARM中,中断一般由中断控制器组成,以S3C2440为例,S3C2440的中断系统一共需要设置5个寄存器,中断源寄存器SRCPND、SUBSRCPND,中断模式寄存器INTMOD,中断屏蔽寄存器INTMASK、INTSUBMASK,中断优先级寄存器PRIORITY,中断挂起寄存器INTPND。

1.2.2.1 中断源寄存器

s3c2440支持60个中断源,部分是子中断源(比如串口接收中断、串口发送中断、串口错误中断都属于串口中断)

SRCPND中断源寄存器地址为0X4A000000,它一共32位,每一位都代表一个中断源,相应的中断置1就表示有中断请求,置0就表示无中断请求(中断的置1系统自动完成,清0需要用户手动)。

清0的方法就是向SRCPND或者SUBSRCPND的相应位写1即可,清0的位置由用户决定。如果在中断处理程序结束处清0,那么在执行中断程序过程中即便该中断源又有中断请求,程序也无法响应。如果中断处理程序的开始处清0,那么在执行中断处理程序的过程中该中断源又有中断请求程序也能响应。

SRCPND寄存器中每位代表的中断源如下:

SUBSRCPND子中断源寄存器地址为0X4A000018,每位代表的中断源如下:

 

 

 

1.2.2.2 中断模式寄存器

INTMOD中断模式寄存器的地址为0X4A000004,一共32位,每位代表的中断源和SRCPND中一致。如果置1则相应位的中断源就为快中断,否则就为普通中断。(32个中断源中只有一个能设为快中断)

1.2.2.3 中断屏蔽寄存器

INTMSK中断屏蔽寄存器的地址为0X4A000008,一共32位,每位代表的中断源和SRCPND中一致。如果置1则相应的中断源将不被响应,否则可以响应相应的中断源。(中断屏蔽不影响:有中断请求SRCPND相应位置1)

1.2.2.4 中断优先级寄存器

s3c2440优先级仲裁模块示意图如下:

s3c2440优先级逻辑由7个仲裁器构成。每个仲裁器中REQ0优先级最高,REQ5优先级最低。余下的REQ1、REQ2、REQ3、REQ4优先级则由ARB_MODE(1位)和ARB_SEL(2位)来决定。

仲裁器的ARB_SEL位和各输入信号优先级对应关系表

当某个仲裁器的ARB_MODE被设置为0时,它的ARB_SEL位是不会自动变化的,此时该仲裁器的输入引脚的优先级固定不变。(当然可以通过软件修改ARB_SEL的值来改变它们的优先级)当ARB_MODE的值设置为1时,ARB_SEL会随着已被服务的IRQx(x为1~4)值而自动改变。

 中断优先级仲裁器的ARB_SEL变化规则

s3c2440的优先级寄存器PRIORITY 的位置为0x4A00000C,为32位,7组仲裁器,每组使用3位,共使用21位,其寄存器每位的分布如下:

   

1.2.2.5 中断待决寄存器

中断待决寄存器INTPND地址为0X4A000010,一共32位,每位代表的中断源和SRCPND中一致。如果相应位置1则中断请求被受理。同一时间只允许一个中断源被受理。(INTPND置1系统自动,清0用户手动,在SRCPND清0后才清除)

INTOFFSET中断偏移寄存器地址为 0X4A000014,一共32位,表示INTPND中的置1位的位序号(0~31),它在INTPND和SRCPND清0后自动清0。

 

2 中断体系软件实现

2.1中断分发原理

2.1.1 异常向量表的位置

我们知道ARM 的异常向量表要求放置到0x0地址处,可以采用哪些方法将异常向量表放到CPU 可见的0x0地址处?

  1. 将异常向量表放置到Nor Flash 0x0地址处,利用芯片特性实现跳转;
  2. 程序启动时将向量表搬到0x0地址处;
  3. 使用MMU进行地址remap;

 

以mini2440-gcc-ucos中为模板讲述

 

2.2 中断处理过程

 

2.2.1 简单的中断处理

以普通的中断irq进行一场处理流程的讲解。

 

可以将中断的简单执行过程分为3个阶段:
某个进程第一阶段执行时,被一个中断中止,于是系统进入了第二个阶段,进行中断处理,中断处理完成后,再回到进程被中止的位置继续执行,运行第三阶段代码。

 

 

在中断模式下,代码会最终跳转到__vector_irq处运行,此处,CPU首先修正返回地址的,然后保存相关的寄存器数据,最后跳转到common_irq_handler继续执行。

common_irq_handler函数中需要完成如下功能:

  1. 关中断;
  2. 判断中断发生的源,清除中断;
  3. 跳转到具体的中断服务函数,执行中断服务;
  4. 开中断;

 

下面以sys-timer心跳定时器中断为例说明中断的简单处理流程。

S3C2440一共集成了5个定时器,其中TIMER0-TIMER3均有外部输出引脚,专门为外部外设提供同步时钟,而第五个定时器TIMER4则是一个内部定时器,对外没有引脚,直接连接到了中断控制器上。这5个定时器的工作原理是一致的。,如下图,

在配置完定时器使用的时钟PCLK,定期器相关的寄存器,使能定时器后,定时中断就会周期性的产生。

 

 

 

 

2.2.2 简单中断嵌套处理

如简单的中断处理,程序运行在第一阶段和第二阶段时,是允许被其他的中断中止的,但当第二个阶段发生时,CPU自动的将CPSR的I位和F位置1,也就是说,第二个阶段的中断是禁止的。当处理某个硬件中断时,另外的硬件也可能产生了中断请求。只能等到退出了第二阶段后才能去处理。

若第二阶段运行的时间较长,并且同时又很多硬件产生了中断,就会出现中断延迟,延长了中断处理的时间,降低了系统的响应速度。解决这个问题的方法有2个:

  1. 允许中断嵌套
  2. 引入中断优先级;

2.2.2.1 基本原理

使用中断嵌套处理中断延迟的方法多见于一些通用操作系统中。其基本实现是中断请求部分高低贵贱,生来平等,没有谁重要谁不重要之分,只优先处理最新发生的中断请求。

中断嵌套的示例图。

如图,当第一个中断还未执行完成,第二个中断就已经产生,于是CPU先去执行第二个中断,执行完毕后,回到第一个中断处理程序中继续执行。第二个中断请求延时没有了,而第一个中断请求的时间延长了,但毕竟也只行了一部分,从而整体上提高了中断的效率。

 

具体实现上,要解决中断模式下又发生了中断,SPSR_mode/LR_mode所保存的值会被重新覆盖的问题,从而造成数据丢失。即使我们可以将SPSR_mode寄存器压入到堆栈中,但是也无法通过类似的方式解决LR_mode的问题(因为LR_mode中保存的是函数的返回地址,我们根本也不知道什么时间异常会发生)。

 

一般采取的方式是切换到其它模式进行中断处理。当中断嵌套发生在其它模式(如SVC模式)时,函数调用的返回值会保存在寄存器LR_svc中,即使此时中断再次发生,CPU也会自动进入中断模式,将被中断程序的返回值保存到LR_irq中,二者并不冲突。

 

2.2.2.2 基本实现

中断嵌套的一个例子

 

 

在enable_irq()和disable_irq()函数之间,虽然与某一硬件有关的中断服务正在处理,但同时也允许其他中断发生。

 

2.2.3 改进后的中断嵌套处理

使用上面的中断嵌套虽然很好的解决了中断嵌套的问题,但是中断使能的时间偏少。

在处理中断请求时,程序首先从中断模式切换到管理模式,在管理模式下使能全局中断,在中断处理完成后,又需要先禁止全局中断,然后切换中断模式,最后返回到上一状态中。

 

中断嵌套的一个原则:

不允许在中断模式下使能全局中断。因为这样会导致中断模式下函数返回值寄存器R14_irq被改写。所以,想要延长使能中断的时间,就以为着减少中断处理程序在中断模式下的时间。

实现方法:

让中断处理程序在管理模式下直接返回到被中断之前的模式,而不是在回到中断模式,然后在回到之前的模式。

 

 

改为

实现该功能的关键点是将上一状态的寄存器直接保存管理模式的堆栈中。

 

 

2.2.4带中断优先级的处理流程

非嵌套与嵌套中断处理都是以先来先服务的原则为中断提供服务。带优先级的中断处理将特定的中断源与优先级联系起来,优先级用来指示中断服务的次序,高优先级的中断比低优先级的中断优先得到服务。

进行优先级排序可以由硬件或软件完成。

对于硬件优先级处理,程序设计比较容易,因为中断控制器会提供当前需要服务的最高优先级中断。这些系统需要在系统初始化时,构造与之联系的优先级表。如NVIC,中断发生后,直接跳转到中断对应的地址处

 

对于软件优先级处理,也需要外部中断控制器的协助,但这种中断控制器只提供一些基本的功能,包括设置和清除屏蔽码,读中断状态和中断源,然后根据中断源跳转到对应的地址处。

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值