FreeRTOS Support Archive

The FreeRTOS support forum can be used for active support both from Amazon Web Services
and the community. In return for using our software for
free, we request you play fair and do your bit to help others! Sign up
to receive notifications of new support topics then help where you can.

This is a read only archive of threads posted to the FreeRTOS support forum.
The archive is updated every week, so will not always contain the very latest posts.
Use these archive pages to search previous posts. Use the Live FreeRTOS Forum
link to reply to a post, or start a new support thread.

Strange behaviour after portEND_SWITCHING_ISR

Posted by Amon-Ra on March 12, 2012

Hello. I am using GCC STM32F103VE. I came across some odd behaviour of my firmware after calling portEND_SWITCHING_ISR - there are two tasks, one for processing data, low priority, and another for delayed interrupt handling, high priority.So, high priority task is waiting for counting semaphore, xSemaphoreTake(IRQSemph, portMAX_DELAY);

When entering ISR first time both tasks are blocked, awaiting different events. So, It works great, context is switched to High Priority task, which is unblocked by IRQSemph counting semaphore. But while processing this task, I suppose, this interrupt is being called once more.

Here is my question: due to mistype, I always passed TRUE to portEND_SWITCHING_ISR, causing context switch even when I shouldn't.

But this caused odd effect - high priority task never unblocked.This seems wrong to me - even after unexpected context switch - there are no more candidates for running, low priority task is blocked all the time, then why sheduler does not return to High Priority task, why is High Priority task still awaiting semaphore, when semaphore is already being given?I checked return value of xSemaphoreGiveFromISR, it retrurns success.When I fixed code and started passing *real* xHigherPriorityTaskWoken value instead of 1, it began to work.

RE: Strange behaviour after portEND_SWITCHING_ISR

In your code, you have forgotten to initialise the xHigherPriorityTaskWoken. It needs to be initialised to pdFALSE on interrupt entry.

The behaviour you observed is the expected behaviour. If giving the semaphore has the potential to unblock a semaphore then the xHigherPriorityTaskWoken is checked, and if it is found to be false, the task is unblocked and xHigherPriorityTaskWoken is set to pdTRUE. If xHigherPriorityTaskWoken was already pdTRUE, then it is assumed that a task has already been unblocked, and no action is taken.

This prevents multiple tasks being unblocked by a single semaphore give, as only one task will process the semaphore, leaving the other unblocked tasks with nothing to do but return to the Blocked state.

Regards.

RE: Strange behaviour after portEND_SWITCHING_ISR

Posted by Amon-Ra on March 12, 2012

Thanks alot, now it is clear!

RE: Strange behaviour after portEND_SWITCHING_ISR

One question, if an interrupt does two operations that unblock tasks (say different queues), and happens to unblock the lower priority (but still above the current running priority) first, then when does the higher one wake?

Or, do you need a separate flag for each queue and test if any of them got set?

RE: Strange behaviour after portEND_SWITCHING_ISR

If you want a task to unblock more than one task from one queue then reset xHigherPriorityTaskWoken to pdFALSE in between each semaphore give. In any case - the task that is unblocked first will always be the highest priority task that was blocked on the semaphore as tasks are unblocked in priority order.

If you have a single interrupt operating on multiple queues and/or semaphores, and you wish one task to be unblocked from each queue/semaphore that is processes, then use a separate flag for each, and OR the flag values when they are passed into portEND_SWITCHING_ISR()/portYIELD_FROM_ISR().

RE: Strange behaviour after portEND_SWITCHING_ISR

Hang on! Looking at the code I think my reply above is not correct. The higher priority task woken flag being pdTRUE should not effect whether any further tasks are unblocked or not. If more than one task is unblocked then any unblocked tasks that find the reason they were unblocked no longer exists (the semaphore or queue has been processed by a different task) will simply put themselves back to sleep again for the remains of the block task.