Don't get binary semaphore to work

Hi all,

I have a battery powered product with a Task Alarm.
It is listening to notifications with a value, the value means how many times the alarm melody should be played.

I had the issue that my microcontroller goToSleep() function puts itself to sleep while the melody was not fully played.

My idea was to work with a binary semaphore take/give so my goToSleep() function could check if the melody is done playing.

As soon as I put xSemaphoreTake() into the code, no alarm will ever played.
The AlarmMelodyBusySemaphore != NULL is True.
Its the next line xSemaphoreTake that somehow is not True

static void tsk_alarm(void *pvParameters)
{
	uint32_t ulNotifiedValue;
	
	
	while (1) {
		if(xTaskNotifyWait( 0, 0, &ulNotifiedValue, portMAX_DELAY) == pdTRUE)
		{
			if (xTimerIsTimerActive( LcdTimerHndl1Sec ) == pdFALSE)
			{
				if (AlarmMelodyBusySemaphore != NULL)
				{
				
					if(xSemaphoreTake( AlarmMelodyBusySemaphore, ( TickType_t ) 10 ))
					{
						
					
						for (int i=0; i<ulNotifiedValue; i++)
						{
						
							alarm_middle();													
							vTaskDelay(pdMS_TO_TICKS(1500));
						}
						
						if( xSemaphoreGive( AlarmMelodyBusySemaphore ) != pdTRUE )
						{
							printf("Semaphore issue\n");
						}
					
					}
					
				}
			}
			
			#if ( PRINT_WATERMARKS == 1 )
				printf("ALARM:%u\n", uxTaskGetStackHighWaterMark( NULL ));
			#endif
		}
				
		
	}
}

you call xSemaphoreTake with a timeout but don’t distinguish in your code between success and timeout.

1 Like

Did you make sure the semaphore was given originally? If I remember right, depending on how you create the semaphore will determine if it is created taken or given.

Good point, that would help with debugging.
I have a lot of nested IF’s, not sure how to get Freertos code more readable.

I have to do a Give on top of my alarm task (above the while(1))
My semaphore is created in my main loop and Taken by default. :upside_down_face:

So why are Binary semaphore already taken on creation?

I found the following documentation:

Note that binary semaphores created using the vSemaphoreCreateBinary() macro are created in a state such that the first call to ‘take’ the semaphore would pass, whereas binary semaphores created using xSemaphoreCreateBinary() are created in a state such that the the semaphore must first be ‘given’ before it can be ‘taken’.

But most examples on freertos don’t show this ‘give before take’ order

[UPDATE] The xSemaphoreGive and xSemaphoreTake documentation examples are using mutex and not binary semaphores. A bit confusing.

You use Give (in task A) triggering a Take (in task B) as a typical data-ready signal, which is the actual main use of semaphores, and that wants the semaphore to start in the Taken state. When using it as an alternative to a Mutex, which would be preferred for that purpose, you would want it to start in the Given state.

I would say that in my code, almost all of the uses of semaphore are in cases where I want the semaphore to start in the taken state.

(Note, xSemaphoreGive and xSemaphoreTake are used for non-recursive mutexs.)

It is not only about debugging. If you unconditionally release a mutex/semaphore in the “claim success” return branch (meaning also when it has not been taken successfully), your results may be unpredictable.

Also, I second Richard’s observations of semaphores vs. muteces. Unfortunately, the term “semaphore” has found its way into multithreading folklore as the “one concept fits all” solution to sync problems, supported among other things by FreeRTOS’ naming of the claim/release functions (as well as the historic tidbit that when Dijkstra introduced semaphores into computing many moons ago, there simply wasn 't anything else). As Richard points out correctly, in many many cases where semaphores are being used in practice, muteces would be the superior solution.

1 Like

Actually, I see it as “Semaphore” is used as a very generic term relating to a general form of synchronization primitive. Note, FreeRTOS doesn’t have a way to create a “plain” Semaphore, but you create one with a specific nature of Binary, Counting, Mutex, or RecursiveMutex. The Give/Take functions work for all the types except RecursiveMutex, which needs its own routines.

So, when @sprucify created his Semaphore, it seems they created a “Binary” Semaphore, which has two different create routines, a much older one supported for legacy code that creates the semaphore “given”, and the current one that creates it “taken”. I wouldn’t be surprized if the older one predates the addition of Mutexes to FreeRTOS, in which case “given” might well be the most wanted state. Now that we have Mutexes, and they should be used in most cases needing a Mutex, the “taken” state of the “current” version is much more likely.