Hi all
we have a situation on an embedded platform where a non-periodic, ‘rare’, one-shot situation has to be detected and dealt with rather quickly. I am still evaluating the exact requirements but we are talking about 0.5mSec to a few tens of msecs. Our timer tick is currently 1mSec.
It looks as though this might be a suitable place to use Task Notifications; I would like to check whether this is the case.
I am thinking that we ‘simply’ have an ISR which detects the condition, then signals an otherwise-blocked task using vTaskNotifyGiveFromISR()/ulTaskNotifyTake(). The high-priority task then deals with the situation.
I see that this mechanism is listed as being faster than using communication objects. Are there any metrics available for comparing between the two mechanisms? I’m thinking of the example timings given on the FreeRTOS website for context switching on an ARM, and what the equivalent might be using Task Notifications.
The Direct-To-Task are more efficient, largely because they, by definition, don’t have to worry about contention on the “read” side, because it is fixed to a single task.
They also are defined in ways that the sender is never blocked, so no need to have code to handle the sender getting blocked .
This saves SOME execution time, probably measured in order of microseconds per call.
The “Context Switch” needs to happen either way, what speeds up is the operations on either side that cause/process that switch.
Provided that the handling task has the highest priority, you should be able to respond to an interrupt in significantly less than your timer tick interval by using portYIELD_FROM_ISR to force a context switch before the next tick.
Inside the signaling interrupt, make sure to use the vTaskNotifyGiveFromISR function with the portYIELD_FROM_ISR as specified in the example on the vTaskNotifyGiveFromISR doc page. This should minimize latency and jitter from this notification.
As always, make sure your ISR has a priority level within bounds of your interrupt priority configuration so that it can be masked in critical sections. This means there will be some additional jitter associated with triggering the ISR, which should be bounded by the maximum length of all critical section in your application.
Hi Paul
I meant to mention portYIELD_FROM_ISR() in my original posting, but I was specifically interested in the possible advantages of task notifications. Presumably both portYIELD_FROM_ISR, and (eg) vTaskNotifyGiveFromISR(), force a context switch “in significantly less than your timer tick interval”?
No, only yield() enforces an immediate context switch, possibly before time slice expiration. As has been explained before by Richard D., the difference between using task notifications over, say, semaphores is that task notifications are optimized to reduce the CPU cycles used in setting up the context switch.
Operations like vTaskNotifyGiveFromISR() just moves a task from blocked to ready, meaning it is available next time the scheduler is run.
portYIELD_FROM_ISR() is what causes the scheduler to run. The tick ISR essential provides a point that it will be run if other ISRs forget to do it when needed.