xTaskNotifyGive issue - basic usage

nndpkz wrote on Thursday, June 07, 2018:

Hi guys,

I am trying to implement example from 9.3 chapter from Mastering The FreeRTOS Real-Time Kernel book. I am using ZYNQ-7000. Now, since I didn’t check how to simulate software interrupts on Zynq, I just decided to simply call a function from which I will call xTaskNotifyGive. This is just an illustration example. This is what I have:

int main( void )
{
	time_t xTimeNow;

	xil_printf( "Hello world!\n\r" );

	time( &xTimeNow );
	prvSRand( (uint32_t)xTimeNow );

	vPortInstallFreeRTOSVectorTable( );

	Xil_DCacheEnable( );

	xTaskCreate( vPlaybackTask, "Playback", 1024, NULL, configMAX_PRIORITIES - 4, NULL );
	xTaskCreate( vPeriodicTask, "Periodic", 1024, NULL, configMAX_PRIORITIES - 6, NULL );

	/* Start the RTOS scheduler. */
	xil_printf( "vTaskStartScheduler\n" );
	vTaskStartScheduler( );

	return 0;
}

static
void vExampleInterruptServiceRoutine( void )
{
	xTaskNotifyGive( vPlaybackTask );
}

static
void vPeriodicTask( void *pvParameters )
{
	while( 1 )
	{
		vTaskDelay( xInterruptFrequency );
		xil_printf("Periodic task - About to generate / simulate an interrupt!\n");
		vExampleInterruptServiceRoutine();
		xil_printf("Periodic task - Interrupt generated!\n");
	}
}

static
void vPlaybackTask( void *pvParameters )
{
	const TickType_t xMaxExpectedBlockTime = xInterruptFrequency + pdMS_TO_TICKS( 10 );
	uint32_t ulEventsToProcess = 0;

	while( 1 )
	{
		ulEventsToProcess  = ulTaskNotifyTake( pdTRUE, xMaxExpectedBlockTime  );
		if( ulEventsToProcess != 0 )
		{
			while( ulEventsToProcess > 0 )
			{
				xil_printf( "Playback task -> processing -> run DMA.\n" );
				ulEventsToProcess--;
			}
		}
	}
}

however, ulTaskNotifyTake never returns a value different from 0. I have also checked that xTaskNotifyGive() is actually called.

Maybe I am missing something obvious here?

Best regards,
Nenad

P.S. The same example from Chapter 6.4 which uses binary semaphore instead of Task Notify is working as expected.

rtel wrote on Thursday, June 07, 2018:

I think this recent thread:
https://sourceforge.net/p/freertos/discussion/382005/thread/543fb83e/
showed xil_printf() may not be thread safe and may cause problems (which
is why we normally serialse logging by only calling printf() form a
single task) so in this case it might be that xil_printf() is taking
longer to execute than you are allowing with the allowable margin you
have set using pdMS_TO_TICKS( 10 ). Try increasing to pdMS_TO_TICKS(
1000 ) as a sanity check.

nndpkz wrote on Thursday, June 07, 2018:

Hi Richard,

yes, I remember the xil_printf() issue, however, since this example worked with binary semaphore, I was thinking that something else is problem.
I forgot to mention that I already tried to set to portMAX_DELAY, but ulTaskNotifyTake() never returned. I will examine xil_printf() again.

Thanks.

rtel wrote on Thursday, June 07, 2018:

Ah - I see the problem.

The parameter to xTaskNotifyGive() is supposed to be the handle of the
task the notification is sent to. The parameter you are passing is a
pointer to the function that implements the task, not the task’s handle.

The last parameter in your call to:

xTaskCreate( vPlaybackTask, “Playback”, 1024, NULL, configMAX_PRIORITIES

  • 4, NULL );

is null so you never save the task’s handle. Do something like this:

// File scope
static TaskHandle_t PlaybackHandle;

// Update call to xTaskCreate to save the handle.
xTaskCreate( vPlaybackTask, “Playback”, 1024, NULL, configMAX_PRIORITIES

  • 4, &PlaybackHandle );

// Update call to xTaskNotifyGive() to use the handle.
xTaskNotifyGive( PlaybackHandle );

nndpkz wrote on Friday, June 08, 2018:

Yes, that was a problem. I knew I was missing something obvious. But, I also thought some assert would fail if something like this happens.

All in all, thank you very much for your help!