AnsweredAssumed Answered

Errata e2582 UART flow control timing issue can result in loss of characters

Question asked by Michael Guntli on Nov 18, 2015
Latest reply on Nov 23, 2015 by Mark Butcher

Dear Freescale Community

 

Task to solve:

Kinetis K60 (K60P144M150SF3) has to receive data over UART (hardware flow control) with a high baud rate (576000kbps), data is sent from an i.MX6 with a UART-TX DMA transfer.

 

Known errata for Kinetis:

- http://www.freescale.com/files/microcontrollers/doc/errata/KINETIS_4N30D.pdf

 

Suggested workaround according to errata:

"For UARTs without a FIFO (or if the FIFO is disabled): Delay might need to be added between characters on the transmit side in order to allow time for the negation of /RTS to be recognized before the next character is sent."

--> not applicable, the i.MX6 uses a DMA transfer for the UART data.

 

Problems:

  1. UART with FIFO buffers are not available, only UART4 which have a depth of 1 byte are available
  2. Service the UART with a traditional "1 interrupt per byte" is too slow, which result in data loss according to the errata
  3. Due to the errata e2584 (UART: Possible conflicts between UART interrupt service routines and DMA), I cannot properly use a DMA RX transfer with idle timeout
    DISCUSSION:  Missing critical RX UART DMA Event Functionality in Freescale Parts
  4. Suggested workaround to add a transfer delay on the transmitter is not acceptable, because this is a DMA transfer started from the i.MX6

 

Proposed solution for discussion:

I can see currently a single solution to the problem, which is kind of ugly but would at least guarantee the correct data receiption:

 

  1. Create a ringbuffer with a fixed size (e.g. 1024 bytes).
    Head is read position from software, Tail is DMA-write position
    ring-buffer-ex1.jpg

  2. Configure a UART-RX-DMA for each byte, and write data to into ringbuffer
    1. Set the destination address:
      • DMA_TCD_DADDR = address of ringbuffer[0]
    2. Configure buffer size 1024:
      • DMA_TCD_BITER_ELINK = 1024
      • DMA_TCD_CITER_ELINK = 1024
    3. Transfer size 1 byte for source and destination:
      • DMA_TCD_ATTR = 0 (DSIZE = 000 (8-bit), SSIZE = 000 (8-bit))
    4. Each request starts a single transfer:
      • DMA_TCD_NBYTES_ML = 1
    5. DMA source is UART4 data register
      • DMA_TCD_SADDR = 0x400EA007
    6. Source not increment:
      • DMA_TCD_SOFF = 0
    7. Destination incremented:
      • DMA_TCD_DOFF = 1
    8. Set DMA to auto reload when reached the end of the buffer (=ringbuffer mode):
      • DMA_TCD_SLAST = 0
      • DMA_TCD_DLASTSGA = -1024
    9. No interrupt notifications from DMA:
      • DMA_TCD_CSR = 0

  3. Poll and read from the ringbuffer within software in a given interval:
    1. Read Tail once from current DMA-write position into a variable, and consume the data until Head == Tail
    2. On next poll read again until Head == Tail

 

Question:

Is the DMA_TCD_CITER_ELINK the correct register to read the current DMA write position?

pmtMark Butcher Maybe one of you could have a look at my proposed solution?

Outcomes