# UART Interrupts in FreeRTOS

#### May Powitzer

##### Newbie
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.

#### KlausST

##### Super Moderator
Staff member
Hi,

I didn't use RTOS before...but I think an infinite loop is not what one wants in an RTOS.

Usually the (UART) interrupt stores received data in a software buffer (FIFO), maybe sets a FLAG when data is received.
The buffer need to be big enough to store at least the count data being received in the time between the main (parse) tasks.

Let's say the baudrate is 115200 and the UART_PARSE task runs every 100ms, then the buffer needs to handle 1152 bytes.
But often there is a "request - response communication" with a max expectable packet size, then it just needs to handle the count of a packet size. ... plus headroom.

I recommend to draw a timing diagram according your UART protocol. Then a flow chart. Not only for us, mainly for yourself.

Klaus

#### May Powitzer

##### Newbie
Thank you @KlausST for your fast response, I also tried something else like you said, I opened a task and stored the loop inside it. The task listens for a flag that changes by the handler when an interrupt occurs, as you said. But unfortunately, it doesn't work because it is after the scheduler starts.
The baud rate I use is 460800, I'm supposed to get a message every 1 millisecond and the buffer needs to handle not more than 30 bytes per message.

#### KlausST

##### Super Moderator
Staff member
Hi
opened a task and stored the loop inside it. T
No loop! (At least I think so)
Just make the task to run every xx milliseconds.

Klaus

#### Aussie Susan

What I've done in the past is to have the ISR set a semaphore or push something to a queue (depending on the situation) - there are specific versions of the appropriate routines that operate from within an ISR. (They usually have something like "...FromISR" at the end of the function name.)
Then in your task you simply wait for the semaphore/queue and then process the data. That can be done in a loop because the wait triggers the task switch etc so nothing else is held up.
Susan

#### May Powitzer

##### Newbie
Thank you for the replays, I’ve tried to enable the UART interrupt from a task after the scheduler has started, and it seems to work better. The problem now is that the other task (my_main_task) runs only once and then no more. I didn't understand how to implement this code without a loop inside the task, I need the task to run immediately after I received a message by the UART interrupt. I tried to use suspend instead of delay, I hope it is as good as the delay @KlausST suggested or the semaphore as @Aussie Susan sujjested.

the code:
C:
/* the UART task - it enables the UART interrupt and then suspend the task until a message has arrived with UART */
{
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)
{
}
}

/* 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
{
}
{
BaseType_t checkIfYieldRequired;
portYIELD_FROM_ISR(checkIfYieldRequired);
}
}

{
int count = 0;

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

int main( void )
{

while(1);
return 0;
}
the output:

hello world! : 0
. . .
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.

#### KlausST

##### Super Moderator
Staff member
Hi,

inside your main there is a "while(1)". This makes you stop further processing.

Klaus

#### Aussie Susan

@KLAUS - the 'vTaskStartScheduler()' before the 'while(1)' you mention should never return: in effect it is the overall 'main loop'. It only returns if the scheduler can't start.
@May - can I suggest tat you use the more conventional (at least it is the only one I use and it has never failed):
if you want a 1 second delay. I'm not sure exactly what effect your code will have but I'm guessing that it may be causing a very long delay which is why you don't see it run a 2nd time.
Also 200 is rather a small task stack - I typically use 1024 as a minimum and often much more.
If what you really want it is your 'my_main_task' to restart after each received message then I would use something like:
Code:
SemaphoreHandle_t uartSemaphore;

void Handler_uart_1(...)
{

// Process the interrupt and when you want to process the whole line...
}

{
uartSemaphoreCreateBinary();     // Even put this in your 'real' main() function
xSemaphoreTake( uartSemaphore, portMAX_DELAY);   // Hold the semaphore - the ISR will release it
while(1)
{
// Wait until the ISR has released the semaphore
xSemaphoreTake(uartSemaphore, portMAX_DELAY);  // Should really check for a timeout
// loop again still holding the semaphore which the next ISR will release
}
}
(Sorry - I'm not use to this forum and the above seems to have lost my indenting) Formatting tags fixed by moderator
By the way, the above requires that the lines can be processed faster than the next line can be received. If that is not the case then use a queue in much the same way - your ISR will push the line into the queue and the main loop will pause until at least 1 line is available in the queue. Just be wary of exceeding the size of the queue.
In this way you only need one task and the ISR.
Susan

Last edited by a moderator:

#### KlausST

##### Super Moderator
Staff member
the 'vTaskStartScheduler()' before the 'while(1)' you mention should never return: in effect it is the overall 'main loop'. It only returns if the scheduler can't start.
I understand. It makes sense.

Klaus