xTaskNotifyFromISR prevent delay of xMessageBufferReceive

xMessageBufferReceive() should never return because nothing is ever sent to onlyForTestBuf(), yet BeepMini() seems to execute - indicating that xMessageBufferReceive() did infact return.

MessageBufferHandle_t onlyForTestBuf; //this is global var

//at task
onlyForTestBuf = xMessageBufferCreate(24);
for(;;)
{
xMessageBufferReceive(onlyForTestBuf, ( void * )myMessage, sizeof(myMessage), portMAX_DELAY );  //portMAX_DELAY
BeepMini();
}

void TIM3_IRQHandler(void)
{
xTaskNotifyFromISR(MotorsActionsHandle, PWMIR_FAULT, eSetValueWithOverwrite, NULL);
TIM3->SR = 0;
while(TIM3->SR &= TIM_SR_CC1IF);
//HAL_TIM_IRQHandler(&htim3);
}

I don’t use onlyForTestBuf at any place! No more can add into onlyForTestBuf! But I hear Beep because of my function BeepMini(). But if I delete xTaskNotifyFromISR from my interrupt no more beep. This is because stream_buffer.c:

size_t xStreamBufferReceive( StreamBufferHandle_t xStreamBuffer, ...
/ *Wait for data to be available.* /
....
( void ) xTaskNotifyWait( ( uint32_t ) 0, UINT32_MAX, NULL, xTicksToWait );

In my interrupt I send via xTaskNotifyFromISR too! Is it a bug or feature? For example task is wating MessageBuffer, but in some moment there is a notify. So task stops wating MessageBuffer and process notify. But ulBitsToClearOnExit of xTaskNotifyWait not using at all! This is a bug I think. Old bit will set after every xTaskNotify.

while(!xMessageBufferReceive(xMotorActionMessageBuffer, ( void * )myMessage, sizeof(myMessage), portMAX_DELAY)){
	ulNotifiedValue = 0;
	if(xTaskNotifyWait(0x00, ULONG_MAX, &ulNotifiedValue, 100)){
       //never be here
	}
	if(ulNotifiedValue & vMAPleaseReinit){
		BeepMini();  //vMAPleaseReinit bit never cleared
	}
};

This is because tasks.c:

			if( pxCurrentTCB->ucNotifyState != taskNOTIFICATION_RECEIVED )
			{
				/* A notification was not received. */
				xReturn = pdFALSE;  //this is problem, taskNOTIFICATION_RECEIVED  was received by xMessageBufferReceive
			}
			else
			{
				/* A notification was already pending or a notification was
				received while the task was waiting. */
				pxCurrentTCB->ulNotifiedValue &= ~ulBitsToClearOnExit;
				xReturn = pdTRUE;
			}

FreeRTOS 10

Stream and message buffers use task notifications internally, which is probably why you see this behaviour. See https://www.freertos.org/RTOS-message-buffer-example.html - we have some experimental code that uses an array of task notifications, instead of today’s single notification, which will make this behaviour avoidable.

@rtel Great that you’re already working on increasing the notification fan-out.
I think it’s a good improvement making notifications even more versatile. Although up to now I got all my projects done by using notifications as fundamental signaling mechanism without exceeding the provided 32 bits.
However, I wonder if the current side-effect to stream/message buffers or vice versa isn’t a pretty cool feature. I think it could be easily used as a simple but fast and cheap WaitForMultipleObjects like mechanism known from Windows platforms.
At least we’d get both, notifications of binary events and/or signaled data or messages.
I’m usually not a friend of feature bloat but maybe it’s worth to add a combined API.
What do you think ?

Please update documentation about feature. https://www.freertos.org/xMessageBufferReceive.html For example
xTicksToWait The maximum amount of time the task should remain in the Blocked state to wait for a message, FUNCTION RETURN IMIADETLY IF GETS NOTIFICATION VIA xTaskNotify OR xTaskNotifyFromISR.

Probably a good call that it should be noted in each API - currently it is only noted on the pages that describe stream/message buffers https://www.freertos.org/RTOS-stream-buffer-example.html

The head revision in github now has an array of direct to task notifications per task. The task.h header file contains the API documentation updates. This will be in the next official release.

1 Like

Meantime, if you still need a workaround, you can use the current release and share the notification value. It appears your design uses the notification value to identify specific events, which is a very common design. And the stream buffer code from FreeRTOS doesn’t modify the notification value.

To share the notification value, check it after any call to the stream/message API. For example, instead of this:

…you might do something like this:

while(!xMessageBufferReceive(xMotorActionMessageBuffer, ( void * )myMessage, sizeof(myMessage), portMAX_DELAY)){
	ulNotifiedValue = ulTaskNotifyValueClear(NULL, ULONG_MAX);
	if(ulNotifiedValue & vMAPleaseReinit){
		BeepMini();
	}
};

One related thing - it looks like maybe you were experimenting with some of the stream buffer code here:

Specifically the UINT32_MAX here doesn’t match FreeRTOS code. You should put that back to 0 if you want to share the notification value.

1 Like