xSemaphoreGiveFromISR not returning pdTRUE

Hi,

I created one binary semaphore and tried to use xSemaphoreGiveFromISR() api from one ISR. But it is not working (return value is not pdTRUE) and got hang once the ISR is called.

I also tried xSemaphoreGive() api from one task, but it was working fine.

I checked the online document and found that xSemaphoreGiveFromISR() can return “errQUEUE_FULL”.

Please see the code and help me to diagnose the problem.

int main() {
	initializeSystem();
	LogDebugInt("----- Hello World -----\r\n", 5);
	LogDebugInt("CPU Clock %dMHz\r\n", bsp_getCPUClock()/1000000);
	LogDebugInt("Peripheral(Master) Clock %dMHz\r\n", bsp_getMasterClock()/1000000);

	s_handle2 = xSemaphoreCreateBinary(); //xSemaphoreCreateCounting(10, 0); //
	m_handle = xSemaphoreCreateMutex();

	if(s_handle2 != NULL && m_handle != NULL){

		xTaskCreate(task1, "TASK-1", configMINIMAL_STACK_SIZE, NULL, 3, &t_handle1);
		xTaskCreate(task_handler, "HANDLER", configMINIMAL_STACK_SIZE, NULL, 2, NULL);

		vTaskStartScheduler();

	} else {
		LogDebugInt("Failed to create Semaphore and Mutex.\r\n", 0);
	}
}
void task1(void *param){
 for(;;){
	 if(xSemaphoreTake(m_handle, portMAX_DELAY)){
		 LogDebugInt("(T1): Printing by Task-1 -> %c\r\n", input);
		 xSemaphoreGive(m_handle);
	 }
	 vTaskDelay(pdMS_TO_TICKS(1000));

	 //xSemaphoreGive(s_handle2);
 }
}
void task_handler(void *param){

 uint32_t i, j;
 for(;;){
	 if(xSemaphoreTake(s_handle2, portMAX_DELAY)){
		 pio_toggleLED(UPPER_LED);
		 //To Waste some CPU cycles
		 //for(i=0; i<10000; i++)
			 for(j=0; j<1000; j++);
	 }
 }
}
char input=' ';
BaseType_t xHigherPriorityTaskWoken;
void UART0_Handler(){
	input = SAM7S_UART_GetChar(DBG_PORT);

	if(xSemaphoreGiveFromISR(s_handle2, &xHigherPriorityTaskWoken) == pdTRUE){
		pio_toggleLED(MID_LED);
	}
}

Code looks ok, other than xHigherPriorityTaskWoken should be set to pdFALSE before you call xSempahoreGiveFromISR().

Are you sure the semaphore has been created before the interrupt executes?

What does this mean? What is executing when the system is hung? If you break on the debugger, what do you see?

I would recommend setting a breakpoint on the call to xSemaphoreGiveFromISR(), then use the debugger to step into the function so you can see why it is returning pdFALSE. Once you have that information, if you don’t understand it, then reply back here.

Hi,
Thanks for your reply, I set xHigherPriorityTaskWoken to pdFALSE, but nothing changed. Its a UART_Rx interrupt, call the ISR, once data is available on UART port.

I tried to debug the code and found that it was calling one of configASSERT() (line no 744 in port.c) and execution halted. You can see the following trace.

xQueueGiveFromISR()->vPortValidateInterruptPriority()->configASSERT( ucCurrentPriority >= ucMaxSysCallPriority ) (line no 744 in port.c).

Also see the few entries of FreeRTOSConfig.h.
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 0x0F
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5
#define configKERNEL_INTERRUPT_PRIORITY ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) ) //configPRIO_BITS=3
#define configMAX_SYSCALL_INTERRUPT_PRIORITY ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )

I checked the vale of ucCurrentPriority(which is 64 for 10 interrupt priority) and ucMaxSysCallPriority(which is 160) and found that it met the condition for interrupt priority 10, assigned to UART_RX. I think 10 is fine as it is in between configLIBRARY_LOWEST_INTERRUPT_PRIORITY and configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY.

For experiment, I changed the priority to 4 and ucCurrentPriority changed to 128 and met the condition once again.

I think there is a bug in porting FreeRTOS code (v10.3.1) for Cortex-M7.

Please correct me if I am wrong.

There is no such serious bug in FreeRTOS. It would break all Cortex-M applications at least. Hence it’s very, very unlikely that a version is released with broken interrupt handling, right :wink:
You should read Cortex-M interrupt priorities for details.
I’m using a tiny helper macro to deal with logical interrupt priorities in Cortex-M (C++) application code when configuring NVIC.

#define uxPortIntPrio(p)  ( UBaseType_t(configLIBRARY_LOWEST_INTERRUPT_PRIORITY) - p )

Arm Cortex interrupts are a bit confusing because their priorities are specified two different ways (as small unshifted numbers, and then as numbers shifted into the places used by the hardware).

Looking at some of your numbers, some things don’t make sense.
configLIBRARY_LOWEST_INTERRUPT_PRIORITY = 0x0F which implies that you have 4 priority bits, but the comment is that configPRIO_BITS = 3, and a mapping of 4 to 128 and 5 to 160 agrees with a 3 bit priority field, thus the lowest priority value should be 0x07, and any priority of 8 or greater will act like it is 8 lower, thus 15 goes to 7, which works, but your 10 goes to 2 which is too small.

Hi,
Thanks for your reply.

I spent lots of time and found that as per the datasheet, the length of NVIC bits are 3, i.e lowest priority should be 7, not 0x0f.

I copied the FreeRTOSConfig file from demo project. Finally correct it and issue resolved.

Thanks for your support.

Also note your ISR is missing a call to yield if xHigherPriorityTaskWoken is true. In official Cortex-M ports it looks like this:

    portYIELD_FROM_ISR(xHigherPriorityTaskWoken);

This statement helps FreeRTOS switch to the task awoken by the ISR right away instead of at the end of the current time slice, if the task has higher priority than the interrupted one. Many applications rely on this kind of short synchronization latency.

Hi,

Thanks for your valuable input.

Now I included that.