Hello,
I want to use an isr to switch to a certain task. In my application this has to be fast and therefore the named task is always at highest priority.
Now my question is if there is a way to save the time normally needed for scheduling which task is at highest priority but instead switch in the named task rightaway.
I measured the time between a notification give and the corresponding notification take by setting and clearing a portbit and this is far more than the somewhere mentioned ca 80 cycles, I would guess it is more than 200 cycles.
Tasks are always referenced by their handle. The fastest way to switch
from an interrupt to a task is to have the task at the highest priority
and then send it a direct to task notification from the interrupt -
making sure to call taskYIELD_FROM_ISR/taskEND_SWITCHING_ISR at the end
of the ISR.
Hello Richard,
thank you for your answer.
I tried some things and would like to get your comment on the results.
I am working with a STM32H743 Nucleo board, it is clocked at 400 MHz. I put task.o, list.o and port.o in ITCM-RAM to make it as fast as possible. IDE is Atollic TrueStudio 9, optimize is set to optimize for speed.
I have two tasks, simply named Task1 and Task2
For my first experiment I give Task1 priority 1 and Task2 priority 2.
In Task1 I have these lines:
SetPortBit (port_Testpins, pin_Task2);
xTaskNotifyGive (Handle_Task2);
vTaskDelay( pdMS_TO_TICKS( 13 ) );
and in Task 2:
ulTaskNotifyTake (pdFALSE, pdMS_TO_TICKS( 10000 ));
ClearPortBit (port_Testpins, pin_Task2);
This results in a pulse at pin_Task2 of 940 nsec length
In my second experiment I use an isr that is triggered on an UART RX event. When this happens it runs these lines:
SetPortBit (port_Testpins, pin_Task1);
xTaskNotifyFromISR (Handle_Task1, 0, eIncrement, &xHigherPriorityTaskWoken);
portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
And in Task1 (it now has priority 3 ) I have
NotifyResult = ulTaskNotifyTake (pdFALSE, pdMS_TO_TICKS( 10000 ));
ClearPortBit (port_Testpins, pin_Task1);
This results in a pulse at pin_Task1 of 960 nsec length.
This setup also has a queue and a timer, I don’t know if that affects this time in any way.
Both times are practically equal, I would have somehow expected a shorter time for the return from isr (without really knowing internals of FreeRTOS).
Then this time at a 400 MHz clock makes my assume that there is much more done than just a task switch. Back to my initial question I would like to ask if this can’t be cut short as it will always be Task1 having the highest priority (in my case, I am aware that this is not a general solution).
If I add more tasks to my project, will I have to face a longer time?
I attach my FreeRTOSConfig.h
Thank you very much for your help
(I plan to be at embedded world on wednesday. Is there a chance to meet you there?)
Now first I wonder why it is longer from inside the isr, I would have
expected a shorter time (without really knowing internals of FreeRTOS).
I think it is expected that the time would be longer as you have to
exist one ISR (the one in which the notification is given) and enter
another (the PendSV ISR that performs the context switch). The
cortex-m’s tail chaining will make that slightly faster, but only by a
hand full of nano seconds.
Back to my initial question I would
like to ask if this can’t be cut short as it will always be Task1 having
the highest priority (in my case, I am aware that this is not a general
solution).
The actions performed would be the same - in fact if you were to use a
task name it could be slightly longer as you would first need to get the
handle from the name. You can step through what happens in the debugger
using a direct to task notification you already have the handle of the
task being unblocked so the task is unblocked directly with no
intermediate object. At least at the time of writing the ‘notify give
from ISR function’ is here to see the code that executes: https://sourceforge.net/p/freertos/code/HEAD/tree/trunk/FreeRTOS/Source/tasks.c#l4956
If I add more tasks to my project, will I have to face a longer time?
No. For optimal performance ensure
configUSE_PORT_OPTIMISED_TASK_SELECTION is set to 1 so the task
selection is performed using a CLZ instruction rather than a C
algorithm, ensure configCHECK_FOR_STACK_OVERFLOW is set to 0 as stack
overflow checking (although extremely useful) is the slowest thing done
in the context switch, make sure there are no trace macros, etc.
I attach my FreeRTOSConfig.h
Thank you very much for your help
(I plan to be at embedded world on wednesday. Is there a chance to meet
you there?)
first I apologize for misleading you, I already corrected my post. The isr time was wrong I overlooked something that was also executed before portYIELD. So both times are equal.
Then thank you again for your help. I will check your hints in my code.
And I think I will take the time to go into FreeRTOS details.
Have a nice trip to Nuremberg, maybe will meet there.