An uncertain blocked time after giving a semaphore form a Timer Intterupt

Hi all,
Recently, I use Segger RTT SystemViewe to monitoring my project. I found there is something wrong after giving a semaphore to a task from a Timer ISR. As the following code shows:

SemaphoreHandle_t sensor_TimerSemaphore = NULL;

static void TIMER_0_task1_cb(const struct timer_task *const timer_task)
{
	BaseType_t xHigherPriorityTaskWoken;
	
	if(sensor_TimerSemaphore!=NULL){
		xSemaphoreGiveFromISR(sensor_TimerSemaphore,&xHigherPriorityTaskWoken);
	}
	portYIELD_FROM_ISR(xReturn);
}


void Sen_T(void *p)
{
	(void)p;
	while (1) {
		if( xSemaphoreTake(sensor_TimerSemaphore,portMAX_DELAY)) // 256 Hz
		{
			// Sampling
		}
	}
}

The following figure shows the time sequence of my tasks in FreeRTOS:


One can see that an Timer Interrupt(ISR123) gave a semaphore to Sen_T. After that the Sen_T is blocked serveral microseconds.
The blocked time is uncertain.

Feel free to share your idea with me!

It looks like your call to portYIELD_FROM_ISR() isn’t working. The one you posted doesn’t seem right – I don’t see xReturn defined anywhere. I think you meant this:

portYIELD_FROM_ISR(xHigherPriorityTaskWoken);

Also, importantly, you must initialize xHigherPriorityTaskWoken to pdFALSE.

1 Like

Yes, you are right!!
Finally It works and I revised snippets as the following :

static BaseType_t xHigherPriorityTaskWoken = pdFALSE;  //initialization
BaseType_t Sensor_Task_GiveSemaphore_FromISR(){
	
	if(sensor_TimerSemaphore!=NULL){
		xSemaphoreGiveFromISR(sensor_TimerSemaphore,&xHigherPriorityTaskWoken);
	}
	return xHigherPriorityTaskWoken;
}
static void TIMER_0_task1_cb(const struct timer_task *const timer_task)
{
	SEGGER_SYSVIEW_RecordEnterISR();
	semphr = get_sensor_Semaphore();
	if (semphr !=NULL)
	{
		xtaskwoken = Sensor_Task_GiveSemaphore_FromISR();
	
	}else{
		xtaskwoken = pdFALSE;
	}
	SEGGER_SYSVIEW_RecordExitISRToScheduler();
	portYIELD_FROM_ISR(xtaskwoken);
}

Thank you very much!

Best if you clean up xHigherPriorityTaskWoken just a little bit more.

Function xSemaphoreGiveFromISR() cannot set xHigherPriorityTaskWoken to pdFALSE. It either sets xHigherPriorityTaskWoken to pdTRUE or leaves it unchanged. All of the FromISR() functions that can unblock a task follow the same pattern. Because of this pattern, your code should initialize xHigherPriorityTaskWoken to pdFALSE at the beginning of the ISR code that can wake a task.

For reference, see xSemaphoreGiveFromISR().

In your specific case here, this change may not make a functional difference because every time the ISR runs you actually do wake a higher-priority task. But it’s good to get used to following the pattern so you’ll always induce a yield operation when needed, and only when needed, regardless of your task priorities and timing.

1 Like

I would NOT make the woken flag a non-local variable, as it should NOT be shared among interrupts. Each interrupt should initialize its flag at start, so if an ISR gets interrupted after setting the flag, but before returning, you might miss that wakeup request.

2 Likes

Thank you for your information!
I should follow the example code xSemaphoreGiveFromISR().