Can I force a context switch to a predetermined task?

mr-m-from-k wrote on Thursday, February 21, 2019:

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.

Thanks for any help

Martin

rtel wrote on Thursday, February 21, 2019:

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.

mr-m-from-k wrote on Friday, February 22, 2019:

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?)

kind regards
Martin

rtel wrote on Friday, February 22, 2019:

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

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?)

You can come to the AWS booth or my talk:
https://www.embedded-world.de/en/events/vortrag/the-future-of-freertos-/737984

mr-m-from-k wrote on Friday, February 22, 2019:

Hello Richard,

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.

Martin