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.

AM623: UART: how to send more than 64 bytes without gaps

Part Number: AM623
Other Parts Discussed in Thread: SK-AM62

Dear TI Support Team,

Our AM6232 linux-based devices are using up to four UART interfaces for communicating with external peripherals at a baud rate of 921600. The communication is telegram-based, with telegrams up to 500 bytes in length. The receiver expects a continuous data stream with a maximum gap of 10 µs between bytes.

During measurements on the TX line, we observed transmission pauses of 10–40 µs when sending data blocks larger than 64 bytes. These gaps cause issues on the receiver side. We suspect the cause is the UART FIFO running empty and waiting for the driver to refill it. Adjusting the TX threshold via the device tree did not resolve the issue.

We are considering using DMA to ensure continuous transmission. Could you please advise:

  1. What UART and DMA settings would you recommend for this use case?
  2. How should DMA be configured in the device tree for UART on AM6232?
  3. Are there known limitations or performance considerations when using DMA with UART on AM62x?

Note: Our previous AM33xx-based product handled this use case without any issues.

Thank you in advance for your support.

Best regards,
Andreas Martin

Example: 17us gap after transmission of 64 bytes

  • Hi Andreas,

    Using DMA on UART transfers is not recommended, the DMA channel setup time is not trivial, so DMA won't be helpful for UART.

    Which SDK/kernel version do you use on AM6232?

  • We are using a Vanilla 6.1.1xx kernel. Currently 6.1.141.

    We are open to any solution and not focused on using DMA. Our previous AM33xx device used DMA for this usecase and we never had such timing issues there.

    I also tried to set tx-threshold via device-tree, but I don't see a difference in the behaviour.

  • Hi Andreas,

    I will try to see if I can replicate the issue SK-AM62 EVM with SDK9.0 which is based on kerenl 6.1.32, then look into it.

  • Hi Andreas,

    I can replicate the issue on EVM, and the following kernel patch can remove the gap. However, the performance is not optimal, it appears with this patch the UART TX interrupts are generated when every 3 bytes are transmitted. I will continue working on it.

    diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c
    index cf68d9f6924f..69c38e8351af 100644
    --- a/drivers/tty/serial/8250/8250_omap.c
    +++ b/drivers/tty/serial/8250/8250_omap.c
    @@ -89,7 +89,7 @@
     #define OMAP_UART_WER_MOD_WKUP 0x7f
     #define OMAP_UART_TX_WAKEUP_EN (1 << 7)
     
    -#define TX_TRIGGER     1
    +#define TX_TRIGGER     48
     #define RX_TRIGGER     48
     
     #define OMAP_UART_TCR_RESTORE(x)       ((x / 4) << 4)
    @@ -482,7 +482,7 @@ static void omap_8250_set_termios(struct uart_port *port,
            up->fcr |= TRIGGER_FCR_MASK(priv->tx_trigger) << OMAP_UART_FCR_TX_TRIG;
            up->fcr |= TRIGGER_FCR_MASK(priv->rx_trigger) << OMAP_UART_FCR_RX_TRIG;
     
    -       priv->scr = OMAP_UART_SCR_RX_TRIG_GRANU1_MASK | OMAP_UART_SCR_TX_EMPTY |
    +       priv->scr = OMAP_UART_SCR_RX_TRIG_GRANU1_MASK |
                    OMAP_UART_SCR_TX_TRIG_GRANU1_MASK;

  • Hi Andreas,

    Other than 921600, do you use any other baud rate in your project?

  • Hi Andreas,

    Please apply the following kernel patch to resolve the UART TX gap issue. The TX_TRIGGER value set in this patch might have to be reduced more if you use higher baud rate than 921600.

    diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c
    index cf68d9f6924f..c41f8d617f36 100644
    --- a/drivers/tty/serial/8250/8250_omap.c
    +++ b/drivers/tty/serial/8250/8250_omap.c
    @@ -89,7 +89,7 @@
     #define OMAP_UART_WER_MOD_WKUP	0x7f
     #define OMAP_UART_TX_WAKEUP_EN	(1 << 7)
     
    -#define TX_TRIGGER	1
    +#define TX_TRIGGER	60
     #define RX_TRIGGER	48
     
     #define OMAP_UART_TCR_RESTORE(x)	((x / 4) << 4)
    @@ -482,7 +483,7 @@ static void omap_8250_set_termios(struct uart_port *port,
     	up->fcr |= TRIGGER_FCR_MASK(priv->tx_trigger) << OMAP_UART_FCR_TX_TRIG;
     	up->fcr |= TRIGGER_FCR_MASK(priv->rx_trigger) << OMAP_UART_FCR_RX_TRIG;
     
    -	priv->scr = OMAP_UART_SCR_RX_TRIG_GRANU1_MASK | OMAP_UART_SCR_TX_EMPTY |
    +	priv->scr = OMAP_UART_SCR_RX_TRIG_GRANU1_MASK |
     		OMAP_UART_SCR_TX_TRIG_GRANU1_MASK;
     
     	if (up->dma)
    @@ -1472,7 +1476,7 @@ static int omap8250_probe(struct platform_device *pdev)
     
     	up.port.regshift = OMAP_UART_REGSHIFT;
     	up.port.fifosize = 64;
    -	up.tx_loadsz = 64;
    +	up.tx_loadsz = TX_TRIGGER;
     	up.capabilities = UART_CAP_FIFO;
     #ifdef CONFIG_PM
     	/*
    diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
    index a17803da83f8..20a79db56618 100644
    --- a/drivers/tty/serial/8250/8250_port.c
    +++ b/drivers/tty/serial/8250/8250_port.c
    @@ -1938,8 +1941,12 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir)
     			status = serial8250_rx_chars(up, status);
     	}
     	serial8250_modem_status(up);
    -	if ((status & UART_LSR_THRE) && (up->ier & UART_IER_THRI)) {
    +	if (((status & UART_LSR_THRE) && (up->ier & UART_IER_THRI)) ||
    +			((iir & UART_IIR_ID) == UART_IIR_THRI)) {
     		if (!up->dma || up->dma->tx_err)
     			serial8250_tx_chars(up);
     		else if (!up->dma->tx_running)
    

  • Sorry for the late response. I had problems with my TI account.

    Thank you for the patch. When using our maximum baudrate 921600 on four interfaces, it was still not stable but much better. I had to reduce TX_TRIGGER to 48. With this value the device successfully finished a long running stress test.

    Two questions regarding patch handling:

    1. Will this patch be sent to upstream kernel?
    2. Besides others, the value of TX_TRIGGER should be controlled by device-tree settings. For example there are settings like tx-threshold, which in my understanding does the same but is not implemented in 8250 omap driver. Why are the settings hardcoded?
  • Hi Andreas,

    No, this patch is not the proper implementation, as you have already noted, so it won't be sent to kernel upstream.

    There are multiple issues in implementing it easily:

    Blindly setting the TX threshold trigger (by hardcoding in driver as my patch or in devicetree) is not optimal for use cases that the UART receivers don't care about the gap, since it doesn't fully utilize the TX FIFO and generates more TX interrupts.

    As you have already found, the TX threshold trigger value has to be adjusted based on the UART use cases, the number of UART ports running in parallel and the baud rate. Setting the value in devicetree is not a solution, since the UART use case could change in Linux runtime.

    Another problem is that this threshold triggers UART threshold interrupts, which is not handled in kernel 8250 framework in general. 8250 port driver does have function serial8250_tx_threshold_handle_irq() to handle this threshold interrupt, but it is currently only used for UART type ALTR_16550_*.

    I think the real problem is in the UART devices which has a fixed/tight RX timeout value. In your case, 10us is basically just one byte time at 921600 baud. Most of UART controllers have bigger default RX timeout value and it is configurable. For example, the UART module on AM62x has the default TX timeout to be about 5-bytes time, and it can be adjusted in UART registers.