Overrun errors with two USART interrupts
Asked Answered
L

3

9

Using two USARTs running at 115200 baud on a STM32F2, one to communicate with a radio module and one for serial from a PC. The clock speed is 120MHz.

When receiving data from both USARTs simultaneously overrun errors can occur on one USART or the other. Doing some quick back of the envelope calculations there should be enough time to process both, as the interrupts are just simple copy the byte to a circular buffer.

In both theory and from measurement the interrupt code to push byte to buffer should/does run in the order of 2-4µS, at 115200 baud we have around 70us to process each char.

Why are we seeing occassional OREs on one or other USART?

Update - additional information:

  1. No other ISRs in our code are firing at this time.
  2. We are running Keil RTX with systick interrupt configured to fire every 10mS.
  3. We are not disabling any interrupts at this time.
  4. According this book (The Designer's Guide to the Cortex-M Processor Family) the interupt latency is around 12cycles (not really deadly)

Given all the above 70us is at least a factor of 10 over the time we take to clear the interrupts - so I'm not sure its is so easy to explain. Should I be concluding that there must be some other factor I am over looking?

MDK-ARM is version 4.70

The systick interrupt is used by the RTOS so cannot time this the other ISRs take 2-3µS to run per byte each.

Lucillalucille answered 15/4, 2014 at 8:52 Comment(8)
You haven't provided enough information for someone to say why you, specifically, are getting overruns. Obvious candidates: Disabling interrupts somewhere else? Higher priority interrupt handler too slow? Bug in your code? Not enough information to figure out which.Capua
ISR latency is pretty deadly on that chip, the UARTs don't have a fifo buffer. Your theoretical calculation is already off by a factor of two. Add higher priority interrupts whose ISR take too much time or interrupts getting disabled in code you don't know about and an overrun gets to be easy to explain.Duumvir
Thanks for the comments I've added some more information to the question, I'm not sure what other information I can provide.Lucillalucille
What version of RTX (or ARM-MDK)? Early versions for Cortex-M3 had bugs and did not fully support interrupt priority grouping. The question is perhaps unanswerable without code.Grin
How long does the systick interrupt take to execute? Can the systick ISR be interrupted by the USART interrupts? What is the interrupt latency for all three?Recap
I am not one to give up on an unexplained problem since symptoms may show up elsewhere later. Still, for my last few projects, I've always gone with DMA to create a circular buffer which stores data received from the USART. Actual hardware (the DMA controller) just doesn't miss deadlines (unless it too is overloaded, but unless you're using it for something else, 2 USARTs at that rate should be a piece of cake).Aggravation
Is it possible that the processor was sleeping at the time? According to the datasheet, waking up from stop mode could typically take 110 us in certain circumstances, and waking up from standby mode takes at a minimum 260 us. Also, can you make a small project, stripping out as much code as you can, that reproduces this bug? Especially if you take out every other interrupt (including the RTOS) and don't ever put the processor in sleep mode. That could be indicative of some sort of hardware bug (the kind that should go in an errata sheet).Aggravation
You may not disable interrupts completely, but do you set your PRIMASK high enough to disable your UART interrupts (possibly inadvertently)? I know FreeRTOS will do this on the CM3 to allow you to still have "fast" interrupts that don't use the OS, but they need to be set above a specific priority level.Dumbwaiter
M
3

I ran into a similar problem as yours a few months ago on a Cortex M4 (SAM4S). I have a function that gets called at 100 Hz based on a Timer Interrupt.

In the meantime I had a UART configured to interrupt on char reception. The expected data over UART was 64 byte long packets and interrupting on every char caused latency such that my 100 Hz update function was running at about 20 Hz. 100 Hz is relatively slow on this particular 120 MHz processor but interrupting on every char was causing massive delays.

I decided to configure the UART to use PDC (Peripheral DMA controller) and my problems disappeared instantly.

DMA allows the UART to store data in memory WITHOUT interrupting the processor until the buffer is full saving lots of overhead.

In my case, I told PDC to store UART data into an buffer (byte array) and specified the length. When UART via PDC filled the buffer the PDC issued an interrupt.

In PDC ISR:

  1. Give PDC new empty buffer
  2. Restart UART PDC (so can collect data while we do other stuff in isr)
  3. memcpy full buffer into RINGBUFFER
  4. Exit ISR

As swineone recommended above, implement DMA and you'll love life.

Mustachio answered 6/12, 2014 at 7:38 Comment(0)
P
0

Had a similar problem. Short solution - change oversampling to 8 bits which makes USART clock more precise. And choose your MCU clock wisely!

huart1.Init.OverSampling = UART_OVERSAMPLING_8;

Furthermore, add USART error handler and mechanism to check that your data valid such as CRC16. Here is example for the STM32F0xx series, I am assuming it should be pretty similar across the series.

void UART_flush(void) {
  // Flush UART RX buffer if RXNE is set
  if READ_BIT(huart1.Instance->ISR, USART_ISR_RXNE) {
    SET_BIT(huart1.Instance->RQR, UART_RXDATA_FLUSH_REQUEST);
  }

  // Not available on F030xx devices!
  // SET_BIT(huart1.Instance->RQR, UART_TXDATA_FLUSH_REQUEST);

  // Clear All Errors (if needed)
  if (READ_BIT(huart1.Instance->ISR, USART_ISR_ORE | USART_ISR_FE | USART_ISR_NE)) {
    SET_BIT(huart1.Instance->ICR, USART_ICR_ORECF | USART_ICR_FECF | USART_ICR_NCF);
  }
}

// USART Error Handler
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart) {
  if(huart->Instance==USART1) {
    // See if we have any errors
    if (READ_BIT(huart1.Instance->ISR, USART_ISR_ORE | USART_ISR_FE | USART_ISR_NE | USART_ISR_RXNE)) {
        // Flush errors
        UART_flush();

        // Raise Error Handler
        _Error_Handler(__FILE__, __LINE__);
    }
  }
}

DMA might help as well. My problem was related to USART clock tolerances which might even cause overrun error with DMA implemented. Since it is USART hardware problem. Anyway, hope this helps someone out there! Cheers!

Poff answered 2/5, 2018 at 19:50 Comment(0)
K
0

I have this problem recently, so I implemented a UART_ErrorCallback function that had was not implanted yet (just the _weak version). Is like this:

void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
     if(huart == &huart1)
     {
         HAL_UART_DeInit(&huart1);
         MX_USART1_UART_Init(); //my initialization code
      ...

And this solve the overrun issue.

Kosher answered 6/2, 2021 at 22:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.