ARM7/9 的中断与 RTOS 系统

来源:互联网 发布:人工智能 文化创意 编辑:程序博客网 时间:2024/05/22 20:21

(本文原创,转载注明出处,谢谢) 

 

最近比较忙,博客没有更新。今天特别想起来朋友问我的一个问题ARM7、ARM9支持嵌套中断吗?这个问题当时我不假思索的回答支持。

 

实际上,这个问题并不像我想象的那么简单,是非常复杂的。在RTOS系统里,如果想支持ARM的嵌套中断,也需要对RTOS针对ARM做特殊的处理。

 


首先我们来看一个问题,ARM的中断过程。ARM 有两种中断,一个是FIQ;一个是IRQ。FIQ异常中断为快速异常中断,它比IRQ异常中断优先级高。体现在:

1.当FIQ和IRQ异常中断同时产生时,CPU先处理FIQ异常中断;

2.在FIQ异常中断处理程序中,IRQ异常中断被禁止。

 

同时,与其他的异常模式相比,FIQ异常向量还有额外的5个物理寄存器,在进入FIQ处理程序时,可以不用保存这5个寄存器,从而也提高了FIQ异常中断的执行速度。

 

 

当中断来临时,ARM硬件响应IRQ异常中断的伪代码如下所示:

R14_irq = address of  next instruction to be executed + 4

SPSR_irq = CPSR

/*进入IRQ异常中断*/

CPSR[4:0]=0b10010

/*切换到ARM状态*/

CPSR[5]=0

/*CPSR[6] is unchanged*/

/*禁止IRQ异常中断*/

CPSR[7] =1

if high vectors configured then

PC = 0xFFFF0018

else

PC = 0x00000018

 

硬件响应FIQ异常中断的伪代码如下:

R14_fiq = address of next instruction to be executed + 4

SPSR_fiq = CPSR

/*进入FIQ异常中断模式*/

CPSR[4:0]=0b10001

/*切换到ARM状态*/
CPSR[5]=0

/*禁止FIQ异常中断*/

CPSR[6]=1

/*禁止IRQ异常中断*/

CPSR[5]=1

if high vectors configured then

PC=0xFFFF001C

else

PC=0x0000001C

 

 

看到这里我们可能已经明白了,ARM在IRQ状态下,是不允许IRQ中断的,允许FIQ中断嵌套;而在FIQ中断下,既不允许IRQ中断,也不允许FIQ中断。这是不是意味着ARM不支持中断嵌套呢?在RTOS中又如何设计呢?

 

 

先看看ARM支持不支持嵌套中断。进入IRQ时,CPSR[5]=1;那么也意味着,IRQ产生中断后,就不能再中断了。如果我们手动的将CPSR[5]=0,这样,在IRQ状态下即可允许产生第二个IRQ中断。但第二中断来了,根据上面的伪代码很显然会破坏 R14_irq、SPSR_irq。

 

 

杜春雷《ARM体系结构与编程》一文中给出的办法是:

  1. 将返回地址保存到IRQ的数据栈中;
  2. 保存工作寄存器和SPSR_irq;
  3. 清除中断标志位;
  4. 将处理器切换到系统模式,重新使能中断(IRQ/FIQ);
  5. 保存用户模式的LR寄存器和被调用者不保存的寄存器;
  6. 调用C语言的IRQ/FIQ异常中断处理程序;
  7. 当C语言的IRQ/FIQ异常中断处理程序返回后,恢复用户模式的寄存器,并禁止中断(IRQ/FIQ);
  8. 切换到IRQ模式,禁止中断;
  9. 恢复工组寄存器和寄存器LR_irq
  10. 从IRQ异常中断处理程序中返回。

书中也给了现实的代码例子,这个处理过程是通用处理过程。一般的RTOS系统,比如说uC/OS-II和RTEMS,从bootloader接手CPU的控制权后,就停留在SVC模式下执行。用户态和系统态根本就没有用到。FIQ模式也没有用到。只用到:SVC模式、IRQ模式、UND和ABT模式。

 

我从uC/OS-II的官网上下载了uC/OS-II 2.86 在 AT91SAM9260 上的移植代码。相关代码罗列如下:

 

进入中断的向量的代码从384行的,OS_CPU_ARM_ExceptIrqHndlr开始。

 

 

将相关寄存器保护后进入OS_CPU_ARM_ExceptHndlr处执行,分为两种情况,一种是从SVC模式中断;另外是从其它模式中断而来。我们从上面的IRQ进入的伪代码可知,在不支持嵌套的情况下,必然是从SVC模式而来。所以,必然从标号OS_CPU_ARM_ExceptHndlr_BreakTask 处执行。贴出的两段代码英文注释写得非常清楚了,在这里不做细细的介绍了。我只大致说一下这段代码的问题:

 

我们上面贴出的ARM进入IRQ模式的伪代码是硬件过程,硬件自动完成的。这段代码并未考虑这一点,441行和445行还禁止了IRQ中断。471和472行又恢复了中断。这是多余的一个工作。中断本身就是禁止的,恢复后依然是禁止的。从整段代码来看,这个代码是支持嵌套中断的代码,但却没有考虑到ARM中断的硬件动作。致使嵌套中断的代码变成了不支持嵌套中断的代码。

 


仔细看一下这段代码,uC/OS-II系统中断栈的处理,基本上是中断栈使用中断硬件独立的栈,而任务使用任务的栈。这样可以避免任务栈的浪费,有些CPU不支持中断的独立栈,只能是浪费被中断了的任务的栈。uC/OS-II这个移植做得还不错。充分考虑了栈这里的特点,使用了ARM的硬件栈,避免了任务栈的浪费。

 

 

如果将uC/OS-II的代码改为支持嵌套中断的代码也非常简单,在第461和462行插入伪代码

 

R2 &= ~(OS_CPU_ARM_CONTROL_IRQ_DIS);

 

在第499和500行也插入同样的伪代码。这样,就将屏蔽的中断位打开了。即可允许嵌套了。RTEMS的移植包中,其实也有同样的问题,但我还没有细细的阅读相关的代码,回头读完一并将代码分析贴出来。

 

写得不好,希望大家宽宥,如有错误,希望多多指教。



(本文原创,转载注明出处,谢谢) 

 


 

 

 


原创粉丝点击