Question about sending notifications from own task

I have a number of projects that I’ve done with FreeRTOS over the past couple of years. I just about every project, there is some task that needs to send a notification to itself. It’s typically a task that parses data from the outside world (usually a UART) and then the task sends a notification to itself to perform some action based on the parsing of the data.

So the task is an infinite loop calling

xTaskNotifyWait(0x0, 0xFFFFFFFF, &notifications, portMAX_DELAY);

at the beginning of the loop. After this call, all the notifications received are processed. In my current project, the processing of certain notification cause another notification to be sent to the task (from the same task).

This has worked fine for all my projects until my last one as the task stops at xTaskNotifyWait() and doesn’t return - as if the notification was never received.

I know the notification gets set because I can step through the source code of xTaskGenericNotify() and see

pxTCB->ulNotifiedValue[ uxIndexToNotify ]

gets set along with

/* Mark this task as waiting for a notification. */
pxTCB->ucNotifyState[ uxIndexToNotify ] = taskNOTIFICATION_RECEIVED;

xTaskNotify is called with the eSetBits option. There are no ISRs involved in either of the notifications here.

Aftert setting the notification, I keep stepping through the code to the call to xTaskNotifyWait at the top of the loop (which calls xTaskGenericNotifyWait() in tasks.c):

    BaseType_t xTaskGenericNotifyWait( UBaseType_t uxIndexToWait,
                                       uint32_t ulBitsToClearOnEntry,
                                       uint32_t ulBitsToClearOnExit,
                                       uint32_t * pulNotificationValue,
                                       TickType_t xTicksToWait )
    {
        BaseType_t xReturn;

        configASSERT( uxIndexToWait < configTASK_NOTIFICATION_ARRAY_ENTRIES );

        taskENTER_CRITICAL();
        {
            /* Only block if a notification is not already pending. */
            if( pxCurrentTCB->ucNotifyState[ uxIndexToWait ] != taskNOTIFICATION_RECEIVED )
            {
                /* Clear bits in the task's notification value as bits may get

What I see is that pxCurrentTCB->ucNotifyState[uxIndexToWait] is no longer set to taskNOTIFICATION_RECEIVED. It is set to taskWAITING_NOTIFICATION so the notification doesn’t get processed. It’s not clear to me why this gets changed.

I can work around it with what I consider a hack of adding a do-while loop after xTaskNotifyWait() like this:

do
{
	/* Process all notifications here */
}
while ((notifications = ulTaskNotifyTake(true, 0)) != 0);

This way, any notifications that are sent during processing of notifications are immediately read and continue to be processed. This tells me that the notification was definately sent and is waiting, I just don’t think/hope this should be required.

The FreeRTOS version that works is “V10.4.3 LTS Patch 2” as defined in tasks.h. It’s running on an NXP LPC54102. The directory from FreeRTOS is “amazon-freertos”.

The one that doesn’t work is running on an NXP K22FN512VMP12. The FreeRTOS directory is “freertos” and the version is “V10.2.0”.

I have done diffs of the FreeRTOS code, specifically tasks.c and tasks.h and didn’t see anything obvious. The version, 10.2.0, doesn’t have an array of notification values. The 10.4.3, does.

Both of these are provided by NXP and are integrated with their SDK.

I have functions for malloc failed hook and the stack overflow. I have upped the stack size to see if it was a stack problem. Same issue.

Any ideas?

In further testing, the workaround does not work. In fact, other tasks are having problems receiving notifications too.

I have a UART task that writes to a stream buffer from and ISR and then sends a notification to task and it’s missing notifications too. It’s using xStreamBufferSendFromISR() and xTaskNotifyFromISR(). Not sure why.

Do you have any tasks that might wait for stream buffers (tx or rx) and also use the above code? Stream buffers use task notifications in their internal implementation. And until this recent commit, stream buffers always used notification index 0. You would end up with the symptoms you describe. (However, the symptoms would be the same in both v10.4.3 LTS Patch 2 and v10.2.0, so a little mystery there.)

I’m not sure how to answer your question. I think the answer is yes, as I have a non-zero blocking time for the read in the task processing loop. The value TASK_RECEIVE_TICKS_TO_WAIT is 4 ticks.

The way I’m reading from the serial port is

Receive part of the UART interrupt code:

if (flags & kUART_RxDataRegFullFlag)
{
	uint8_t rx = UART_ReadByte(UART_PERIPHERAL);
	xStreamBufferSendFromISR(task_processing_data.receive_stream_handle, &rx, sizeof(rx), &woken);

	task_processing_notify_from_isr(NOTIFICATION_UART_RECEIVE, &woken);
}

UART_ClearStatusFlags(UART_PERIPHERAL, flags);

  /* Switch required? */
portYIELD_FROM_ISR(woken);

Then in the task when I get the notification:

if (notifications & NOTIFICATION_UART_RECEIVE)
{
	uint8_t rx;

	/* If we have a bytes to receive, pull them from the stream and send them to the packet processor */
	while (xStreamBufferReceive(task_processing_data.receive_stream_handle, &rx, sizeof(rx), TASK_RECEIVE_TICKS_TO_WAIT))
	{
		task_packet_processor_process(rx);
	}
}

The stream buffer is declared as

/* Receive buffer */
task_processing_data.receive_stream_handle =  xStreamBufferCreate(TASK_RECEIVE_STREAM_SIZE, 1);
configASSERT(task_processing_data.receive_stream_handle != NULL);

I set the TASK_RECEIVE_TICKS_TO_WAIT to zero and it does the same thing.

I have found that if I don’t send the NOTIFICATION_UART_RECEIVE notification, of course the UART in that task doesn’t work but everything else seems to work. So it is definately something with the notifications causing the issue.

What is the preferred way to do this? A separate task for the UART processing?

Thanks for taking the time to respond.

@jefftenney means that streambuffer receive might eat task notification events because internally stream buffer signaling is ‘hooked’ into the task notification mechanism (more precisely the 1st entry with index 0). So using (indexed) task notifications (with index 0) and stream buffers might be problematic.

2 Likes

Thanks, I’ve confirmed that is exactly what is happening.

It is described here as well-

The stream buffer implementation uses direct to task notifications. Therefore, calling a stream buffer API function that places the calling task into the Blocked state can change the calling task's notification state and value.

You can consider using a different task notification index -

Thanks. Unfortunately, I read the documentaiton on the xStreamBufferReceive() and it doesn’t mention notification at all.

I ended up using a queue and combining things (notification and receive events) and it works.

Thank you for sharing your solution!

Yes, the StreamBuffer documentation hides this detail well, but is now mentioned in the documentation for vStreamBufferSetStreamBufferNotificationIndex() and uxStreamBufferGetStreamBufferNotificationIndex() (which I think are somewhat new parts of the API).

One point to notice, is that it uses just plain notification, and if you have your notification set or increment the notification value, then its use doen’t interfear, as the word won’t get unset, and thus the get will still see the value.