Chapter 9: bugs, clarifications, and tips
Chapter 9: Intertask Communication (pg 209)
● Clarification, page 211:
o The queue-size is 2. However, I don't think it will ever hold more than one element, due to the algorithm and task priorities.
● Bug in the code (mainQueueCompositePassByValue.c), page 211-212:
o It would be better if this line was in the body of the if-statement:
■ vTaskDelay(nextCmd.msDelayTime/portTICK_PERIOD_MS);
o If xQueueReceive() fails then nextCmd.msDelayTime does not get set on this iteration of the loop.
● Clarification, page 214
o The queue-size is 8. However, the queue-size only needs to be 1 here. It would work the same, in operating the LEDs.
● Additional info, page 219
o Info about uxMessagesWaiting:
o It is in the struct QueueDefinition, which is defined in FreeRTOS's queue.c:
■ C:/projects/packtBookRTOS/Middleware/Third_Party/FreeRTOS/Source/queue.c
o Some additional variables in the struct:
● Bug in the book, page 220
o There are some incorrect statements under "A long queue was used for commands:".
o The queued commands and latency are attributed to both: "low-priority task receiving" and "long queue length".
o However, for this program, the queued commands and latency are not due to the receiving task having lower priority than the sending task. If the sending task is given higher priority than the receiving task, the commands will queue in the same way.
● Tip, page 221:
o It can be beneficial to write this code one's self, before looking at the provided program.
● Additional info, page 221
o Info on how data is copied to and from a queue:
o xQueueSend and xQueusReceive just use memcpy(), internally.
o The copy is in FreeRTOS's queue.c, in the functions: prvCopyDataFromQueue() and prvCopyDataToQueue()
● Bug in the book and code (mainTaskNotifications.c), page 227
o Problem:
■ There's a bug in the example program mainTaskNotifications.c, in its use of ulTaskNotifyTake().
■ ulTaskNotifyTake is not the correct notify function to use here, although the code does work.
■ ulTaskNotifyTake is intended for use as an alternative to a semaphore, but this code is not implementing a semaphore. Also, in using ulTaskNotifyTake here, it has to be made to do something that isn't relevant to the example program.
■ Using ulTaskNotifyTake is not as straight-forward and it adds a bit of unnecessary complexity.
o Solution:
■ The intended API to use here is xTaskNotifyWait():
● From the FreeRTOS manual:
xTaskNotifyWait( uint32_t ulBitsToClearOnEntry,
uint32_t ulBitsToClearOnExit,
uint32_t *pulNotificationValue,
TickType_t xTicksToWait );
● How it would be used in mainTaskNotifications.c
xTaskNotifyWait(0, 0, ¬ificationvalue, portMAX_DELAY);
o Analysis:
■ Why ulTaskNotifyTake is not the correct notify API to use here:
■ The FreeRTOS Reference Manual (page 123), describes how ulTaskNotifyTake is just intended for use in implementing a fast semaphore:
● “ulTaskNotifyTake() is intended for use when a task notification is used as a faster and lighter weight alternative to a binary semaphore or a counting semaphore. FreeRTOS semaphores are taken using the xSemaphoreTake() API function, ulTaskNotifyTake() is the equivalent that uses a task notification value instead of a separate semaphore object...”
● “When a task is using its notification value as a binary or counting semaphore other tasks and interrupts should send notifications to it using either the xTaskNotifyGive() macro, or the xTaskNotify() function with the function’s eAction parameter set to eIncrement (the two are equivalent).”
■ Using ulTaskNotifyTake adds some unnecessary complexity.
● ulTaskNotifyTake returns the calling-task's notification-value, and it alters the notification-value when exiting. The parameter xClearCountOnExit specifies how the notification-value is altered on exit:
ulTaskNotifyTake( BaseType_t xClearCountOnExit, TickType_t xTicksToWait );
● In mainTaskNotifications.c, the call is:
uint32_t notificationvalue = ulTaskNotifyTake( pdTRUE, portMAX_DELAY );
● In using ulTaskNotifyTake here, the task's notification-value must be set to zero on exit. It doesn't need to be zero for the example-program's calculations. It needs to be zero to make ulTaskNotifyTake operate correctly, since it's designed to perform semaphore-like processing.
● For example, if the task's notification-value is greater than zero when ulTaskNotifyTake exits, the next call to ulTaskNotifyTake can run whether or not there is a pending notification.
● If xTaskNotifyWait is used instead, the task's notification-value on exit isn't a concern.
● Bug in FreeRTOS, in its documentation for ulTaskNotifyTake:
o The book presents an example-program mainTaskNotifications.c, on page 227 As just described, above, there is a bug in the program's use of ulTaskNotifyTake.
o The example-program has an additional apparent bug in its use of ulTaskNotifyTake. However, the bug is actually in the FreeRTOS documentation for ulTaskNotifyTake.
o In the program, one of the calls to xTaskNotify sets the task-notification-value to 0:
■ xTaskNotify( recvTaskHandle,0, eSetValueWithOverwrite);
o According to the API documentation, ulTaskNotifyTake will not return if the task's notification-value is 0. This is a documentation error, and I've reported it on FreeRTOS's Kernel forum.
o When the example-program is run, ulTaskNotifyTake does return when the notification-value is 0.