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( ;; );