FreeRTOS:为什么要在 isrHandler 中调用 taskYIELD_FROM_ISR() 方法

FreeRTOS: Why to call taskYIELD_FROM_ISR() method within the isrHandler

我试图理解为什么用户必须调用 taskYIELD_FROM_ISR() 方法以及为什么它不会在 xStreamBufferSendFromISR 方法中被 RTOS 自动调用。

我的问题是指 FreeRTOS_Manual 页。 369.

/* A stream buffer that has already been created. */
StreamBufferHandle_t xStreamBuffer;

void vAnInterruptServiceRoutine( void ) {
  size_t xBytesSent;
  char *pcStringToSend = "String to send";
  BaseType_t xHigherPriorityTaskWoken = pdFALSE;

  /* Attempt to send the string to the stream buffer. */
  xBytesSent = xStreamBufferSendFromISR(xStreamBuffer,(void *) pcStringToSend,strlen( pcStringToSend),&xHigherPriorityTaskWoken);

  if(xBytesSent != strlen(pcStringToSend)){
    /* There was not enough free space in the stream buffer for the entire string to be written, ut xBytesSent bytes were written. */
  }

  /* 
    If xHigherPriorityTaskWoken was set to pdTRUE inside xStreamBufferSendFromISR() then a    
    task that has a priority above the priority of the currently executing task was unblocked 
    and a context switch should be performed to ensure the ISR returns to the unblocked task. 
    In most FreeRTOS ports this is done by simply passing xHigherPriorityTaskWoken into 
    taskYIELD_FROM_ISR(), which will test the variables value, and perform the context switch 
    if necessary. Check the documentation for the port in use for port specific instructions. 
  */

  taskYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}

我对场景的理解

先决条件

在 ISR 内

案例A 如果 ISR 方法现在正在返回,则不会调用调度程序并且 Task2 运行 直到时间片周期结束,然后调度程序切换到高优先级 Task1。

案例 B 如果 ISR 方法最后调用 taskYIELD_FROM_ISR(xHigherPriorityTaskWoken);,调度程序将被调用,返回 ISR 后,Task1 将是 运行 而不是 Task2。

问题

  1. 是不是Task2会一直执行到一个时间片周期结束还是有另一个任务切换的触发点?
  2. 为什么调用xStreamBufferSendFromISR()时RTOS没有自动调用taskYIELD_FROM_ISR()方法?
  • 1) 我也这么认为
  • 2) 我不太确定这一点。我认为这样做是为了保持快速中断并保持低上下文切换开销。因此,您可以根据需要的响应时间选择是否触发上下文切换。
  1. 是的,在不调用 taskYIELD_FROM_ISR 的情况下,调度程序会在下一个计划的滴答中将上下文提供给 Task1。这可以使用 Segger SystemView 进行验证。 uartPrintTask 在信号量上阻塞,然后从缓冲区打印数据。请注意 uartPrintTask 为 "ready" 和 "running" 之间的长时间延迟。这个延迟是可变的——虽然它永远不会持续超过 1 毫秒(示例中的滴答率)

现在,在 ISR 末尾添加 taskYIELD_FROM_ISR 的相同示例。 uartPrintTask 在 ISR 之后始终执行 2. FreeRTOS 不能自动 从 ISR 调用任何东西。您可以完全控制所有中断。 taskYIELD_FROM_ISR 应该放在你的 ISR 实现的末尾(但你可能已经在 ISR 的任何地方调用了 xStreamBufferSendFromISR)。

FreeRTOS 的优点之一(在我看来)是它不会劫持任何东西并提供大量的灵活性。您可以让中断完全执行 "underneath" RTOS - FreeRTOS 不需要知道任何关于它们的信息。不自动调用 taskYIELD_FROM_ISR 是这种灵活性的另一个例子(在我看来)。

来自SafeRTOS manual:

Calling either xQueueSendFromISR() or xQueueReceiveFromISR() within an interrupt service routine can potentially cause a task to leave the Blocked state which then necessitates a context switch if the unblocked task has a higher priority than the interrupted task. A context switch is performed transparently (within the API functions) when either xQueueSend() or xQueueReceive() cause a task of higher priority than the calling task to exit the Blocked state. This behavior is desirable from a task, but not from an interrupt service routine. Therefore, xQueueSendFromISR() and xQueueReceiveFromISR(), rather than performing the context switch themselves, instead return a value indicative of whether a context switch is required. If a context switch is required, the application writer can use taskYIELD_FROM_ISR() to perform the context switch at the most appropriate time, normally at the end of the interrupt handler. See “xQueueSendFromISR()” on page 69 and “xQueueReceiveFromISR()” on page 71 which describe the xQueueSendFromISR() and xQueueReceiveFromISR() functions respectively for more information.