I included FreeRTOS into a little AVR software project (using ATMega328P and preemptive scheduling), I work on and so far it works pretty well. But while implementing some more features (using binary semaphores to sync with an interrupt) I noticed a strange behaviour, which can cause the whole system to lock.(It might be a general issue with that port.)
Imagine the following scenario:
Task A waits for an interrupt event using binary semaphores, it blocks when calling "xSemaphoreTake()" - the context is saved (including a set I-flag because we are not in an ISR or deleted the flag manually), then a switchover to task B is performed and the corresponding context restored. Code execution continues…
Now an Interrupt occurs (the ISR Task A waits for) - the I-flag is deleted (by the CPU) causing all interrupts to be disabled (including the scheduler) and the ISR code is called. Now the context (of task B) is saved (including the deleted I-flag), some operations are performed and "xSemaphoreGiveFromISR()" is called, waking task A. Because it has a higher priority than B, a context switch (to task A) is performed. The context is restored with the I-Flag set (ok so far, because this flag would have been set by the "reti" instruction anyway).
Task A executes and then blocks again waiting for the next Interrupt - the context is saved, the switch to task B is done.
Now the context of task B is restored but with the I-flag being DELETED (because it was saved from within an ISR). Since the return is done using "ret", the flag is not set and the interrupts - including the scheduler - remain disabled!
Task B executes, but has no idea that interrupts got disabled. Unless interrupts are (re)enabled manually, task B executes forever waiting for a scheduler to interrupt it, but this will NEVER happen.
IMHO this could also happen if tasks are switched by the scheduler (in a timer-ISR) AND if one task blocks waiting for an event (maybe occuring in another task or an ISR). Here the contexts - except for the blocked one - will always be saved with the I-flag cleared. If a task is resumed after another task entered the blocked state from outside an ISR, the I-flag will always remain deleted and the scheduler does not execute anymore.
Do I miss an important fact, or is this really a problem in the AVR port (and maybe others)?
I already implemented a solution that works for me, but I really want to be sure if this might be a general issue (which was kind of hard to track down).