Tasks not running in priority order

Hello all,

I have come across a weird issue where it looks like FreeRTOS is letting lower priority tasks to run over a higher priority one. Let me try to explain the specifics of this scenario.

There are 3 tasks at 3 different priorities (low, medium, and high) and 2 ISRs (same priority) in play here. Here is the order of events.

  1. ISR A runs and signals tasks medium and low to run.
  2. ISR B runs and signals high task to run.
  3. Task Medium executes to completion
  4. Task low executes to completion.
  5. Task high executes

I would expect that task high runs first since it has the highest priority. configUSE_PREEMPTION is enabled. I looked for a priority inversion case where task high is locked on a resource that low or medium is using but did not find that scenario. I do not have tracealyzer working at the moment (hoping to get that going soon). Any ideas on what is happening here is appreciated. Thanks!

FreeRTOS version 10.5.1
Running on stm32mp257

First, with preemption enabled, you still need the ISR to trigger the rescheduling to make it happen right away, normally with some code that tests the “was woken” flag from the signalling call.

Second, you are remember that “low priority” for tasks is smaller numbers, (0 is the idle task priority) and higher values are higher priority?

If anything, when the medium task completes and reschedules, the system should take the High Priority task over the low, unless something has corrupted memory.

Just to rule out an application bug, you can reduce the task definitions to minimum like toggling an LED or incrementing a variable and see if you still observe the same issue.

Here are couple of other things to check:

  • Is tick interrupt firing and tick count incrementing?
  • Did you use portYIELD_FROM_ISRin your ISR?

In the ISR it calls portYIELD_FROM_ISR() so it should trigger a context switch right away. Yes, I am aware that a higher priority task is a greater number and double and triple checked priority values of these tasks. Something weird is happening, maybe corrupted memory? Is there a way to tell if that is happening?

Have you defined configASSERT? Can you try the latest main code?

If you suspect memory corruption, enable configCHECK_FOR_STACK_OVERFLOW according to the listed methods here, and implement thevApplicationStackOverflowHook() function. This hook lets you catch and handle stack overflows, such as logging an error or halting the system.

Besides configUSE_PREEMPTION, other configurations or hooks—such as the idle hook (vApplicationIdleHook()), tick hook (vApplicationTickHook()), or any custom code that alters the scheduler’s behavior—might interfere with normal operation. If any of these hooks are custom-defined in your application, can you try disabling them temporarily and running the system again to check for changes?

After some more investigation I found that out that the configTIMER_TASK_PRIORITY was set to 2. Increasing the priority to be the highest in the system got rid of this issue. It looks like that when setting an event from an ISR, it goes through the Timer Service task that is set to priority configTIMER_TASK_PRIORITY. Having it set so low caused it not to wake up to tell the higher priority thread to run when any task above a priority of 2 was running. Not sure why it defaults so low considering how important this Timer service task is.

One thing to point out is that you said you signaled “tasks”, which would normally imply using the direct-to-task notifications, which happen directly. Possibly it might mean signalling a semaphore that a task is waiting on, which also would happen directly.

It seems you were signaling an EventGroup, which is a much more heavy operation, because it might trigger multiple tasks to become ready, which is why it is deferred to the task level using the timer/service task.

I don’t know where you got your “default” value for that task, but yes, it is normally set to be the highest priority task, or at least close to that level.