ISR routine is not properly running

I have a USART with byte received interrupt enabled.
When a byte is arrived, I put it in a queue.
I have a single task that reads that queue. Zero ticks delays in the queue receive.

The problem is that I get overun error in the USART. That means the ISR routine is not running properly. And some received bytes are missed.

To me it sounds like something else takes priority over the USART ISR.

The USART is enabled after scheduler.

Microcontroller: Cortex-M4.
FreeRTOS Kernel V10.5.1
My USART has priority NVIC 5.
CPU freq: 120MHz.
USART baudrate: 115200

The code works fine without FreeRTOS, I don’t miss any bytes. The ISR routine works fine.

NVIC_DisableIRQ(USART1_IRQn);  
NVIC_ClearPendingIRQ(USART1_IRQn);  
NVIC_SetPriority(USART1_IRQn, 5);  
NVIC_EnableIRQ(USART1_IRQn);  
/* 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

/* The lowest interrupt priority that can be used in a call to a "set priority"
 * function. */
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY         0x0f

/* The highest interrupt priority that can be used by any interrupt service
 * routine that makes calls to interrupt safe FreeRTOS API functions.  DO NOT CALL
 * INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHER
 * PRIORITY THAN THIS! (higher priorities are lower numeric values. */
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY    5

/* Interrupt priorities used by the kernel port layer itself.  These are generic
 * to all Cortex-M ports, and do not rely on any particular library functions. */
#define configKERNEL_INTERRUPT_PRIORITY                 (configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS))

/* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!!
 * See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */
#define configMAX_SYSCALL_INTERRUPT_PRIORITY            (configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS))

My isr handler:

void USART1_Handler(void)
{
	BaseType_t pxHigherPriorityTaskWoken = pdFALSE;
	uint32_t stat = usart_get_status(USART1);
	if ((stat & US_CSR_RXRDY) == US_CSR_RXRDY)
	{
		uint8_t b = USART1->US_RHR;
		if (rx_queue)
		{
			xQueueSendFromISR(rx_queue, &b, &pxHigherPriorityTaskWoken);
		}
	}
	if ((stat & US_CSR_OVRE) == US_CSR_OVRE)
	{
		usart_reset_status(USART1);
       // This statement becomes true, randomly and unexpectendly.
     /*
       example of how I chatch this:
       ASSERT(false);
      */
	}

	if (pxHigherPriorityTaskWoken)
	{
		portYIELD_FROM_ISR(pdTRUE);
	}
}
// code that enables usart.
void usart_init(void)
{
	if (rx_queue == NULL)
	{
		rx_queue = xQueueCreate(1024, sizeof(uint8_t));
	}
	ASSERT(rx_queue != NULL);
	xQueueReset(rx_queue);

    // enable USART code here

	NVIC_DisableIRQ(USART1_IRQn);
	NVIC_ClearPendingIRQ(USART1_IRQn);
	NVIC_SetPriority(USART1_IRQn, 5);
	NVIC_EnableIRQ(USART1_IRQn);
}

// ------

// size is unused here.
// application code reads one byte at a time.
// I have commented out the disable/enable interrupt but nothing changed. 
int usart_read(uint8_t * const buff, uint16_t size)
{
    // I tried to also remove the disable/enable rx inter here. but nothing changed.
	BaseType_t ret = 0;
	//disable_rx_interrupt();
	if (rx_queue)
	{
		ret = xQueueReceive(rx_queue, buff, 0);
	}
	//enable_rx_interrupt();
	return ret;
}

The pieces of code above work perfect without FreeRTOS. Of course I had to replace my buffers/queues with FreeRTOS provided queue to make it work.
But that’s the only things I changed.

The problem is that with FreeRTOS enabled the statement
if ((stat & US_CSR_OVRE) == US_CSR_OVRE)
becomes true.

If I add a little delay:
vTaskDelay(1);
Inside my main super loop (the only task I have).
It runs better. Runs better means it’s less frequent to observe the above statement being true.

That’s how I enable the task:

	xTaskCreate(main_app, "main", 2048, NULL, tskIDLE_PRIORITY+1, NULL);

	vTaskStartScheduler();

	/* If all is well, the scheduler will now be running, and the following
	line will never be reached.  If the following line does execute, then
	there was insufficient FreeRTOS heap memory available for the idle and/or
	timer tasks	to be created.  See the memory management section on the
	FreeRTOS web site for more details. */
	for( ;; );

We also need to see your ISR code.

Did you define configASSERT ? What’s the queue size and which other tasks are running at which (higher ?) prio ?
Please show the ISR and relevant task code.

Yes I have configured ASSERT.

Assert isn’t failed

I added the code of my ISR.
I just replaced my own queue with FreeRTOS queue

I added some pieces of code.

disable/enable_rx_interrupt is not needed because you fully service the USART in the ISR, which is good. Instead it might delay servicing the USART maybe causing an overrun. So far the code seems ok. You could also use the convenience macro portEND_SWITCHING_ISR in the ISR.
What’s the baud rate and the CPU clock ?
What else is the main task doing when polling ?
Also I’d avoid polling the queue and use a waiting/blocking call to process the queue as soon as there is something to do.
Alternatively you could use FreeRTOS streambuffer as transfer mechanism, which comes with less overhead than a queue.

If I understand correctly, the ISR routine should be able9 to be invoked whenever a byte is coming.
The overun takes place whether I have a queue to add the received bytes or not. It doesn’t matter.
That means, whatever the application is doing, the ISR must be invoked and read the register. If the register is not read on time and next byte comes in, the overun occurs.
That lead me to the conclusion that the handler is somehow suspended (?) and no one reads the register that holds received byte.

I have commented out the disable/enable interrupt but nothing changed. However my point is that the ISR routine should be able to run on time but it looks like someone else takes priority over it.

The baudrate is 115200.
CPU frequency is 120MHz.

Note that without FreeRTOS everything works perfect. That’s another indicator that it has to do with some priorities.
Also, one more detail is that lowering the baudrate to 9600 reduces the frequency of overun occurance.

So I’m pretty sure that someone does not allow the ISR handler to run on time!

Does the USART have a fifo, and is it enabled?

It sounds like you may have a task using an excessively long Critical Section.

One debugging technique is to make the ISR hangs on the overrun, and use the debugger to look at the return address to see if it happens just after a call to exit the critical section, in which case that critical section is too long.

It also could be another ISR taking too long, look at what ISRs have the same or higher priority, maybe to test make the serial port the higher priority by lowering the priority of the other ISRs.

Your MCU should be fast enough to handle 115200 baud even without using PDC support.
If this is the only interrupt you’re using post-processed by a single task this should work :thinking:
Do you use the default FreeRTOS SysTick ?
Just to be sure you have configUSE_PREEMPTION enabled ?

@richard-damon It’s seems to be a Microchip (former Atmel) SAM4-MCU. No FIFO but with an associated DMA called PDC which can be used to setup a FIFO style behavior.

Yes.

#define configUSE_PREEMPTION    1

Yes it is.
Note that, the code works perfectly without FreeRTOS. The overun started occuring when I decided to migrate my code to FreeRTOS.

The task does not pause. It runs indefinitely.
I just expect the ISR routine to interrupt and get called whenever a byte is received.

When a byte comes in, the register needs to be read. Otherwise, the next byte will cause the overun error to occur, and the previous byte will be lost.

I noticed all this because I was reading incomplete frames from USART.

I tried disabling everything else…
Still same behaviour.

Have you tried studying the behavior with Tracealyzer or a compatible tool?

The ISR will interrupt UNLESS the task has invoked a critical section. Your symptoms seem to imply that interrupts are being blocked,

The other possibility is that you queue fills because something keeps the task from processing characters out of the queue fast enough.

Perhaps you should check the status of the write to the queue to see if that happens.

As I suggested, I would likely add a test in the ISR for the problem and just hang there, then examine the machine state to see what just happened to see what triggers it.

To make the task react as soon as possible to incoming data I’d make it waiting (forever using portMAX_DELAY) for the queue to get woken up immediately, read the 1st available byte and would then add a
while ( xQueueReceive(rx_queue, ++buff, 0) ) … ; loop (limited to size of the provided buff) to flush the queue as event coalescing/to catch up with the incoming data stream.
There are also some diagnostic functions like uxQueueMessagesWaiting resp. uxQueueSpacesAvailable you might use to see what’s going on.
I’d not recommend leaving the task busy spinning around to poll the queue.
This would cause issues when adding more tasks to your application because it’d not give up the CPU when there is nothing to do.

You assuming the task does not read the bytes out of the queue. While the real problem is that the ISR does not invoke to service the received byte.

Yes, true. I’m planning to do it. But one step at a time.

One of the issues to consider is that when the task reads fom the queue, the critical section is claimed implicitly to ensure queue coherence. It may be the case that this critical section ownership may interfere with the next character. I would also vote for not storing/reading the characters one byte at a time, at least not on the OS level.