系统学习AutoSAR ETAS RTA-OS嵌入式操作系统(四)中断Interrupts

系统学习AutoSAR ETAS RTA-OS嵌入式操作系统(四)中断Interrupts

5. Interrupts

中断提供了应用程序与现实世界发生事件之间的接口。例如,你可以使用一个中断来捕获按钮被按下的动作,标记时间流逝或者捕获其他刺激。当发生一个中断时,处理器通常会查看内存中预定义位置上的向量。

向量通常包含相关中断处理程序的地址。你的处理器文档和目标/编译器端口指南将为你提供更多信息。包含应用程序所有向量的内存块称为向量表。

5.1 单级和多级平台 Single-Level and Multi-Level Platforms

目标处理器根据支持的中断优先级级别进行分类。您应该确保充分了解目标硬件上的中断机制。

目标有两种不同类型:

Single-level.单级。 在单级平台上,只有一个中断优先级。如果正在处理一个中断,则所有其他待处理的中断必须等到当前进程完成后才能执行。

Multi-level. 多级。 在多级平台上,存在多个中断层次。如果正在处理一个中断,它可以被任何更高优先级的中断抢占。这有时被称为嵌套中断模型。

5.2 中断服务程序 Interrupt Service Routines

AUTOSAR操作系统使用中断服务程序(ISR)来捕获中断。 ISR与任务类似,但不同之处在于:

  • 它们不能通过RTA-OS API调用来激活。
  • 它们不能进行TerminateTask()和ChainTask()的API调用。
  • 它们从与之关联的中断优先级水平的入口点开始执行。
  • 只能使用RTA-OS API调用的子集。

参考指南告诉您每个API调用的允许调用上下文。您可以参考此指南来查看是否可以在ISR中使用API调用。

5.3 Category 1 and Category 2 Interrupts

AUTOSAR操作系统将中断分为两个类别,称为Category 1和Category 2。该类别表示操作系统是否参与处理中断:

5.3.1 Category 1 Interrupts

Category 1中断不与RTA-OS交互。它们应该始终是应用程序中最高优先级的中断。你需要正确配置硬件,编写处理程序并从中断返回。你可以在第5.6.1节了解更多关于Category 1中断处理程序的信息。

处理程序在RTA-OS的优级水平或以上执行。然而,你可以使用RTA-OS API调用来用/禁用和恢复/挂起中断。

5.3.2 Category 2 Interrupts

对于第2类中断,中断向量指向内部RTA-OS代码。当中断被触发时,RTA-OS执行内部代码,然后调用您提供的处理程序。

处理程序作为绑定到中断的ISR提供(您可以将其视为非常高优先级的任务)。执行从ISR的指定入口点开始,一直持续到入口函数返回。当入口函数返回时,RTA-OS执行另一小段内部代码,然后从中断返回

图5.1显示了一个Category 2中断处理程序的状态图。

图5.2展示了如何可视化内部RTA-OS代码包装器。

5.4 Interrupt Priorities

"中断在中断优先级级别(IPL)上执行。RTA-OS标准化了所有目标微控制器的IPL0表示用户级别,在该级别下执行所有任务,而IPL为1或更高则表示中重要的是不要将IPL与任务优先级混淆。比应用程序中使用的最高任务优先级更高。

IPL是对目标硬件上中断优先级的处理器无关描述。口的目标/编译器端口指南将告诉您有关如何将IPL映射到目标硬件中断优先级的更多信息。

在单级平台上有两个IPL,0和1。IPL 0意味着目标没有被中断,任务按优先级顺序运行。IPL 1意味着目标正在处理中断。由于只有一个非零IPL,所有中断,无论是Category1还是Category2,都以相同的优先级运行。这意味着所有中断都是串行化的。

在多级平台上,高优先级中断可以抢占低优先级中断,因此,ISR处理程序可以嵌套。例如,一个高优先级的ISR可以中断低优先级的ISR的执行。然而,ISR永远不能被任务抢占。

一个类别1的ISR决不能被类别2的ISR中断。这是因为类别2的ISR可以激活一个任务,因此在离开ISR时,操作系统需要检查上下文切换——这就是操作系统在图5.2中“包装器”函数的第二部分所做的。由于ISR可以嵌套在多级平台上,因此每次中断退出时都必须进行这种检查。现在,如果类别1的ISR可以被类别2的ISR抢占,那么在退出类别1的ISR时,不会进行上下文切换的检查,最初被抢占的任务会恢复,而不是激活的更高优先级的任务。这是优先级倒置,可能会在系统中引起未知的副作用。

这个问题意味着所有类别2ISR必须有一个IPL,不高于最低优先级类别1ISR。RTA-OS在构建时自动检查这一点,如果是这种情况,将产生一个错误。

图5.3显示了单级和多级平台的中断优先级结构。

5.4 User Level 用户等级

用户级是允许处理所有中断的最低中断优先级。

所有任务从它们的入口点开始在用户级执行。

任务有时需要在用户级之上运行,例如,它可能需要访问与ISR共享的数据。当数据被访问时,它必须阻止中断被服务。最简单的方法是让任务在数据被访问时禁用中断。这将在5.7节讨论。另一种机制是使用AUTOSAR OS的资源机制。这将在第6章讨论。

即使当任务的中断优先级高于用户级时,ISR也可以抢占任务。然而,它只能这样做,如果ISR的中断优先级高于当前级别。

5.4.2 OS Level

最高优先级类别2 ISR的优先级定义了OS级别。如果在OS级别或更高级别执行,那么其他类别2中断不能发生。

RTA-OS使用OS级别来防止对内部OS数据结构的并发访问。

任何操纵OS内部状态的RTA-OS API将在OS级别执行部分(如果不是全部)的执行时间。OS钩子(例如Error Hook,PreTask和PostTaskHook)和OS回调也在OS级别运行。如果任务在OS级别执行,那么不会发生任何RTA-OS操作(除了由任务发出的调用)。

5.5 Interrupt Configuration 中断配置

在RTA-OS中,中断是使用rtaoscfg静态配置的。图5.4展示了如何构造一个中断。

在最简单的层次上,一个中断具有以下属性:

An interrupt name 一个中断名。这个名字用来引用你将要写的用来实现处理函数的C代码(你将在5.6节中学习如何做到这一点)。

An interrupt category 一个中断类别。如果处理函数不需要执行RTA-OS API调用,那么这个类别就是类别1,否则就是类别2。

An interrupt priority 一个中断优先级。这个优先级被调度器用来决定中断什么时候运行(类似于任务优先级被用于任务的方式)。优先级是一个特定于微处理器的参数,所以在你设置优先级之前必须选择一个RTA-OS目标。注意,一些目标只支持一个中断优先级。

An interrupt vector 一个中断向量。RTA-OS使用指定的向量来生成中断的向量表项。像中断优先级一样,中断向量的配置是特定于微处理器的,所以在配置中断向量之前必须选择一个目标。

**集成指南5.1:**在IPL是用户可编程的微控制器上,那么您的责任是确保中断设备的编程优先级与您为RTA-OS配置的级别相匹配。由于这个配置必须在OS启动之前进行,RTA-OS无法为您完成这个任务,因为可能需要执行第1类ISR。RTA-OS可能能够生成适当的配置数据供您使用。您应该参考您的目标/编译器端口指南以获得具体指示。

**集成指南5.2:**RTA-OS GUI允许选择不同的目标(例如,允许您快速将一个OS配置迁移到一个新的微控制器)。当目标更改时,所有特定于目标的配置都将被删除,包括中断优先级和中断向量设置。因此,您需要提供适当的新目标设置。

5.5.1 Vector Table Generation

在大多数情况下,RTA-OS可以自动生成向量表。rtaosgen将创建一个向量表,该向量表将指向内部包装代码,并将其放置在生成的库中。

如果你想编写自己的向量表,那么你必须确保RTA-OS不生成向量表。你可以禁用向量表生成(Target -> Disable Vector Table Generation),以防止向量表被生成,如图5.5所示。

当你编写自己的向量表时,你需要确保所有与第二类ISR相关的中断向量都分支到RTA-OS中断包装器,它设置了ISR执行的上下文。

**集成指南5.3:**你不能直接分支到你的中断处理程序实现。这样做会绕过RTA-OS,并且你在处理程序上下文中尝试与内核进行的任何交互都可能导致内核状态不可恢复的损坏。

通常,您自己的向量表需要分支到形式为Os_Wrapper_VECTOR的标签,其中VECTOR是向量的十六进制地址。具体细节因端口而异。您应该查阅目标/编译器端口指南以获取有关如何提供自己的向量表的具体细节。

5.6 Implementing Interrupt Handlers 实现中断处理函数

现在,您将学习有关一类和二类中断的中断处理程序。

5.6.1 Category 1 Interrupt Handlers

编写Category 1 ISR的格式是非可移植的。微控制器的编译器通常定义了一种特定于编译器的扩展,允许将函数标记为中断。然而,有些编译器无法做到这一点。当出现这种情况时,您需要编写一个汇编语言处理程序。

你必须确保Category 1 ISR入口函数的名称与配置ISR时指定的名称相同。

对于Category 1的ISR,通常需要使用特定编译器关键字(有时称为pragma或directive)来定义入口函数。RTA-OS提供了一个名为CAT1_ISR的宏,该宏会根据您的编译工具链扩展为正确的指令,您应该使用这个宏将您的函数标记为Category 1 ISR。

An entry function for a Category 1 ISR is shown in Example 5.1.
CAT1_ISR(Interrupt1) {
    /* Handler body. */
    /* Return from interrupt. */
}
Example 5.1: Entry Function for a Category 1 ISR
5.6.2 Category 2 Interrupt Handlers

你之前看到过,Category 2中断是在RTA-OS的控制下处理的。Category 2 ISR类似于一个任务。当中断处理程序需要运行时,它有一个由RTA-OS调用的入口函数。使用C语法编写Category 2中断处理程序如示例5.2所示。

#include <Os.h>
ISR(isr_identifier){
    /* Handler body. */
}
Example 5.2: Entry Function for a Category 2 ISR

你不需要为Category 2 ISR入口函数提供任何C函数原型。这些原型在由rtaosgen生成的Os.h头文件中提供。

**集成指南5.4:**在Category 2 ISR中,你不能放置“从中断返回”的命令。从中断返回是由RTA-OS处理的。

5.6.3 Dismissing Interrupts

当硬件检测到中断时,通常会设置一个挂起位来告知中断控制器发生了中断。然后,中断控制器将通过中断向量表分支到处理程序。

挂起位的处理方式取决于目标设备,但有两种基本模型:

  1. 在中断处理程序执行分支时,待处理位会自动清除。如果在当前中断处理过程中有新的中断产生,则当处理程序退出后,它将自动重新触发。

  2. 用户代码必须在中断处理程序中手动清除待处理位。无论是第一类还是第二类的中断处理程序,在其主体部分都需要包含代码来清除待处理位,并向硬件信号表明该中断已被处理。

如果需要清除待处理位,最好在进入处理程序时立即执行此操作,因为这样可以将设置待处理位和后续清除之间的时间最小化。这有助于防止中断多次变为挂起状态但硬件无法识别的问题。代码示例5.3展示了一个Category 2 ISR处理程序的推荐结构。

#include <Os.h>
ISR(Interrupt1) {
    /* Dismiss the interrupt where required */
    /* Rest of the handler */
}
Example 5.3: Dismissing the interrupt

您需要查阅硬件参考手册,以了解需要在目标硬件上执行的操作。

5.6.4 Writing Efficient Interrupt Handlers 编写高效的中断处理程序

每个中断处理程序都会在代码执行的时间内阻塞所有优先级相等或更低的中断。当编写中断处理程序时,最好将处理程序尽可能地简短。长时间运行的处理程序会增加对较低优先级中断服务的延迟。

通过减少中断处理程序的执行时间,可以最大程度地提高整个系统的响应能力。

如果您需要执行一个长时间运行的代码片段,可以将该代码放入一个任务中,并从Category2 ISR激活该任务。示例5.4示例5.5演示了这些技术之间的区别。

使用Category 2处理程序,您可以将所需功能移动到一个任务中,只需使用中断处理程序来激活该任务,然后终止。

#include <Os.h>
ISR(InefficientHandler) {
    /* Long handler code. */
}
Example 5.4: Inefficient interrupt handler
#include <Os.h>
ISR(EfficientHandler) {
    ActivateTask(Task1);
}

TASK(Task1) {
    /* Long handler code. */
    TerminateTask();
}
Example 5.5: More efficient interrupt handler

5.7 Enabling and Disabling Interrupts

只有在使能的情况下,中断才会发生。默认情况下,RTA-OS确保在StartOS()返回时所有中断都是使能的。

集成指南5.5: AUTOSAR OS使用一词表示屏蔽中断,“Enable”一词表示解除屏蔽中断。因此,enable和disable API调用并不会启用或禁用中断源;它们只是阻止处理器识别中断(通常通过修改处理器的中断掩码)。

为了防止在任务或中断服务程序的关键代码段中发生中断,您可能需要短暂地禁用中断。关键代码段可能是一系列访问共享数据的语句。

您可以使用多种不同的API调用来启用和禁用中断:

  • DisableAllInterrupts() and EnableAllInterrupts()

    禁用和启用所有可以在硬件上禁用的中断(通常是那些可以屏蔽的中断)。这些调用不能嵌套。在DisableAllInterrupts()之后,不允许使用除EnableAllInterrupts()之外的任何No OS API调用。

  • SuspendAllInterrupts() and ResumeAllInterrupts()

    暂停和恢复所有可以在硬件上禁用的中断(通常是那些可以屏蔽的中断)。这些调用可以嵌套。在SuspendAllInterrupts()之后,之外的任何API调用,也不允许使用SuspendOSInterrupts()/ResumeOSInterrupts()对。

  • SuspendOSInterrupts() and ResumeOSInterrupts()

    暂停并恢复硬件上的所有2类中断。这些调用可以嵌套。在SuspendOSInterrupts()之后,不允许使用除了SuspendAllInterrupts()/ResumeAllInterrupts()对和SuspendOSInterrupts()/ResumeOSInterrupts()对之外的任何API调用。

如果存在比"Suspend"调用更多的"Resume"调用,可能会导致严重错误并且行为未定义。后续的"Suspend"调用可能无法正常工作,这将导致关键部分没有保护。

示例5.6展示了中断控制API调用如何正确嵌套使用。

对于Category 1用中断的整个时间内,请确保不进行任何RTA-OS API调用(除了其他Suspend/Resume调用)。

#include <Os.h>
TASK(Task1) {
    DisableAllInterrupts();
    /* First critical section */
    /* Nesting not allowed */
    EnableAllInterrupts();
    SuspendOSInterrupts();
    /* Second critical section */
    /* Nesting allowed. */
    SuspendAllInterrupts();
    /* Third critical section */
    /* Nested inside second */
    ResumeAllInterrupts();
    ResumeOSInterrupts();
    TerminateTask();
}
Example 5.6: Nesting Interrupt Control API Calls

在Category 1的ISR情况下,您必须确保在中断被禁用的整个时间内不进行任何RTA-OS API调用(除了其他Suspend/Resume调用)。

如果Category 2的ISR将中断级别提高到操作系统级别以上,则不能进行任何其他RTA-OS API调用,除非通过EnableAllInterrupts()调用来恢复中断优先级。执行ISR时,不允许将中断优先级降低到初始水平以下。

5.8 Saving Register Sets

回顾第4.15节,RTA-OS提供了一种机制,可以在上下文切换时保存寄存器集,并且rtaosgen可以优化所需的保存量以提高运行时性能。

相同的机制也可以被第2类中断服务程序使用,只需选择哪些中断服务程序使用配置的寄存器集,如图5.6所示。

集成指南5.7:默认中断不被所有端口支持。

在配置时分配给默认中断的名称必须在您编写处理程序时在应用代码中使用。示例5.7展示了一个与图5.7所示配置相匹配的默认处理程序。

CAT1_ISR(DefaultInterruptHandler) {
    /* invoke target-specific code to lock interrupts */
    asm(’di’); /* or whatever on your platform */
    for (;;) {
        /* Loop forever */
    }
/* Do NOT return from default handler. */
}
Example 5.7: The Default Interrupt Handler

默认中断与其他中断略有不同。它用于填充向量表中未定义中断的每个位置。这一特性旨在作为调试辅助工具,并在生产系统中发生错误生成中断时提供“故障停手段。如果您确实希望将中断处理程序附加到向量以执行有用的工作,应明确创建它们作为ISR。

对默认中断处理程序使用存在限制。它不能进行任何OS调用,如果其返回,则系统行为是未定义的。

**集成指南5.8:**不要从默认中断中进行任何RTA-OS API调用,也不能从处理程序返回。默认中断的实现类似于Category 1中断,因此必须使用CAT1_ISR宏将其标记为中断。您的默认中断处理程序的最后一条语句应该是一个无限循环。示例5.7展示了如何做到这一点。

5.10 Summary

  • RTA-OS支持两类中断:Category 1和Category 2。
    Category 1的ISR是正常的嵌入式系统中断,可以绕过RTA-OS。因此它们不能与操作系统交互,并且禁止进行(大多数)RTA-OS API调用。应使用CAT1标记它们。
  • Category 2的ISR RTA-OS提供包装器运行的操作系统管理中断。这些中断可以进行RTOS API调用。必须使用ISR宏标记它们。
  • 所有中断都在一个始终严格高于最高任务优先级的中断优先级级别(IPL)下运行。
  • IPLs在所有硬件设备上统一了中断优先级模型 - 较高的IPL意味着较高的优先级。
  • RTA-OS可以生成一个中断向量表,或者您可以选择编写自己的向量表。当生成向量表时,RTA-OS可以使用用户配置的默认中断来填充未使用位置。
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

艾格北峰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值