FreeRTOS 上下文切换

FreeRTOS context switching

我正在为我的一个项目使用 FreeRTOS,我正在阅读文档,但有些东西我无法理解。 我知道上下文切换是在触发滴答中断时发生的,因此调度程序会执行其工作并取消阻塞正在等待事件的任务并选择处于就绪状态的更高优先级任务。但是当一个任务在 tick 中断之前阻塞时会发生什么?该文档似乎暗示上下文切换会立即发生(例如,两个具有不同优先级的任务各自调用 vTaskDelay() 以释放 CPU 时间片)。它是如何发生的?我进行了搜索,但找不到我的问题的任何答案。

EDIT 在我的 FreeRTOS (SAMD21 Cortex-M0+) 端口中使用了 portYIELD() 宏,它只是请求一个 SVCall 异常,所以这是用于执行上下文切换(除调度程序 运行 节拍中断外)?

有关于 taskYIELD 的文档。此函数可用于请求上下文切换,因此无需等待滴答。上下文切换是特权操作,因此通常由软件中断来完成。在您的情况下,通过 PendSV 和 SVCall。

如果所有任务都被阻止(例如被 vTaskDelay),那么 FreeRTOS 是 运行ning Idle TaskvTaskDelay 在内部使用 portYIELD 请求上下文切换,因为无法继续当前任务。

您还需要一些关于 Preemptive multitasking 的知识才能理解该模式下的 FreeRTOS。

编辑 2016-01-29:

  • 调用延迟函数导致内部调用taskYIELD/portYIELD。因此,您当前的任务被阻止并且 FreeRTOS 重新安排到最高优先级的任务,可以 运行(也不会被阻止)或空闲任务,如果没有任务能够 运行。
  • 打电话,例如xQueueReceive可以有两种可能。队列中有一些元素,所以它被弹出。队列中没有元素,因此任务切换到 blocked state 并为您调用 YIELD,因此 FreeRTOS 重新安排到另一个任务。
  • 打电话,例如xQueueSend可以有两种可能。队列中没有空间,因此任务被阻塞,直到有 space。至少有一个空闲元素,所以你可以推入队列。

从队列接收元素或向队列发送元素可以唤醒其他更高优先级的任务,即正在做相反但当前被阻塞。 FreeRTOS 会立即重新安排。

这也可以通过中断处理程序完成。您可以有处理程序任务,它正在等待某个队列。从中断中,您将一些元素放入队列。中断结束后,FreeRTOS 重新调度到等待该队列的任务。在该任务上具有足够高的优先级只是先决条件。这有好处,你在中断中没有做太多 - 只是一些清理并将项目发送到队列 - 这是短期操作。 处理中断也可以通过xTimerPendFunctionCallFromISR来完成,这是另一种处理中断的有趣方式。

另请阅读 FreeRTOS fundamentals。关于它的章节很多,读起来很有趣。

每当 OS 调用(例如 TaskDelay 或将项目发送到队列或释放资源)发生时,如果另一个任何其他任务准备好 运行,OS 就会工作,如果更高优先级的任务准备好 运行,它将 pre-empt 当前任务。基本上任何准备好 运行 的最高优先级任务都会 运行。仅当两个或多个具有相同和最高优先级的任务准备好 运行.

时才会发生时间片

是一个中断 运行s。在 cortex-m 上,PENDSV 中断执行上下文切换。

您是在问当当前 运行ning 任务阻塞时您必须做什么才能切换到另一个任务?或者您是在询问如何执行上下文切换的机制?真的不清楚。

如果您问的是当一个任务阻塞时如何切换到另一个任务,那么答案是什么都没有,这就是 RTOS 为您做的事情的基础。例如,如果您调用 vTaskDelay(),或指定阻塞时间的 xQueueReceive(),则任务进入阻塞状态。当任务被阻塞时,它不能 运行,因此 RTOS 中的调度算法选择下一个任务 运行 并启动该任务 运行ning.

聚会有点晚了。 我相信在 xQueueReceive 中调用了隐式 taskYield。

在 ISR 中,对 xQueueSend 的调用不会调用 taskYield。必须显式调用它(& 在函数末尾)。这让 ISR 可以控制是否进行上下文切换。 因此,如果任务在 xQueueReceive 上被阻塞,因此在空闲任务中说,并且调用 ISR,则执行 xQueueSendFromISR。如果没有调用 taskYield,它将 return 到空闲任务,直到下一个计时器滴答。即使 xQueueReceive 可以解锁。 如果在 ISR 中调用 taskYield,调度程序将被调用并且 xQueueReceive 将解除阻塞并在 ISR 之后立即 运行。