Efficient Use of FreeRTOS Semaphore & Queus with High Rate ISR's on Pic32MX

jasonfromca wrote on Thursday, February 27, 2014:

Dilemma perhaps someone can help me to solve …

In thinking ahead, I’m trying to use FreeRTOS efficiently with a high rate ISR running:

I have a ISR that is triggering every 80 microseconds on a Pic32MX processor and which I expect to run continuously.

Solution #1:

One solution is to use deferred interrupt processing:

  • From the ISR that triggers every 80 microseconds, call xSemaphoreGiveFromISR()
  • From a task siting on a xSemaphoreTake(), then task will wake up, and handle the processing.

My concern is in regards to other tasks: With this solution (using a semaphore give from an ISR) the FreeRTOS kernel and other tasks are guaranteed to context switch from what they are tasked to do and yield to this higher priority task to do deferred work at a 80 microsecond rate.

Deferred interrupt processing is not bad per say, but I’m concerned about it at such a high rate and the affect it will have on the other tasks. Deferring the work to a FreeRTOS task, I would say there is a lot of context switching that will the be continuously occurring.

If someone said, “Oh no, FreeRTOS semaphore’s inure a 200 microsecond penalty between xSemaphoreGiveFromISR() and xSemaphoreTake()” then it’s clear that this wouldn’t work. Of course of course, timing depends on processor port and type.

** Solution #2: **

Alternatively, do all the processing in the interrupt itself. When enough processing is performed, then notify a task the work is done.

  • One problem with that, is that I’m then spending a lot of time in the ISR doing processing. Because of this, I may miss other interrupts.
  • With deferred interrupt processing and Using a task, I can prioritize how things run!

Feedback …

Any input, thoughts, or ideas on which direction to go would be great? Others may have a better understanding of the performance impact that can occur between both solutions.

znatok wrote on Thursday, February 27, 2014:

Just combine two options.
For instance you can buffer data in ISR handler and once you reach some threshold wake up task.

aturowski wrote on Thursday, February 27, 2014:

That is a very good advice. The threshold level should be set according to data processing latency acceptable in that project. Another thing to consider is to use DMA to buffer the data provided this interrupt can be fully serviced by DMA.

richard_damon wrote on Thursday, February 27, 2014:

Not knowing how much work is needed to be done on each data sample, and what the latency requirements are, it is a little hard to give specific advice.

A couple of general comments.

ISR’s are allowed to do some work, they don’t need to just set a semaphore and return (and sometimes they NEED go do more to clear the interrupt). They should NOT do a “lot” of processing.

Every 80 microseconds is FAST. To signal a task at that rate will incur a lot of overhead, as you will be causing 2 context switches in that period (to the signaled task, then back out of it). While the context switch time should be short enough that this is possible, you are going to be losing a lot of processor power just in context switching. You better not be needing to do a lot per sample, or you are going to run short on processing power. If you are not doing a lot of processing per sample, it might make sense to do that processing in the ISR to avoid the context switches (one rule of thumb is that if the processing is quicker than the two context switches, it belongs in the ISR).

If you have other interrupts that need low latency, then you have a tough problem, not impossible, but tough, and you will need to do careful design, in things like interrupt priority, to meet the requirements.

If you don’t need to immediately process each sample, buffering (and maybe even using DMA to gather), will be a big win.