I try to understand why the user has to call the taskYIELD_FROM_ISR()
method and why it isn't automatically called by the RTOS within the xStreamBufferSendFromISR
method.
My question refers to the FreeRTOS_Manual p. 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);
}
My understanding of the scenario
Preconditions
vAnInterruptServiceRoutine
Within the ISR
xStreamBufferSendFromISR()
Case A If the ISR method is returning now, the scheduler will not be called and Task2 is running until the time slice period is over and then the scheduler switches to the high prior Task1.
Case B
If the ISR method calls taskYIELD_FROM_ISR(xHigherPriorityTaskWoken);
at last, the scheduler will be called and after returning the ISR, Task1 will be running instead of Task2.
Questions
taskYIELD_FROM_ISR()
method not called automatically by the RTOS when calling xStreamBufferSendFromISR()
?taskYIELD_FROM_ISR
, the scheduler gives context to Task1
on the next scheduled tick. This can be verified with Segger SystemView. uartPrintTask
blocks on a semaphore and then prints data from a buffer. Notice the long delay between when uartPrintTask is "ready" and when it is "running". This delay is variable - although it never lasts longer than 1mS (the tick rate in the example)
Now, the same example with taskYIELD_FROM_ISR
added at the end of the ISR. uartPrintTask
is consistently executed after the ISR
2. FreeRTOS can't automatically call anything from an ISR. You've got full control over all interrupts. taskYIELD_FROM_ISR
should be placed at the end of your ISR implementation (but you may have placed the call to xStreamBufferSendFromISR
anywhere in the ISR).
One of the beautiful things about FreeRTOS (in my opinion) is that it doesn't hijack anything and gives tons of flexibility. You can have interrupts that execute completely "underneath" the RTOS - FreeRTOS doesn't need to know anything about them. Not automatically calling taskYIELD_FROM_ISR
is another example of this flexibility (in my opinion).
From the 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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With