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);
}
我对场景的理解
先决条件
- 有两个任务
- 任务 1(高优先级)和任务 2(低优先级)
- Task1 处于阻塞状态,等待 streamBuffer 输入
- Task2 处于 运行-状态,被
vAnInterruptServiceRoutine
中断
在 ISR 内
- ISR 方法调用
xStreamBufferSendFromISR()
- 这个调用意味着,Task1 的 Blocked-State 变为 Ready-State
案例A
如果 ISR 方法现在正在返回,则不会调用调度程序并且 Task2 运行 直到时间片周期结束,然后调度程序切换到高优先级 Task1。
案例 B
如果 ISR 方法最后调用 taskYIELD_FROM_ISR(xHigherPriorityTaskWoken);
,调度程序将被调用,返回 ISR 后,Task1 将是 运行 而不是 Task2。
问题
- 是不是Task2会一直执行到一个时间片周期结束还是有另一个任务切换的触发点?
- 为什么调用
xStreamBufferSendFromISR()
时RTOS没有自动调用taskYIELD_FROM_ISR()
方法?
- 1) 我也这么认为
- 2) 我不太确定这一点。我认为这样做是为了保持快速中断并保持低上下文切换开销。因此,您可以根据需要的响应时间选择是否触发上下文切换。
- 是的,在不调用
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
是这种灵活性的另一个例子(在我看来)。
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.
我试图理解为什么用户必须调用 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);
}
我对场景的理解
先决条件
- 有两个任务
- 任务 1(高优先级)和任务 2(低优先级)
- Task1 处于阻塞状态,等待 streamBuffer 输入
- Task2 处于 运行-状态,被
vAnInterruptServiceRoutine
中断
在 ISR 内
- ISR 方法调用
xStreamBufferSendFromISR()
- 这个调用意味着,Task1 的 Blocked-State 变为 Ready-State
案例A 如果 ISR 方法现在正在返回,则不会调用调度程序并且 Task2 运行 直到时间片周期结束,然后调度程序切换到高优先级 Task1。
案例 B
如果 ISR 方法最后调用 taskYIELD_FROM_ISR(xHigherPriorityTaskWoken);
,调度程序将被调用,返回 ISR 后,Task1 将是 运行 而不是 Task2。
问题
- 是不是Task2会一直执行到一个时间片周期结束还是有另一个任务切换的触发点?
- 为什么调用
xStreamBufferSendFromISR()
时RTOS没有自动调用taskYIELD_FROM_ISR()
方法?
- 1) 我也这么认为
- 2) 我不太确定这一点。我认为这样做是为了保持快速中断并保持低上下文切换开销。因此,您可以根据需要的响应时间选择是否触发上下文切换。
- 是的,在不调用
taskYIELD_FROM_ISR
的情况下,调度程序会在下一个计划的滴答中将上下文提供给Task1
。这可以使用 Segger SystemView 进行验证。uartPrintTask
在信号量上阻塞,然后从缓冲区打印数据。请注意 uartPrintTask 为 "ready" 和 "running" 之间的长时间延迟。这个延迟是可变的——虽然它永远不会持续超过 1 毫秒(示例中的滴答率)
现在,在 ISR 末尾添加 taskYIELD_FROM_ISR
的相同示例。 uartPrintTask
在 ISR 之后始终执行
taskYIELD_FROM_ISR
应该放在你的 ISR 实现的末尾(但你可能已经在 ISR 的任何地方调用了 xStreamBufferSendFromISR
)。
FreeRTOS 的优点之一(在我看来)是它不会劫持任何东西并提供大量的灵活性。您可以让中断完全执行 "underneath" RTOS - FreeRTOS 不需要知道任何关于它们的信息。不自动调用 taskYIELD_FROM_ISR
是这种灵活性的另一个例子(在我看来)。
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.