This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

MSP430 UART overrun rx

Hi,

I'm using MSP4305659 for receiving data at 921,600BPS.

The reception is done using cyclic buffer implemented by interrupt.

I see from time to time starnge overrun error.

UCOE = 1 but in contrary to the datasheet, the  UCRXERR = 0.

Receive error flag. This bit indicates a character was received with error(s).
When UCRXERR = 1, on or more error flags, UCFE, UCPE, or UCOE is also
set. UCRXERR is cleared when UCAxRXBUF is read.
0b = No receive errors detected
1b = Receive error detected

Itsik.

  • I assume that you are using a MSP430F5659 with USCI and not eUSCI. Right?

    Did you noticed any received data missing in your circular buffer? (Especially when you detected data overrun error.) 

    Did you set or clear the UCRXEIE bit in the UCAxCTL1 register?

    Could you show us the code fragments where you read the UCAxSTAT and the UCAxRXBUF registers? Specifically, how many times did you reference these two resisters? And in what order? 

  • I assume that you are using a MSP430F5659 with USCI and not eUSCI. Right?

    [Itsik] correct

    Did you noticed any received data missing in your circular buffer? (Especially when you detected data overrun error.) 

    [Itsik] - I'm receiving the byte anyway for clearing the overrun flag.

    I did not look at the data but all I know that after that something wrong is happened after that that finally cause to the system to restart.

    Did you set or clear the UCRXEIE bit in the UCAxCTL1 register?

    [itsik] - Yes.

    Could you show us the code fragments where you read the UCAxSTAT and the UCAxRXBUF registers?Specifically, how many times did you reference these two resisters? And in what order? 

    [Itsik] - not relevant code excluded.
    It called from interrupt handler. This is the only place it called.

    The problem happens once 15 min after restart.

    #define UARTReceiveBufferReg() (HWREG8((BT_UART_MODULE_BASE) + OFS_UCAxRXBUF))

    VectorRegister = BT_UART_IVR;

    /* Determine the cause of the interrupt (Rx or Tx). */
    if(VectorRegister == USCI_UCRXIFG)
    {

               uint8 u8UartStatTmp = USCI_A_UART_queryStatusFlags(UartContext.UartBase,0xEC);

              if(u8UartStatTmp)
              {
                     Dummy = UARTReceiveBufferReg();
               }

               else

    {

              UartContext.RxBuffer[InIndex++] = UARTReceiveBufferReg();

    }

    }

  • Hello Itsik,

    From Section 36.3.6 of the User's Guide: "To detect overflows reliably the following flow is recommended. After a character was received and UCAxRXIFG is set, first read UCAxSTAT to check the error flags including the overflow flag UCOE. Read UCAxRXBUF next. This clears all error flags except UCOE, if UCAxRXBUF was overwritten between the read access to UCAxSTAT and to UCAxRXBUF. Therefore, the UCOE flag should be checked after reading UCAxRXBUF to detect this condition. Note that, in this case, the UCRXERR flag is not set."

    Hence if a UCOE occurs between the read access to UCAxSTAT and UCAxRXBUF the UCRXERR flag is not set. This seems to describe the issue you are seeing. Now that we have determined the validity of the UCOE we can now address how to fix the issue. First, can you please share your UART initialization code? We need to make sure that the USCI clock is at 20 MHz and that the baud rate values have been set correctly for optimal 921600 operation. 1 Mbps is already on the higher end of the device's UART capabilities and extra cycles introduced by the USCI IFG can easily cause an overrun condition. You may need to either decrease your baud rate to 460800, use DMA to automatically store received characters, or figure out how to reduce the amount of time spent in the ISR (using C code instead of driverlib functions could help).

    Regards,
    Ryan
  • HI Ryan,

    Thanks for the detailed and valuable answer. I appreciate it. 

    I fםund the root cause of why I have overrun at all.
    It was because the received byte did not read fast enough. 
    I did not aware of the issue of the interrupts are not nested by default.
    If an interrupt handler with lower priority was starting before the UART interrupt the overrun happen.
    If solved by using nested interrupt.

    About clearing the overrun flag,
    For performance issues, I will not read again the status register after reading the RXBUFF. 
    The overrun flag will be cleared at the next iteration of interrupt handler execution.
    Is this method can bring to an unexpected results beyond that I read this flag at the next execution?
    As  I writing this post, I understand why after I detecting the overrun status, the byte I read is correct.
    That is because the overrun related to the byte I already read it the prev. handler execution,
    and I did not aware of reading incorrect byte.
    Because I'm working at message oriented it is not an issue if I detecting by mistake the next byte as overrun instead the damaged byte.
    Anyway the message is already damaged at the situation of overrun.
    At the worst case, if the byte overrun is the last at a message, this message will be fail on verify and the next one will be fail because incorrect detecting a good byte as overrun.
    At my case, the UART is between BT external device and 3rd party BT stack (All from TI) I have nothing operative to do with the knowledge that there was an error. I read the byte anyway and put it on the cyclic buffer let the BT stack to deal with it.
    I that way, I don't loose the next packet even at the worst case.
    Theoretically, at that case, the knowledge of error byte is not interested. It is interested just for development issue to know that I have to improve the design.

    Is the interrupt handler will be called again because of the overrun flag did not clear?

    About reducing the baud rate, it is not an option at my case because it is required.

    About the CPU and UART clocks - I used TI tools to achieve the correct configuration and made a lot of effort when I tried to use 480,600.

    About DMA:
    I must say that... Ohhh it very heart....

    I actually use DMA where ever I can.
    TI DMA can be used just when you know at startup how many bytes you are receiving or you know that bytes will arrive endlessly.
    At my situation (and I think at almost all situations) the messages length of the coming message is unknown at the time teh DMA size is set.
    So actually, it cant be used.
    At ST uC there is a solution for this issue. The UART has silent detection an I'm using it for detecting and of packet. At TI uC there is not such option.
    At other UART channel of TI with proprietary protocol, I tried to set the header length and at the time, the last header byte received, to set again the DMA fo receiving the rest of the message after I received te length field, but it did not work out.
    For using DMA, I had to use additional GPIO as a LE likewise SPI bus.

    I'm using the DMA at this channel at transmission and I have an issue of flow control that I hope solved, because there is no direct way to suspend the DMA from sending bytes. I have to make hacking...

    Itsik.

  • >It was because the received byte did not read fast enough. 
    >I did not aware of the issue of the interrupts are not nested by default.


    Turning GIE-bit on in a ISR to allow any new (regardless of priority) interrupt to literally interrupt this interrupt is frown on.
    If your baudrate is near 1mbit, this is very high rate for a system that don't have fifo.
    Run mcu 16-25mhz
    Make all ISR use  less than 10 lines of code that take max 5uS to run, no function calls, no complicated math, set flag for main.c for larger tasks.
    Use DMA if possible

  • Thanks Tony,

    'Frown on' - did you mean turn on?

    (regardless of priority):
    Example:

    interrupt handler at priority 10 is running and GIE is enabled.

    Now other interrupt at priority 5 flag is set. its interrupt will be nested called before priority 10 will be ended?

  • Frown : disapproval, displeasure

    Yes any IRQ even with lower priority will interrupt.(msp430, msp432 ARM may have better nest control)
    If you set GIE in all ISR's except in the UART RX ISR it may work.
    But what a tangled mess (e.g nested) IRQ system we created and I frown on it.

  • That is what I actually did. I inserted GIE just at the interrupts at low priority that can be interfered and it worked.

    Did you know that if you enable the interrupt before resetting the ISR flag , the same handler starts to run recursively endlessly.

    So actually, there is no ISR priority system...

  • Under the circumstance you face, I would not enable GI inside that ISR.

    But I occasionally do set GI in the middle of ISR. And I might have frowned (wrinkled my brow) while doing so -- due to deep thoughts, not displeasure or disapproval. I had to consider possible priority reversal and recursion.

    There is an interrupt request-granting-priority. But once the (current) highest priority request is granted, GI is cleared before ISR is entered, GI is restored after ISR exits.

    I would frown on using DMA to handle incoming RXD too -- again, due to in deep thoughts, not displeasure or disapproval. Possible transmission error (and data overrun error) need to be considered and may be difficult to handle.
  • Itsik Hadar said:
    Did you know that if you enable the interrupt before resetting the ISR flag , the same handler starts to run recursively endlessly.

    Sure. But even if you cleared that flag before setting GI, recursion might still happen.

  • Hello Itsik,

    Along the lines of Tony's suggestions, service your low-priority ISRs as quickly as possible to keep them from taking away precious cycles that are required for the UART ISR.

    Regards,
    Ryan

**Attention** This is a public forum