1. 概述
中断是指MCU在运行过程中,出现某些意外情况需处理时,MCU能自动停止正在运行的程序并转入处理新情况的程序,处理完毕后又返回原被暂停的程序继续运行。
当中断发生时,处理器通常查看内存中的一个预定义位置,称为中断向量。向量通常包含相关中断处理程序的地址,而包含应用程序中所有向量的内存块称为中断向量表。
中断提供了应用程序与现实世界中发生的事情之间的接口。例如,我们可以使用中断来捕获触发的按钮、看门狗喂狗操作或计算发生的时间等。
2. 基本概念
2.1 单级与多级
单级:即所有中断处于同一优先级,当一个中断正在执行时,其他中断必须等待直到当前中断处理完成。
多级:即中断也区分不同的优先级,高优先级的中断可以抢占低优先级的中断。
2.2 中断服务函数
AUTOSAR OS使用中断服务程序(ISR)捕获中断。ISR与任务类似,但ISR的不同之处在于:
- 不能被RTA-OS的API调用激活;
- 无法被TerminateTask()和ChainTask()API调用;
- 在相关的中断优先级级别从入口点开始执行;
- 只能进行RTA-OS API调用的子集。
2.3 一类与二类中断
在AUTOSAR OS中按OS是否参与处理将中断分为一类及二类中断:
一类中断:不与RTA-OS进行交互,是应用程序中优先级最高的中断,需要用户正确的配置硬件、编写处理程序并从中断中返回。
二类中断:中断向量表指向内部RTA-OS代码,当引发中断时,RTA-OS执行内部代码,然后调用用户提供的处理程序。
处理程序是作为绑定到中断的ISR提供的(我们可以认为这是一个非常高优先级的任务)。执行从ISR的指定入口点开始,一直持续到入口函数返回。当entry函数返回时,RTA-OS执行另一小段内部代码,然后从中断返回。
2.4 中断优先级
中断以中断优先级(IPL)执行,RTA-OS标准化了IPL,IPL 0表示用户级别,其中所有任务都执行,IPL为1或更多表示中断级别。注意不要将IPL与任务优先级混淆, IPL为1高于应用程序中使用的最高任务优先级。
IPL是对目标硬件中断优先级的独立于处理器的描述。在单级平台上有两个IPL,0和1。IPL 0表示目标不被中断,任务按优先级顺序运行。IPL 1表示目标正在为中断提供服务。由于只有一个非零IPL,所有中断(类别1和类别2)都以相同的优先级运行。这意味着所有中断都是序列化的。 在多级平台上,高优先级中断可以抢占低优先级中断,因此ISRs处理程序可以嵌套,但ISR不能被低优先级任务抢占。
一类中断不能被二类中断抢占,即所有的2类中断都比最低级的一类中断低。这是因为2类ISR可能会激活任务,因此操作系统在离开ISR时需要检查上下文切换。
由于ISR可以嵌套在多级平台上,因此每次中断退出时都必须进行此检查。如果1类ISR可以被2类ISR抢占,则在退出1类ISR时,不会检查上下文切换,并且最初抢占的任务将恢复,而不是激活的高优先级任务。这是优先级反转,这可能会在系统中造成未知的后果。
2.4.1 User Level
Task级别即是User level. 用户级别是允许处理所有中断的最低中断优先级。所有任务都从其入口点开始在用户级别执行。 任务有时需要在用户级别以上运行,例如,它可能需要访问与ISR共享的数据。当数据被访问时,必须防止中断被调用。实现这一点的最简单方法是,任务在访问数据时禁用中断。另一种机制是使用AUTOSAR OS的Resource机制。 即使任务在中断优先级高于用户级别的情况下运行,ISR也可能抢占任务。但是,只有当ISR的中断优先级高于当前优先级时,它才能这样做。
2.4.2 OS Level
由于二类中断是需要OS参与参与,这样即2类ISR的最高优先级定义了OS级别。如果执行发生在OS级别或更高级别(一类中断),则不会发生其他类别2中断。 RTA-OS使用OS Level来防止并发访问内部操作系统数据结构。任何操作操作系统内部状态的RTA-OS API都将在OS级别执行其部分(如果不是全部)执行时间。OS Hook(例如:ErrorHook、PreTask和PostTaskhook以及OS回调也在操作系统级别运行。如果任务在OS级别执行,则不会发生RTA-OS操作(任务发出的调用除外)。
3. 中断配置
RTA-OS使用的是静态配置,最简单的中断需要配置的内容包括:中断名、中断类别、中断优先级及中断向量表。 RTA-OS使用指定的向量为中断生成向量表条目。与中断优先级一样,中断向量配置也是MCU特有(不同MCU,向量表不同)的,因此在配置中断向量之前必须选择目标。
3.1 中断向量表的生成
在大多数情况下,RTA-OS可以自动生成向量表。如果用户要自己写向量表,需要确保RTA-OS没有生成向量表。通常,用户自己的向量表需要分支到形式为Os_Wrapper_vector的标签,其中vector是向量的十六进制地址。
4.中断的应用
4.1 中断处理程序的实现
4.1.1一类中断的处理
编写1类ISR的格式是不可移植的。微控制器的编译器通常为ANSI C定义一个编译器专用扩展,允许将函数标记为中断。然而,有些编译器无法做到这一点。当这种情况发生时,用户将需要编写一个汇编语言处理程序。
用户必须确保1类ISR输入功能的名称与用户在配置期间为ISR指定的名称相同。对于1类ISR,在定义输入函数时,通常必须使用编译器特定的关键字(有时称为pragma或指令)。RTA-OS提供了一个名为CAT1_ISR的宏,该宏可扩展为编译器工具链的正确指令,用户应使用该指令将函数标记为1类ISR。
4.1.2 二类中断的处理
二类中断在RTA-OS控制下执行,当二类中断需要执行,由RTA-OS调用中断的入口函数,二类中断的入口函数如下:
#include <Os.h>
ISR(isr_identifier){
}
注意:不得在2类ISR中放置“中断返回”命令。中断返回由RTA-OS处理。
4.1.3 中断解除
当硬件检测到中断时,它通常会设置一个挂起位,告诉中断控制器中断已经发生。然后,中断控制器将通过中断向量表分支到处理程序。
挂起位的处理取决于目标,但有两个基本模型: 1.中断处理后(即中断处理程序的分支发生时),挂起位自动清除。当处理程序退出时,如果在处理当前中断时中断变为挂起状态,它将自动重新触发。 2. 挂起位必须由中断处理程序中的用户代码手动清除。中断处理程序的主体,无论是类别1还是类别2,都需要包含清除挂起位的代码,并向硬件发送中断已被处理的信号。
4.2 高效的中断处理程序
每个中断处理程序将在代码执行期间阻止所有优先级相同或较低的中断。编写中断处理程序时,最好将处理程序尽可能短。长时间运行的处理程序会为低优先级中断的服务增加额外的延迟。
使用中如果需要在中断中处理较多的代码,可以采用:将代码写到Task中,再通过中断来激活Task,这样低优先级的任务可以打断该Task从而减少延迟,示例代码如下:
#include <Os.h>
ISR(EfficientHandler) {
ActivateTask(Task1);
}
TASK(Task1) {
TerminateTask();
}
4.3 启用与禁用中断
只有将中断使能了才会发生,对于RTA-OS,在StartOS()后默认所有中断都打开。 AUTOSAR OS使用术语Disable表示屏蔽中断,而Enable表示取消屏蔽中断。因此,启用和禁用API的调用不会启用或禁用中断源;它们只是阻止处理器识别中断,可以调用如下API来启用或禁用中断: ? DisableAllInterrupts() and EnableAllInterrupts() 在硬件层面启用或禁用中断,这两个API不能嵌套 在DisableAllInterrupts()后必须再调用EnableAllInterrupts()。 ? SuspendAllInterrupts() and ResumeAllInterrupts() 挂起及恢复所有中断,可以被嵌套 ? SuspendOSInterrupts() and ResumeOSInterrupts() 可以嵌套使用。 Suspend与Resume需要成对出现,Resume不要比Suspend多。
使用示例:
#include <Os.h>
TASK(Task1) {
DisableAllInterrupts();
EnableAllInterrupts();
SuspendOSInterrupts();
SuspendAllInterrupts();
ResumeAllInterrupts();
ResumeOSInterrupts();
TerminateTask();
}
注: 1) 一类中断在关闭期间,不可以调用OS的API 2) 如果2类ISR将中断级别提高到OS级别以上,并调用DisableAllInterrupts( ),则它可能不会进行任何其他RTA-OS API调用,但用于恢复中断优先级的EnableAllInterrupts( )调用除外。执行ISR时,不允许将中断优先级降低到初始级别以下。
4.4 默认中断
在使用RTA-OS生成中断向量表时,用户可能希望使用默认中断填入未使用的向量表位置。配置时分配给默认中断的名称是在编写处理程序时必须在应用程序代码中使用的名称。示例显示了一个默认处理程序。
CAT1_ISR(DefaultInterruptHandler) {
asm(’di’);
for (;;) {
}
}
注: 1)不要在默认中断中调用任何RTA-OS的API; 2)默认中断的使用类似于一类中断,也需要使用CAT1_ISR的宏。
|