我参加了一个关于FreeRtos和Cortex M的讲座,讲师建议,如果不从ISR使用ISR安全版本的API,则可能导致Cortex M处理器中的使用错误异常。发生这种情况是因为这可能涉及从中断上下文(中断处理程序)到任务上下文(线程处理程序) 我的问题是为什么这个任务切换会被认为是非法的,这种切换会产生什么影响?
在 Cortex-M(某些)上,当前上下文将存储在中断之前(中断进入)使用的堆栈上,因此如果您在任务中并且它被中断,则一些当前上下文将存储在任务堆栈上(通过 PSP)。中断本身始终在 MSP 上运行。如果中断没有返回到它中断的任务,那么中断的任务将有一个混乱的堆栈(因为它在退出时恢复存储的上下文)以及试图为切换到的任务恢复不正确的上下文。
在上下文切换(发生在中断中)上,一些上下文再次自动存储在任务堆栈上,但操作系统也将其余上下文存储在任务堆栈上。当它执行切换并退出中断时,操作系统会恢复它为任务自己存储的上下文,然后通过退出中断自动恢复上下文的其余部分。这是有效的,因为它可以确保堆栈保持正确的格式。查看 Cortex-M4 通用用户指南中的中断进入/退出。
并非所有处理器都像这样工作。
这个答案是通用的,不是FreeRTOS或Cortex-M特定的 - 它适用于任何平台上的任何典型RTOS:
无法从中断服务例程调用导致调度程序运行的 RTOS API 调用。 例如,如果您给出信号量,通常调度程序会运行以切换到该信号灯上挂起的任何任务;这在 ISR 中是不合适的,在 ISR 中,调度程序必须在中断上下文退出时运行一次;显然,您不希望在中断完成之前进行上下文切换,并且可能会有其他 API 调用或更高优先级中断的抢占,从而导致不同的任务变得可运行;当上下文切换发生时,仅进行一次该评估可保持确定性行为。
特定于 ISR 的函数版本不会立即调用调度程序;相反,它们设置一个标志来指示调度程序必须在退出中断上下文时运行。
通常,进行RTOS API调用的ISR必须具有序言和尾声;特定的进入/退出中断调用或宏。 这个序言,增加了一个计数器,在尾声中递减;如果计数器为零并且设置了计划标志,则计划程序将运行。 计数器用于防止调度程序在退出嵌套中断时运行。 这可确保调度程序在退出时仅运行一次,从最低优先级的挂起中断。
是否或为什么会发生"uasge 错误"是 FreeRTOS 特定的实现细节,主要是学术性的。 RTOS 同样可以在 ISR 中捕获非 ISR 安全调用的使用,并运行更具体的错误处理程序,如果它不费心这样做,那么由此产生的行为可能会触发使用错误;这似乎是一个有点粗糙的依赖机制;使用错误是一个非常广泛的陷阱,可能由于多种原因而发生:
使用错误:检测未定义指令的执行,未对齐 用于加载/存储多个的内存访问。启用后,除以零 并且还会检测到其他未对齐的内存访问。
一些 RTOS 没有特定于 ISR 的功能,相反,导致调度的 API 调用在内部检测 ISR 上下文,并在该上下文中表现不同 - 这对程序员来说更简单、更安全,但在每个此类调用上测试上下文的开销很小。 在内部处理 ISR 安全的 API 还意味着调用可能自己进行操作系统 API 调用的函数更简单,因为这些函数本身不需要特定于 ISR。