xTaskNotifyWait not working

Hi,
I am calling this in one task every few seconds:

xTaskNotify(xAPP_PRINT_LABEL_Tasks, NOTIF__PRINT_LABEL__PRNT_SINGLE_LBL, eSetBits);

and have this in the task xAPP_PRINT_LABEL_Tasks

if (xTaskNotifyWait(0, 0, &uiCurrentNotificationValue, portMAX_DELAY) == pdTRUE)

the full listing on the receiving task is:

    if (xTaskNotifyWait(0, 0, &uiCurrentNotificationValue, portMAX_DELAY) == pdTRUE)
    {
        //notification received
        if (uiCurrentNotificationValue == NOTIF__PRINT_LABEL__PRNT_SINGLE_LBL)
        {
            app_print_labelData.state = APP_PRINT_LABEL_STATE_START_TO_PRINT;
            break;
        }
        else
        {
            SYS_DEBUG_PRINT(SYS_ERROR_ERROR, "Wrong Task NOTIF. woke up task in APP_PRINT_LABEL_STATE_STANDBY state: Line  %d in file %s\r\n" , __LINE__, __FILE__);
        }
    }

but it seems to be called only once.

Am I missing something? Perhaps in the bit clearing?
Do I need to clear the bits for it to be called again?

Thank you

I just tried running this code, and it executed as expected with ulPass incrementing every second and ulFail remaining at zero. Can you try it too?

volatile uint32_t ulPass = 0, ulFail = 0;

static void prvSendTask( void *pvParameters )
{
    for( ;; )
    {
        vTaskDelay( 1000 );
        xTaskNotify( xTaskToNotify, 0xa5, eSetBits);
    }
}
/*-----------------------------------------------------------*/

static void prvReceiveTask( void *pvParameters )
{
uint32_t ulReceivedValue;

	for( ;; )
	{
        ulReceivedValue = 0;
        if( xTaskNotifyWait( 0, 0, &ulReceivedValue, portMAX_DELAY ) == pdTRUE )
        {
            ulPass++;
            configASSERT( ulReceivedValue == 0xa5 );
        }
        else
        {
            ulFail++;
        }
	}
}

Hello,

I too have observed this issue with FreeRTOS version 10.2.1 (as it is the one that Gets included in my project when I use STM32CubeMX to generate code for STM32H7xx microcontroller).

What I found out is that when xTaskNotifyWait() API has two code lines listed below:

and

which are concerning.

My code’s has an ISR that calls xTaskNotifyFromISR(). The ISR would usually trigger sometime after taskEXIT_CRITICAL(); i.e.

is triggered but the next line has not executed.

In above case, the Notify does not work as expected.

I did not had an immediate fix, so I had to add an osDelsy(8) in the ISR just before making a call to xTaskNotifyFromISR().

I know this is not the correct / right solution, but no other fix is known to me.

Thanks,
Rajeev

Can you post the relevant code signaling the notification in ISR and waiting for/processing it in the task ? Do you use the notification exclusively for signaling this interrupt event to the post-processing task ? I think it might be just a misunderstanding or usage issue.

Hello Hartmut,

Is it possible for you to share an email where I can share the code parts related with this communication thread. I otherwise will have to modify the function before posting it here (as it uses proprietary product names).

I will need some time to share the modified code here.

Thanks,
Rajeev

I think it should be fine to post just the lines with giving the notification and taking it (maybe with adjusted variable names). Since notifications can be used for different scenarios or modes depending on the arguments used, it’s possible to get it wrong for the intended purpose. That’s why I’m asking for it :slight_smile:

Dear Hartmut,

Below code shared for reference:

osThreadId_t				ProprietaryPrTaskHandle;

void T_ProprietaryPr(void * argument)
{
	uint32_t u32IRQMasked;
	to_C__ProprietaryPrDataIn static * po_C__ProprietaryDataIn;

	toProprietaryPr * * ppoProprietary = (toProprietaryPr * *)argument;

	// This notify has already executed and does not have to do anything with the ISR / rvProprietaryTimerEvent Trigger
	ulTaskNotifyTake( pdTRUE, portMAX_DELAY);

	toProprietaryPr * poProprietary = (* ppoProprietary);

	TickType_t xLastWakeTime;

	/* Task Loop */
	while( TRUE )
	{
		// Initialise the xLastWakeTime variable with the current time.
		xLastWakeTime = xTaskGetTickCount();

		/* Get Input */
		while( TRUE )
		{
			dvDisableInterrupts;
			{
				if(0 < osMessageQueueGetCount(*(poProprietary->pQ__C__ProprietaryDataInHandle)))
				{
					if (osOK != osMessageQueueGet(*(poProprietary->pQ__C__ProprietaryDataInHandle), &po_C__ProprietaryDataIn, NULL, 0 /* Do not use osWaitForever as IRQ is disabled */))
					{
						// #ToDo: add error handling here
						// ++ Error Counts
						assert_failed((uint8_t *)__FILE__, __LINE__);
					}
				}
				else
				{
					po_C__ProprietaryDataIn = NULL;
				}
			}
			dvEnableInterrupts;
			if( po_C__ProprietaryDataIn == NULL )
			{
				__schedule_barrier();
#if 1
// This is the  TASK NOTIFY TAKE  WHICH CAUSES the concern...
				ulTaskNotifyTake( pdTRUE, portMAX_DELAY);
#else
				EventBits_t Event = osEventFlagsWait(H_ProprietaryPr_EvtGrp_Event, (1UL << dE_ProprietaryPrInput), (!osFlagsNoClear) | osFlagsWaitAll, osWaitForever);
				if(osOK != Event)
				{
					assert_failed((uint8_t *)__FILE__, __LINE__);
				}
				// #DRA: #ToDo: add error handling here based on value available with variable Event
#endif
				__NOP();
			}
			else
			{
				break;
			}
		}

		/* Pass Proprietary Input To Main Task */
		po_C__ProprietaryDataIn->poProprietary = poProprietary;
		VERIFY(rnAddItemToMainTaskQueue( ndProprietaryPrDataInItemType, rvReceivedProprietaryPrDataIn, po_C__ProprietaryDataIn ) == ndNoError);
		// Wait for the next cycle.
		vTaskDelayUntil( &xLastWakeTime, pdMS_TO_TICKS(20) );
	}
}


int main()
{

// Proprietary code here

	ProprietaryPrTaskHandle = osThreadNew(T_ProprietaryPr, (void*) &poProprietaryPr, &ProprietaryPrTask_attributes);
	if ( NULL == ProprietaryPrTaskHandle )
	{
		// Error handling here
		assert_failed((uint8_t *)__FILE__, __LINE__);
	}

// Proprietary code here

}



/**********************************************************************************************************************/
/********* Proprietary Timer Event ****************************************************************************************/
/**********************************************************************************************************************/
void 										rvProprietaryTimerEvent( void )
{
	uint32_t u32IRQMasked;
	to_C__ProprietaryPrDataOut static * po_C__ProprietaryPrDataOut;
	to_C__ProprietaryWireDataOut static * po_C__ProprietaryWireDataOut;
	to_C__ProprietaryTag * po_C__ProprietaryTagOut;
	const bool							Wire = 1;
	const bool							Pr = 0;

	if( !bProprietaryLibraryInialized )
	{
		return;
	}

	/******************************************************
	 * Proprietary Output
	 *****************************************************/
	uint32_t u32ItemCount = osMessageQueueGetCount(Q__C__ProprietaryTagsOutHandle); 
	if(0 < u32ItemCount)
	{
		dvDisableInterrupts;
		{
			if (osOK != osMessageQueueGet(Q__C__ProprietaryTagsOutHandle, &po_C__ProprietaryTagOut, NULL, 0 /* Do not use osWaitForever as IRQ is disabled */))
			{
				// #ToDo: add error handling here
				// ++ Error Counts
				assert_failed((uint8_t *)__FILE__, __LINE__);
			}
		}
// Proprietary code here
		rvFreeMemoryWithHandle( po_C__ProprietaryTagOut, H__C__ProprietaryTag );
	}
	

	{
		u32ItemCount = osMessageQueueGetCount(*(poProprietaryPr->pQ__C__ProprietaryDataOutHandle));
		if(0 < u32ItemCount)
		{
			// ST10 code calls MvRemoveFromTopOfQueue(po_C__ProprietaryPrDataOut, o_C__ProprietaryDataOutLink, &poProprietaryPr->Q__C__ProprietaryDataOut);
			if (osOK != osMessageQueueGet(*(poProprietaryPr->pQ__C__ProprietaryDataOutHandle), &po_C__ProprietaryPrDataOut, NULL, 0 /* Do not use osWaitForever as function called inside IRQ */))
			{
				// #ToDo: add error handling here
				// ++ Error Counts
				assert_failed((uint8_t *)__FILE__, __LINE__);
			}
// Proprietary code here
			MvFreeOwnedMemoryWithHandle( po_C__ProprietaryPrDataOut, poProprietaryPr->H__C__ProprietaryDataOut );
		}
		if( bSignalProprietaryPrInput )
		{
// #CONCERN: 20210210: #ToDo: Find a way to get rid of below osDelay()
			osDelay(8);
			bSignalProprietaryInput = false;
			__schedule_barrier();
			__memory_changed();
#if 1
			xTaskNotifyGive(ProprietaryPrTaskHandle);
#else
			osEventFlagsSet(H_ProprietaryPr_EvtGrp_Event, 1UL << poProprietaryPr->E_Input);
#endif
		}
	}

// Proprietary code here
	return;
}

Thanks,
Rajeev

Given that your real code uses xTaskNotifyGiveFromISR in the ISR I suspect that the issue is caused by the surrounding code e.g. dealing with bSignalProprietaryPrInput and bSignalProprietaryInput flags in the ISR and the po_C__ProprietaryDataIn pointer in the task.
In fact your notification signaling mechanism depends on some other (shared ?) flags and variables which could be easily handled slightly wrong causing a subtle race condition.
Then sometimes a delay here and there seem to solve a problem but just (unreliably) works around a symptom.
Sorry - your notification API calls are right and I’m convinced the FreeRTOS notification implementation is correct even if I don’t have a STM32H7 MCU, but others. I’d carefully review the usage of all those flags/variables and would try to get rid of as much as possible, because they make the code very complex and hard to get right.

Not sure how that is even possible, if the osDelay() is waiting for the tick interrupt and the tick interrupt has the lowest priority.

It is not immediately clear what the issue is in that, what is not working, and where does the interrupt occur - I’m assuming between the taskEXIT_CRITICAL() and taskENTER_CRITICAL() in the code you posted above. What makes you concerned about these lines? I’ve never seen a problem here and the code is extensively tested - however different devices have difference characteristics and different compilers do different things. If you can repeat the issue try adding a memory barrier between the exit and re-entry of the critical section. In GCC that can be done by adding: __asm volatile( “” ::: memory );

Hi,

If one checks the code associated with taskENTER_CRITICAL() one would observe a call made to portDISABLE_INTERRUPTS()

When referring to file tasks.C, it is understood that the Interrupt would have occurred after Line number 4768 got executed and before line number 4804 executed. The interrupt can however be serviced only after Line Number 4802 gets executed.

I even tried executing the code with help of:

  1. A Task
  2. Timer 1 of 1 ms
  3. Software Interrupt
    and observe the same result.

Regards,
Rajeev

Thanks for the additional information but it is not clear what the issue is. The critical section is exited then reentered specifically to allow interrupts to execute - so they are not held disabled too long. So the behaviour you describe so far is intended. Are you saying allowing interrupts to execute at that point is creating a race condition or other issue if the interrupt is sending or otherwise using the notification that is being waited for by that function call?

Is it possible for you to write a sample to demonstrate the problem? I have one STM32H743 and I can try to run and see.

Thanks.

Dear Gaurav,

I have been working on a different project these days. It would be hard for me to move to the (earlier) discussed project (whose code pieces I shared) and take out code pieces to come up with a small project. I am not sure how I will ensure that the while the Notify Take function parts are executing, the code execution triggers a Notify Give (which is necessary for triggering the earlier shared concern).

Regards,
Rajeev