Description
[Also see the blog post "Decrease RAM Footprint and Accelerate Execution with FreeRTOS Notifications"]
Each RTOS task has an array of task notifications. Each task notification
has a notification state that can be either 'pending' or 'not pending',
and a 32-bit notification value. The constant
configTASK_NOTIFICATION_ARRAY_ENTRIES sets the number of indexes in
the task notification array. Prior to FreeRTOS V10.4.0 tasks only had a single task notification,
not an array of notifications.
A direct to task notification is an event sent
directly to a task, rather than indirectly to a task via an intermediary object
such as a queue, event group or semaphore. Sending a direct to task notification to a task sets the state of
the target task notification to 'pending'. Just as a task can block on an intermediary object
such as a semaphore to wait for that semaphore to be available, a task can block
on a task notification to wait for that notification's state to become pending.
Sending a direct to task notification to a task can also optionally
update the value of the target notification in one of the
following ways:
-
Overwrite the value regardless of whether the receiving task
has read the value being overwritten or not.
-
Overwrite the value, but only if the receiving task has read
the value being overwritten.
-
Set one or more bits in the value.
-
Increment (add one to) the value.
Calling xTaskNotifyWait()/xTaskNotifyWaitIndexed()
to read a notification value clears that notification's state to 'not pending'.
Notification states can also be explicitly set to 'not pending' by calling
xTaskNotifyStateClear()/xTaskNotifyStateClearIndexed().
Note: Each notification within the array operates independently - a task
can only block on one notification within the array at a time and will not be
unblocked by a notification sent to any other array index.
RTOS task notification functionality is enabled by default, and can be excluded
from a build (saving 8 bytes per array index per task) by setting
configUSE_TASK_NOTIFICATIONS to 0 in FreeRTOSConfig.h.
IMPORTANT NOTE: FreeRTOS Stream and Message Buffers
use the task
notification at array index 0. If you want to maintain the state of a
task notification across a call to a Stream or Message Buffer API function then
use a task notification at an array index greater than 0.
Performance Benefits and Usage Restrictions
The flexibility of task notifications allows them to be used where otherwise it would
have been necessary to create a separate queue,
binary semaphore,
counting semaphore
or event group.
Unblocking an RTOS task with a direct notification is 45% faster
* and
uses less RAM than unblocking a task using an intermediary object such as
a binary semaphore.
As would
be expected, these performance benefits require some use case limitations:
-
RTOS task notifications can only be used when there is only one task that
can be the recipient of the event. This condition is however met in the
majority of real world use cases, such as an interrupt unblocking a task
that will process the data received by the interrupt.
-
Only in the case where an RTOS task notification is used in place of
a queue: While a receiving task can wait for a notification in the
Blocked state (so not consuming any CPU time), a sending task cannot
wait in the Blocked state for a send to complete if the send cannot
complete immediately.
Use Cases
Notifications are sent using the xTaskNotifyIndexed()
and xTaskNotifyGiveIndexed() API functions (and their
interrupt safe equivalents),
and remain pending until the receiving RTOS task calls either of the
xTaskNotifyWaitIndexed() or
ulTaskNotifyTakeIndexed() API functions.
Each of these API functions has an equivalent that does not have the "Indexed"
prefix. The non "Indexed" versions always operate on the task notification at
array index 0. For example xTaskNotifyGive( TargetTask ) is equivalent
to xTaskNotifyGiveIndexed( TargetTask, 0 ) - both increment the task notification
at index 0 of the task referenced by the task handled TargetTask.
*
Measured using the binary semaphore implementation from
FreeRTOS V8.1.2, compiled with GCC at -O2 optimisation, and without
configASSERT() defined. A 35% improvement can still be obtained using the improved
binary semaphore implementation found in FreeRTOS V8.2.0 and higher.
Copyright (C) Amazon Web Services, Inc. or its affiliates. All rights reserved.