UART Interrupts in FreeRTOS

Hi everyone,
I am a newbie to FreeRTOS and I am trying to implement communication using UART on my zcu104 board.
I implemented an infinite loop in my main thread to listen for a flag raised by an interrupt handler. It works fine.
When I placed the loop after the schedular, it stopped working.
I found that inside the schedular function it has a function called “portDISABLE_INTERRUPTS()”, above it the following comment:

“Interrupts are turned off here, to ensure a tick does not occur
before or during the call to xPortStartScheduler(). The stacks of
the created tasks contain a status word with interrupts switched on
so interrupts will automatically get re-enabled when the first task
starts to run.”

I created a task as suggested in the comment and it still not working.
I tried to find out if there are any priority issues and it seems that the interrupts have a higher priority than my task as it should.

What am I missing?

Thank you.

If I understand correctly you are saying that interrupts are working before the scheduler starts (up to the point where a FreeRTOS API function is called, after which they are deliberately left disabled), but don’t work after the scheduler has started.

It is possible that the interrupt controller is reset as the scheduler is started. Try installing and enabling the UART interrupt from a task after the scheduler has started.

1 Like

I remember at least at one time the code that xylinx provided for their BSP totally reset the Interrupt controller in the initialize the tick routine, so that any interrupt configure prior to that point were lost. Its been a while since I worked on that code so I am not sure of the details, but like many vender provided code bases, you need to double check them. I seem to remember needing to extract out the interrupt control reconfigure code and make all the code use the same version of the interface to avoid the issue.

1 Like

Thank you for the replays, I’ve tried to enable the UART interrupt from a task after the scheduler has started, as suggested by you, and it seems to work better. The problem now is that the other task (my_main_task) runs only once and then no more.

the code:

/* the UART task - it enables the UART interrupt and then suspend the task until a message has arrived with UART */
void uart_task()
{
	int Status;

	//UART 1 init
	Status = Init_uart_1(&InterruptController, &UartPs, UART_DEVICE_ID_WEAP, 
                                                                            UART_INT_IRQ_ID_WEAP);
	if (Status != XST_SUCCESS)
	{
		return XST_FAILURE;
	}

	while(1)
	{
		vTaskSuspend(NULL); // suspend itself
		printf("received uart message\r\n");
	}
}


/* the UART interrupt handler - it counts the bytes received by the UART and raises a flag when a message with 10 bytes long has received */
void Handler_uart_1(void *CallBackRef, u32 Event, unsigned int EventData)
{
XUartPs_Recv(&UartPs, &RecvByte_uart_1, 1); // receive data from uart into RecvByte_uart_1
// push the received byte into cyclic buffer
CB_Push_byte(CycleBuffer, CYCLE_BUFFER_SIZE, &CB_count, &CB_tail, RecvByte_uart_1);
// Later on, I will use the cyclic buffer in the uart_task to inspect the received message.
if (RecvByte_uart_1 == 0x5dU) // check if it is the beginning of a message
{
hadler_msg_counter = 0;
}
hadler_msg_counter++;
if (hadler_msg_counter == 10) // if finished reading a message
{
BaseType_t checkIfYieldRequired;
checkIfYieldRequired = xTaskResumeFromISR(myIntTaskHandle);
portYIELD_FROM_ISR(checkIfYieldRequired);
}
}


/* the main task*/
void my_main_task(void * p)
{
	int count = 0;

	while(1)
	{
		printf("hello world! : %d\r\n", count++);
		vTaskDelay(1000 * configTICK_RATE_HZ / 1000);
	}
}

int main( void )
{
	xTaskCreate(my_main_task, "main_task", 200, (void*) 0, tskIDLE_PRIORITY, &myTaskHandle);
	xTaskCreate(uart_task, "UartListener", 200, (void*) 0, tskIDLE_PRIORITY, &myIntTaskHandle);

	vTaskStartScheduler();
	while(1);
	return 0;
}

the output:

hello world! : 0
received uart message
received uart message
received uart message
received uart message
received uart message
received uart message
received uart message
. . .

the “hello world !” message occurs only once even if I don’t send any data through UART.

I am not sure what is wrong here.

One big question is if printf is thread safe, and/or using too much stack for your system. You should make sure you turn on stack checking and that configASSERT is defined to catch problems.

1 Like

Hi @richard-damon, I’ve tried to avoid the printf, as you said, and changed it to a counter so I can see if it is increasing its value but unfortunately it doesn’t. I found out that when I delete the first task and it’s only the “my_main_task” left, then the counter works fine, and another step further, if I delete the delay of “my_main_task” (I know someday it will have to be there) and create both of the tasks, they both run but I miss some of the messages I send through the UART.
I make sure that the CHECK_FOR_STACK_OVERFLOWalso decreased the stack size but nothing changed.

in the freeRTOSConfig.h the CHECK_FOR_STACK_OVERFLOW is set to 2 which I think is right in my case.

One thought, make sure when you enabled your interrupt you didn’t disable the timer interrupts. As I said, the issue was that the way the Xylinx code was written you ended up with multiple sets of code for the interrupt controller, and when the second one is created it wipes out the setting for the first one.

1 Like

Hi @richard-damon, thank you for your help.
I did what you suggested and it works!
I needed to enable the tick interrupts again and the delay started working as I wanted.

Thank you!

My preference was to fix their code to use a global interrupt controller configuration, but that depends if you are willing to break from using their provided code.

FYI, there is a new example application demonstrating how to properly use interrupts using the Xilinx FreeRTOS implementation:

Regards,
Terry