所有现代微处理器和微控制器都有某种类型的中断设施。此功能对于提供许多应用程序所需的响应能力至关重要。当然,响应性和可预测性也是使用实时操作系统背后的一个关键目标,因此这两个主题可能会略有冲突。使用中断可能会损害操作系统的实时完整性。这个主题,以及这个冲突的解决方法,在之前的一篇文章中有介绍。在这里,我们将了解 Nucleus SE 采用的中断处理策略。
在所有情况下,中断都不受 Nucleus SE 控制——它们在发生时根据优先级和向量以通常的方式进行处理。它们的执行时间只是从可用于运行主线应用程序代码和调度程序的时间中“偷走”。显然,这意味着所有中断服务程序都应该简单、简短和快速。
本机和托管中断
Nucleus SE 确实提供了两种处理中断的方法:“本机”中断服务例程没什么特别的,与操作系统交互的机会有限(至少在选择优先级调度程序时它们会这样做);“托管”中断服务例程可以进行更广泛的 API 调用。
通过一些进入/退出宏,与 Nucleus SE 应用程序一起使用的中断服务例程可以被指定为本地或托管。
本机中断
Nucleus SE 原生中断是标准的中断服务例程——您可以将它们视为“非托管”。当 am 中断可能以高频率发生并且需要以非常低的开销进行服务时,通常会使用它们。该例程最有可能用 C 编码,因为许多现代嵌入式编译器支持通过中断 关键字编写中断服务例程。唯一保存的上下文信息是编译器认为必要的。这会导致本地中断例程可以执行的操作受到很大限制,我们很快就会看到。
要构建 Nucleus SE 原生中断服务例程,只需按照通常的方式编写 ISR,包括 开头调用宏NUSE_NISR_Enter()和 结尾调用NUSE_NISR_Exit()。这些宏在nuse_types.h中定义, 只需将全局变量NUSE_Task_State设置 为NUSE_NISR_CONTEXT。
托管中断
如果您在 ISR 可以执行的操作方面需要更大的灵活性,Nucleus SE 托管中断可能是解决方案。与本机中断的主要区别在于上下文保存。托管中断不仅仅允许编译器堆叠几个寄存器,而是在进入时保存完整的任务上下文(在其上下文块中)。然后从最后的上下文块加载当前任务的上下文。这容纳了当前任务可能被 ISR 代码的操作改变的可能性;当使用优先级调度程序时,这是完全可能的。Nucleus SE 上下文保存和恢复的完整描述包含在较早的文章中。
显然,完整的上下文保存比本地中断执行的几个寄存器的堆叠表示更高的开销。这是额外灵活性的代价,也是处理中断的方法有多种选择的原因。
托管中断是使用宏NUSE_MANAGED_ISR()构造的,该宏在nuse_types.h 中定义。这个宏构造了一个包含以下序列的函数:
任务上下文保存
将NUSE_Task_State设置 为NUSE_MISR_CONTEXT
调用用户提供的 ISR 代码函数
将NUSE_Task_State恢复 到之前的设置
任务上下文还原
该宏采用两个参数:中断名称,用作构造例程的函数名称;包含用户提供的 ISR 逻辑的函数的名称。
Nucleus SE 实时时钟 ISR(本文稍后将介绍)用作托管 ISR 的示例。
来自中断服务例程的 API 调用
可以从本机或托管 ISR 调用的 API 函数的范围取决于已选择的调度程序。从广义上讲,优先级调度程序的使用为作为 API 函数调用的结果调用调度程序提供了许多机会,这在本机 ISR 中将是一个问题。
来自具有优先级调度程序的本机 ISR 的 API 调用
具有优先级调度程序的本地 ISR 允许有限范围的 API 函数调用。这种限制是 Nucleus SE API 灵活性的结果——许多调用可能导致任务准备就绪,并且本机 ISR 无法调用调度程序(因为任务上下文未保存)。如果不启用任务阻塞,则具有更大的灵活性。
始终允许以下 API 调用:
NUSE_Task_Current()
NUSE_Task_Check_Stack()
NUSE_Task_Information()
NUSE_Task_Countÿ