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.

TMS320F28P650DK: DMA + UART: Skipping byte when transmitting, extra byte when receiving

Part Number: TMS320F28P650DK
Other Parts Discussed in Thread: C2000WARE

Tool/software:

Hello!
We have a TMS320F28P650DK6 exchanging messages (~512-bytes) with another MCU over a UART. About 10% of the time, the TMS misses a byte when transmitting or sees an extra byte of 0's when receiving.

CPU1 on the TMS is clocked at 200MHz, and the UART runs at 1MHz (8 bits/word, 1 stop bit). A logic analyzer trace shows nothing abnormal. Incoming messages look perfectly fine, and outgoing messages look perfect except that they're missing a random byte in the middle. The missing byte appears at both even and odd offsets from the start of the packet.

TX is driven by a DMA -- burst size 2, triggered by 14 bytes or less in the TX FIFO. The DMA is set up to send the entire transfer in one operation.
RX is also driven by a DMA -- burst size 4, triggered by 4 or more bytes in the RX FIFO. The DMA runs continuously, and the buffer is large enough to fit an entire message. I can see that we're receiving spurious zeroes by observing the buffer with a debugger.

I could use some help figuring out what could be causing this behavior. Since the TX DMA's burst size is 2, it shouldn't even be possible to send an odd number of bytes -- but the logic analyzer clearly shows that we are occasionally sending 519 instead of 520. I would appreciate any insight.

Thank you!

  • Hi Anton,

    A few things:

    1. Can you check the UART RIS register and see if any error flags are being raised during your transmissions/receives?
    2. One note with the UART module: you cannot have the UART data register (UARTDR) open in the debugger while receiving, otherwise the UART considers this a “read” of the data register and discards the data from the RX FIFO. Make sure you don't have the UARTDR register open in the CCS Register View or in the Memory browser when receiving data.
    3. Have you tried running the uart_ex4_loopback_dma example from C2000ware on your setup first as a starting point?

    Best Regards,

    Delaney

  • Thank you for looking into it!

    1. I have reproduced the issue with the UARTRIS register reporting no errors. I did see the overflow bit set once when I abused the unit by starting and stopping the debugger a bunch, so it looks like everything is set up right and the interrupt bits are not accidentally being cleared somewhere.
    I also checked UARTRSR and the DMA channel's OVRFLG bit, and they look ok.
    2. Thank you. I have not been looking at UARTDR with the debugger.
    3. We started with examples. Everything has been working somewhat reliably until recently, when we started doing larger (ie, 520-byte) transfers.
    I also just noticed something similar on the second UART, which we are also using for inter-device communication. That UART is transmitting at 8.33MHz, and I'm occasionally noticing four bytes missing in the middle of 46-byte transmission. I'm not sure if this is new or if we just didn't notice until now; I can look into it next week.

    I find these symptoms very strange. If the DMA were too slow (contending for resources with other DMA channels / the CPU, missing triggers, etc), I would expect to see gaps in the transmission but no missing data. Instead, it transmits with no gaps but still misses a byte. Is it possible that the DMA is instead doing two bursts for one trigger?
    On the RX side, my current theory is that the UART FIFO is underflowing -- ie, the DMA tries to retrieve a byte from an empty FIFO, which results in an extra zero in the DMA buffer. Would an underflow set any of the error bits? I'm struggling to figure out where else that zero could possibly come from.

  • Hi Anton,

    Due to the nature of the issue (full bytes being dropped), I would expect this to be an overrun of the UART FIFOs. Your burst size configuration and FIFO levels match, so the timing of the trigger and data transfer should be synchronized properly. 

    Instead of looking in the CCS window, can you try enabling all of the error interrupts and putting a breakpoint or ESTOP0 in the ISR? This is a more definitive way to rule out any errors. You can do the same with the DMA channels - enable the error interrupt flags and add an if statement check inside the ISR with a NOP instruction inside, then add a breakpoint inside the if statement and see if the CPU ever stops. 

    Best Regards,

    Delaney

  • Thanks for the suggestion. That's exactly what I did the first time -- but I tried it again, this time with counters (see code snippet below).

    The DMA end-of-transfer interrupts trigger about as many times as I expect. I think rxmis doesn't trigger because the DMA always clears the interrupt flag before the ISR can run. In a similar vein, I imagine that the txmis interrupt usually gets preempted by the TX DMA?

    The DMA overflow and UART FIFO overflow flags are never set, and yet I still regularly see a missing byte when transmitting and an extra byte when receiving.

    Importantly, I've discovered that the issue only occurs when the USB peripheral is enabled and running.
    As far as I can tell, USB should not conflict with the UART in any way:
     - USB and UART do not share a peripheral bus (see datasheet, pg. 295),
     - We are not using the DMA for USB (or anything else besides the two UARTs),
     - The UART DMA buffers are all in GSRAM0, while everything USB-related is in main memory,
     - All UART transmissions are completed in a single DMA transfer -- so I would not expect issues in the middle of a transmission, even if interrupts are disabled and the CPU is completely tied up with USB things. RX is more complicated since we run the DMA in continuous mode in a circular buffer configuration, but I would still expect problems to come in multiples of the DMA burst size (not one byte).

    To summarize -- the UART runs (as far as I know) autonomously and completely unimpeded, still misses a byte, and then acts as if nothing went wrong. I'm not sure what to make of this; any guidance is appreciated.
    Thank you!

    typedef struct {
        uint32_t tx_dma_transfer_count;
        uint32_t tx_dma_ovrflg;
        uint32_t rx_dma_transfer_count;
        uint32_t rx_dma_ovrflg;
        uint32_t txmis;
        uint32_t rxmis;
        uint32_t femis;
        uint32_t pemis;
        uint32_t bemis;
        uint32_t oemis;
    } uart_err_t;
    volatile uart_err_t g_uart_err = {0};
    
    __interrupt void INT_UARTA_IPC_RX_DMA_ISR(void)
    {
        if(HWREG(UARTA_IPC_RX_DMA_BASE + DMA_O_CONTROL) & DMA_CONTROL_OVRFLG){
            g_uart_err.rx_dma_ovrflg++;
            HWREG(UARTA_IPC_RX_DMA_BASE + DMA_O_CONTROL) = DMA_CONTROL_ERRCLR;
        } else {
            g_uart_err.rx_dma_transfer_count++;
        }
    
        // Record keeping for circular buffer
        g_dbg_ipc_uart.rx_w_wrap_total += 1;
        if(ipc_rx_wrap_cnt < INT16_MAX) ipc_rx_wrap_cnt += 1;
        ipc_rx_wrap_guard = false;
        Interrupt_clearACKGroup(INT_UARTA_IPC_RX_DMA_INTERRUPT_ACK_GROUP);
    }
    
    __interrupt void INT_UARTA_IPC_TX_DMA_ISR(void)
    {
        if(HWREG(UARTA_IPC_TX_DMA_BASE + DMA_O_CONTROL) & DMA_CONTROL_OVRFLG){
            g_uart_err.tx_dma_ovrflg++;
            HWREG(UARTA_IPC_TX_DMA_BASE + DMA_O_CONTROL) = DMA_CONTROL_ERRCLR;
        } else {
            g_uart_err.tx_dma_transfer_count++;
        }
        Interrupt_clearACKGroup(INT_UARTA_IPC_TX_DMA_INTERRUPT_ACK_GROUP);
    }
    
    __interrupt void INT_UARTA_IPC_ISR(void)
    {
        volatile const uint32_t MIS = HWREG(UARTA_IPC_BASE + UART_O_MIS);
    
        if(MIS & UART_MIS_TXMIS) g_uart_err.txmis++;
        if(MIS & UART_MIS_RXMIS) g_uart_err.rxmis++;
        if(MIS & UART_MIS_FEMIS) g_uart_err.femis++;
        if(MIS & UART_MIS_PEMIS) g_uart_err.pemis++;
        if(MIS & UART_MIS_BEMIS) g_uart_err.bemis++;
        if(MIS & UART_MIS_OEMIS) g_uart_err.oemis++;
    
        HWREG(UARTA_IPC_BASE + UART_O_ICR) = 0xFFFFFFFF;
        UART_clearGlobalInterruptFlag(UARTA_IPC_BASE);
        Interrupt_clearACKGroup(INT_UARTA_IPC_INTERRUPT_ACK_GROUP);
    }

  • Hi Anton,

    Interesting, let me look into this further and get back to you.

    Best Regards,

    Delaney

  • Hi Anton,

    Apologies for the delay. Have you tried scoping the RX and TX lines just to verify that the data looks correct/expected there?

    And you are correct; the USB peripheral should not have a direct effect on the UART peripheral in this case.

    One thing I would suggest is try disabling the RX DMA continuous mode, sometimes this can cause issues with timing. Can you test something - disable continuous mode and keep the USB enabled/running.

    Best Regards,

    Delaney