Priority inheritance and priority ceiling will not span into ISR context will it?

I have a shared ring buffer. Its written in oncee normal task context, twice in two different ISRs. A mutex is grabbed, small memcpy work done, then released. It should never take more than 500us to do the work, the mutex has a 100ms block time for testing.

I ran into a priority inversion-like issue. ISR1 triggers, grabs the mutex. ISR2 triggers and attempts to grab the mutex, and it fails. This means ISR2 waited 100ms, and all of this makes sense because it seems that FreeRTOS couldn’t switch ISR contexts despite having inheritance/ceiling algorithms.

1. I would sort of expect ISR1 to be switched to, but these aren’t tasks and I suspect that FreeRTOS’s code here will not attempt to manually switch between ISR contexts like this - despite using the FreeRTOS object.

I “solved” this issue by making both ISR’s into the same context. However… I still use this shared resource outside of the ISRs. So I have the same issue right?

2. Just as FreeRTOS does not seem able to switch around ISR contexts, if I were to grab the mutex from a task, and switch to ISR, then try and grab the same mutex, FreeRTOS is unlikely to switch to normal context, finish the work, and switch me back into an ISR?

It seems to me the most simple solution is to defer the actual work at any of these places and instead send to a queue that is assembled and handled else where in order. The only issue there is that this a UART log and I’ll need to allocate the largest packet size (500 bytes) and then a queue of multiple times that size. I could also use critical sections in the task to prevent the ISR.

For the most part I’m just checking to see what FreeRTOS will do around ISRs.

Mutex timeout only applies to task level xSemaphoreTake and not xSemaphoreTakeFromISR. ISRs can’t block.
ISRs are out of the scope of the task scheduler and controlled by hardware.
Their priority is a given by HW configuration (e.g. NVIC on Cortex-M).
Some MCUs support nested interrupts means an invoked and running ISR can be interrupted by a higher prio interrupt invoking its corresponding ISR.
The preempted ISR is continued after the higher prio ISR has finished.
If you need to protect data shared between task(s) and ISRs you should use (short) ciritcal sections i.e. taskENTER/EXIT_CRITICAL(_FROM_ISR).

An ISR can not use mutexes…and Hartmut always is faster than me… :wink:

@RAc Well, this time … by pure chance :slight_smile:

Tell you what… Even though Hartmut’s answer was completely appropriate and better written, I tossed you a bone for brevity.

Thanks Hartmut!

Yea. This is mostly what I figured. And yes, while I don’t like to do it, in this case, EnterCritical is going to be a lower cost solution than trying to manage a mutex from task and two ISR contexts. I don’t really want a queue for size reasons. And messagebuffers iirc have the same multiple producer issue that my ring buffer has.

Simple solution. Thanks

As explained, ISRs can’t use Mutexes, because ISRs can’t block.

The Critical Section is best for a very short operation.

If the operation gets longer than you want for a normal Critical Section, you can make a special one that disables the scheduler, then disables just the ISRs that need to share that material. This avoids blocking other ISRS.

A Third option is to change the ISRs to defer their operation that needs the shared resource to a high priority task, then you can user the Mutex, as now all accesses are at task level.

The following page describes this approach in detail - Safer Interrupt Handling Demo for NXP LPCXpresso55S69 Development Board - FreeRTOS