FreeRTOS ISR API for STM32F411

abeltom87 wrote on Saturday, April 07, 2018:

Hello Forum,

I am trying go handle a receive Interrupt on STM32F411 Eval board using the FreeRTOS API. However,
xSemaphoreGiveFromISR is the API that is causing the problem. When the interrut occurs, i.e when the Rx line receives a character from user, the program freezes, remains stuck until Reset. If i do not use the FreeRTOS APIs for ISR , the Rx Interrupt works, please see code below. So i know the Interrupt is working, when i turn USE_FREERTOS_ISR_API in my code off and i can see the received byte on my terminal program. Also i have referred to chapter 6 of the FreeRTOS handson guide manual regarding Interrupt management.

void USART2_IRQHandler(void)
{
#ifndef USE_FREERTOS_ISR_API
if (USART_GetITStatus(USART2, USART_IT_RXNE))
{
Rx_Cplt_flag =1
Recvd_word = USART_ReceiveData(USART2);
USART_ClearITPendingBit(USART2, USART_IT_RXNE);

    }
        #else /*Freertos APIS are used*/
    static BaseType_t xHigherPriorityTaskWoken;

    xHigherPriorityTaskWoken = pdFALSE;
    xSemaphoreGiveFromISR( xBinarySemaphore, &xHigherPriorityTaskWoken );
    //xSemaphoreGive(xBinarySemaphore);

    taskENTER_CRITICAL() ;
    if (USART_GetITStatus(USART2, USART_IT_RXNE))
    {

        Recvd_word = USART_ReceiveData(USART2);
        USART_ClearITPendingBit(USART2, USART_IT_RXNE);

    }

    if ( xHigherPriorityTaskWoken != pdFALSE )
        portYIELD_FROM_ISR(xHigherPriorityTaskWoken);


    taskEXIT_CRITICAL();

        #endif

}
`
I have created two other tasks which are running fine. Here are my sample task functions,

int main(void)
{

	SystemInit();

	init_USART2();
	init_led_gpios();
	enable_usart2_irq();
	xBinarySemaphore = xSemaphoreCreateBinary();

	// Create a task
	// Stack and TCB are placed in CCM of STM32F4
	// The CCM block is connected directly to the core, which leads to zero wait states
	if( xBinarySemaphore != NULL )
	{
		xTaskCreateStatic(vTask1_print, "task1_print", TASK1_STACK_SIZE, NULL, 5,
				printTask1_Stack, &Task1Buff);
		xTaskCreateStatic(vTask2_print, "task2_print", TASK2_STACK_SIZE, NULL, 1,
				printTask2_Stack, &Task2Buff);

#ifdef USE_FREERTOS_ISR_API
		xTaskCreateStatic(vTask_ISR_Handler, "task3_isr", TASK3_STACK_SIZE, NULL, 2,
						printTask3_Stack, &Task3Buff);
#endif


		USART_TX_string("Starting scheduler...\r\n");

		vTaskStartScheduler();  // should never return
	}
	while (1)
	{}
}

void vTask1_print(void* p)
{
	while (1)
	{

		USART_TX_string("Task1...\r\n");

#ifndef USE_FREERTOS_ISR_API
		if (Rx_Cplt_flag == 1)
		{
			USART_TX_byte(Recvd_word);
			Rx_Cplt_flag = 0;
		}
#endif
		vTaskDelay(500);
	}

	vTaskDelete(NULL);
}

void vTask2_print(void* p)
{
	while (1)
	{

		toggle_leds();
		vTaskDelay(1000);
	}
	vTaskDelete(NULL);
}


void vTask_ISR_Handler(void *p)
{
	while(1)
	{
		xSemaphoreTake(xBinarySemaphore, 10000);
		USART_TX_byte(Recvd_word);
		vTaskDelay(5000);
	}
}

richard_damon wrote on Saturday, April 07, 2018:

You probably need to set the priority of the interrupt to somethng allowable by FreeRTOS to use the API in the interrupt. If you stop the program with a debugger, you will probably find it has hung inside an asssert.

abeltom87 wrote on Saturday, April 07, 2018:

Thank you for your response, im not able to Debug since OpenOCD is not working correctly on my Toolchain,

However, i went through this https://www.freertos.org/RTOS-Cortex-M3-M4.html

And did the following:

NVIC_USARTStruct.NVIC_IRQChannelPreemptionPriority = 17;

in my USART IRQ init routine, since configMAX_SYSCALL_INTERRUPT_PRIORITY is defined as 16. It still does not work as expected

From my FreeRTOSConfig.h file:

/* Cortex-M specific definitions. */
#ifdef __NVIC_PRIO_BITS
/* __BVIC_PRIO_BITS will be specified when CMSIS is being used. */
#define configPRIO_BITS         __NVIC_PRIO_BITS
#else
#define configPRIO_BITS         4        /* 15 priority levels */
#endif

#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY   0xf


#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 1


#define configKERNEL_INTERRUPT_PRIORITY   ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )

#define configMAX_SYSCALL_INTERRUPT_PRIORITY  ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
#define configASSERT( x ) if( ( x ) == 0 ) { taskDISABLE_INTERRUPTS(); for( ;; ); }
//#define configASSERT(  x  )     if( ( x ) == 0 ) vAssertCalled( __FILE__, __LINE__ )

abeltom87 wrote on Monday, April 09, 2018:

Okay this might sound stupid and unreasonable but i left the priorities as they were (unchanged), and i removed taskENTER_CRITICAL(); and taskEXIT_CRITICAL(); calls and it worked as expected. I cannot explain why. And i still have this feeling that something is still terrribly wrong, since:
a) the default NVIC priority of USART2 is set to 0 ,
b) configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY is set to 5.

davedoors wrote on Monday, April 09, 2018:

You should not be using taskENTER_CRITICAL() or taskEXIT_CRITICAL() in the interrupt handler anyway so it makes sense that removing those calls prevent unexpected behavior. They don’t end in FromISR, and they are the only functions that are allowed. FreeRTOS and the hardware manage the interrupt nesting for you. Which FreeRTOS version are you using? I think your IRQ priorities are screwy and using V10 with configASSERT() enabled may help find errors.

abeltom87 wrote on Monday, April 09, 2018:

Thanks for the quick response, i am using FreeRTOSv9, and cofigASSERT is also enabled as I mentioned previously.

Just so that i understand correct, if there is a critical section inside a IRQ Handler, would it not make sense to use those calls, since i do not want other interrupts to occur.

rtel wrote on Monday, April 09, 2018:

Although V10 has more asserts to try and catch all interrupt priority issues, even V9 should assert if you call taskENTER_CRITICAL() from an interrupt. See line 419 here https://sourceforge.net/p/freertos/code/HEAD/tree/tags/V9.0.0/FreeRTOS/Source/portable/GCC/ARM_CM4F/port.c .

rtel wrote on Monday, April 09, 2018:

V9 has a lot of asserts to try and catch interrupt configuration errs,
but V10 has more (I think it checks just about everything, including the
number of priority bits configured actually matches the hardware).

abeltom87 wrote on Tuesday, April 10, 2018:

So a small update: Its clear to me what was wrong with the critical section calls, kernel is responsible for that purpose, theres no need to do it explicitly in an ISR.

However, I still fail to understand fully whats happening with configASSERT;

When i compiled and executed in Debug mode, seemed like configASSERT was ignored, but in Release mode , it sits in this eternal for loop,configASSERT( x ) if( ( x ) == 0 ) { taskDISABLE_INTERRUPTS(); for( ;; ); }

once i commented this out, it works for Release as well.