Search by Tags

UART (Linux)

 

Compare with Revision




Subscribe for this article updates

Linux serial port/UART access from userspace is provided through tty-devices under /dev. Depending on driver used to drive the UART, those devices can have different names.


Overview

In our Colibri interface standard, we specify some UARTs across different module types.

Toradex Name Legacy Toradex Name Note
UART_A FF_UART Default console UART, with RTS/CTS, DTR/DSR and RI
UART_B BT_UART With RTS/CTS
UART_C STD_UART

Configuration

From user space, one can use the command line utility stty to configure the serial speed. Then the port can be treated as as a regular file:

# stty -F /dev/ttyLP2 115200
# echo Test > /dev/ttyLP2

Using C, use the struct termios to set the initial baud rate:

#include <termios.h>
...
struct termios tty;
int fd;
int flags = O_RDWR | O_NOCTTY | O_NONBLOCK;
 
fd = open("/dev/ttyS0", flags);
 
tcgetattr(fd, &tty);
 
tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8;
tty.c_cflag |= B115200;
 
if (tcsetattr (fd, TCSANOW, &tty) != 0)
{
    fprintf (stderr, "error %d from tcsetattr", errno);
    return -1;
}

A fixed list of baud rates are pre-defined:

Baud rate Symbol
921600 B921600
460800 B460800
230400 B230400
115200 B115200
57600 B57600
38400 B38400
19200 B19200
9600 B9600
4800 B4800
2400 B2400
1200 B1200

Non-standard baud rate

Vybrid modules

With the following userspace C program one can configure UART custom baud rates:

#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <asm/termios.h>
 
int main(int argc, char* argv[]) {
 
    int retval, fd, speed;
    struct termios2 ntio;
 
    if (argc != 3) {
        printf("Usage: %s /dev/ttyXXX 20000\n", argv[0], argv[0]);                   
        return -1;
    }
 
    speed = atoi(argv[2]);
    fd = open(argv[1], O_RDONLY);
    if (fd < 0) {
        perror("Open");
        return -1;
    }
 
    ioctl(fd, TCGETS2, &ntio);
    ntio.c_cflag &= ~CBAUD;
    ntio.c_cflag |= BOTHER;
    ntio.c_ispeed = speed;
    ntio.c_ospeed = speed;
    retval = ioctl(fd, TCSETS2, &ntio);
    close(fd);
 
    if (retval == 0)
        printf("New baud configured\n");
    else
        perror("ioctl");
 
    return 0;
}

Vybrids UART baud rate depend on the main bus clock. Since the two modules are clocked differently, the modules expose a different minimum and maximum baud rate. The baud rates which can practically be used are as follows:

Module Min-baud Max-baud
Colibri VF50 510 4M
Colibri VF61 640 5M

RS-485

RS-485 uses half-duplex communication, which means that one medium is shared for transmitting and receiving data. Therefore the system needs to control the RS-485 transceiver's transmit mode. Usually the UART RTS signal is used to switch the transmitter on and off. Our modules provide the following support:

i.MX 6 Modules

The driver uses the RTS output to control a RS-485 transceiver (see below).

Tegra Modules

Due to hardware limitations there is no RS-485 transceiver control support.

Vybrid Modules

The Vybrid UART block has built-in support for RS-485 auto RTS for controlling direction of the RS-485 transceiver (see below).

Enabling RS-485 support

Enable the RS-485 feature by either using ioctrl TIOCSRS485 from user space as described in RS-485 Kernel Documentation.
Note that neither i.MX6 nor Vybrid based modules evaluate the delay parameters. i.MX6 based modules do additionally not evaluate the logic level parameters.

Or

Enable it in the device tree by setting linux,rs485-enabled-at-boot-time property.

&uart2 {
    status = "okay";
    linux,rs485-enabled-at-boot-time;
}

Boards

Apalis Evaluation Board

The Apalis Evaluation carrier board does have three regular 9-pin male D-Sub serial connectors for UART1 (RS-232 on bottom X28), UART2 (RS-232 on top X28) and optionally UART2 (RS-422/485 on X55). The UART3 is routed to the IrDA transceiver X30 by default. To route it to the UART1 port instead proceed as follows:

  • Remove jumpers X3 rows 38 and 39 and X6 rows 33 to 40 to break the default UART1 to lower 9-pin male D-Sub and UART3 to IrDA connection.
  • Connect X2-38 to X7-39 and X2-39 to X7-36 to re-route the UART3_TXD and UART3_RXD MXM3 pins to the UART1 lower 9-pin male D-Sub serial connector.

The UART4 is routed to the mezzanine connector X38 by default. To route it to the UART2 port instead proceed as follows:

  • Remove jumpers X3 rows 36 and 37 and X6 rows 29 to 32 to break the default UART2 to upper 9-pin male D-Sub and UART4 to mezzanine connection.
  • Connect X2-36 to X7-32 and X2-37 to X7-29 to re-route the UART4_TXD and UART4_RXD MXM3 pins to the UART2 upper 9-pin male D-Sub serial connector.

UART1 can optionally be connected to an integrated FTDI USB-to-serial chip to conveniently access the debug console. Make sure J10 and J12 Pin 2 and 3 are each jumpered (USB) to route TXD/RXD to the FTDI chip. Then, a simple USB A-B cable is sufficient to get a serial console directly from a computer (through /dev/ttyUSB0 on Linux hosts).

Colibri Evaluation Board

The Colibri Evaluation carrier board does have two regular 9-pin male D-Sub serial connectors for UART_A (lower) and UART_B (upper). The UART_C is routed to the IR by default. To route it to the UART_A port instead proceed as follows:

  • Remove jumpers X11 rows 2, 3, 10 and 11 to break the default UART_A to lower 9-pin male D-Sub and UART_C to IR connection.
  • Connect X10-2 to X12-10 and X10-3 to X12-11 to re-route the UART_C_RXD and UART_C_TXD SODIMM pins to the UART_A lower 9-pin male D-Sub serial connector.

UART_A can optionally be connected to an integrated FTDI USB-to-serial chip to conveniently access the debug console. Make sure J17 and J19 Pin 2 and 3 are each jumpered (USB) to route TXD/RXD to the FTDI chip. Then, a simple USB A-B cable is sufficient to get a serial console directly from a computer (through /dev/ttyUSB0 on Linux hosts).

Iris Carrier Board

  • To use UART_A (FF_UART) on the Iris carrier board a regular 10 pin female IDC to 9-pin male D-Sub RS-232 serial cable adapter (e.g. as used for most former PC motherboards) on X13 is required.
  • To use the UART_B (BT_UART) on the Iris carrier board one can use the same regular RS-232 serial adapter from X13 on X14 as the RXD/TXD and RTS/CTS pins share the same connector layout.
  • To use UART_C (STD_UART) on the Iris carrier board one can use X14 pin 1 as UART_C_RXD and pin 7 as UART_C_TXD.

For more information, see also Iris Carrier Board Peripherals.

Ixora Carrier Board

  • To use UART1 on the Ixora carrier board a regular 10 pin female IDC to 9-pin male D-Sub RS-232 serial cable adapter (e.g. as used for most former PC motherboards) on X22 is required.
  • To use the UART2 on the Ixora carrier board one can use the same regular RS-232 serial adapter from X22 on X21 as the RXD/TXD and RTS/CTS pins share the same connector layout.
  • To use UART3 on the Ixora carrier board one can use X21 pin 1 as UART3_RXD and pin 7 as UART3_TXD.
  • UART4 is only available as TTL level on the extension connector X27.

Modules

Apalis i.MX6

Toradex Name NXP/Freescale Name Device
UART1 UART1 /dev/ttymxc0
UART2 UART2 /dev/ttymxc1
UART3 UART4 /dev/ttymxc3
UART4 UART5 /dev/ttymxc4

Note: The i.MX6 UARTs can be switched between DTE and DCE mode. The Apalis i.MX6 module's pin assignment is designed for DTE mode.

Note: For V1.0A modules the assignement is different. UART3 and UART4 are swapped. e.g. UART3 is implemented with the i.MX6 UART5. All RX/TX lines are swapped and the UARTs have to be used in DCE mode to get the RX/TX functionality on the correct pins.

Apalis T30

Toradex Name NVIDIA Name Device
UART1 UART1/UARTA /dev/ttyS0
UART2 UART4/UARTD /dev/ttyHS3
UART3 UART2/UARTB /dev/ttyHS1
UART4 UART3/UARTC /dev/ttyHS2
- UART5/UARTE

Apalis TK1

Toradex Name NVIDIA Name Device Note
UART1 UART1/UARTA/UA3 /dev/ttyS0 RX/TX and RTS/CTS only
UART2 UART2/UARTB/IR3/UB3 /dev/ttyTHS1
UART3 UART3/UARTC/UC3 /dev/ttyTHS2
UART4 UART4/UARTD/UD3 /dev/ttyTHS3
- 6x Kinetis K20 Companion MCU UARTs - not supported in regular Embedded Linux BSP

Colibri i.MX6

Toradex Name Legacy Toradex Name NXP/Freescale Name Device
UART_A FF_UART UART1 /dev/ttymxc0
UART_B BT_UART UART2 /dev/ttymxc1
UART_C STD_UART UART3 /dev/ttymxc2

Note: The i.MX 6 UARTs can be switched between DTE and DCE mode. The Colibri i.MX6 module's pin assignment is designed for DTE mode.

Colibri i.MX7

Toradex Name Legacy Toradex Name NXP/Freescale Name Device Notes
UART_A FF_UART UART1 /dev/ttymxc0
UART_B BT_UART UART2 /dev/ttymxc1 FreeRTOS/Cortex-M4 default console
UART_C STD_UART UART3 /dev/ttymxc2

Note: The i.MX 7 UARTs can be switched between DTE and DCE mode. The Colibri i.MX7 module's pin assignment is designed for DTE mode.

Colibri Txx

Toradex Name Legacy Toradex Name NVIDIA Name Device
UART_A FF_UART UART1 /dev/ttyS0
UART_B BT_UART UART4 /dev/ttyHS3
UART_C STD_UART UART2 /dev/ttyHS1
- - UART3
- - UART5

By default, the first serial port uses the compatible 8250 driver to show a serial console (since NVIDIA's HS driver does not support a serial console).

[    2.702878] Serial: 8250/16550 driver, 1 ports, IRQ sharing disabled
[    2.703164] serial8250.0: ttyS0 at MMIO 0x70006000 (irq = 68) is a XScale
[    3.377362] console [ttyS0] enabled
[    3.381016] tegra_uart.1: ttyHS1 at MMIO 0x70006040 (irq = 69) is a 16550
[    3.387879] Registered UART port ttyHS1
[    3.391734] tegra_uart.3: ttyHS3 at MMIO 0x70006300 (irq = 122) is a 16550
[    3.398681] Registered UART port ttyHS3
[    3.402550] Initialized tegra uart driver

Resources used by serial port on T20 devices:

root@colibri_t20:~# cat /proc/interrupts
 68:     100052          0         PPI  serial
 69:         40          0         PPI  tegra_uart_1
...
122:         47          0         PPI  tegra_uart_3

root@colibri_t20:~# cat /sys/kernel/debug/clock/clock_tree
   clock                          state  ref div      rate
--------------------------------------------------------------.
...
   clk_m                          on     20           13000000
...
      uartd                       on     1   1        13000000
      uartb                       on     1   1        13000000
...
      pll_p                       on     11  x16.6..  216000000
...
         uarta                    on     1   1        216000000

Colibri VFxx

Our Vybrid based modules provide UART access through a Vybrid specific LP UART serial driver. The driver currently supports baud rates from 600 Baud up to 921600 Baud and can handle RTS/CTS hardware flow control.

Toradex Name Legacy Toradex Name NXP/Freescale Name Device RTS/CTS support FIFO size
UART_A FF_UART UART0 /dev/ttyLP0 Yes 16
UART_B BT_UART UART2 /dev/ttyLP2 Yes 8
UART_C STD_UART UART1 /dev/ttyLP1 Yes (non-standard pinmux) 16
- - UART3 /dev/ttyLP3 No 8
- - UART4 /dev/ttyLP4 Yes (non-standard pinmux) 8

Note: UART3 and UART4 are not enabled by default on our standard images and need device tree modifications to be enabled.

[    0.232712] 40027000.serial: ttyLP0 at MMIO 0x40027000 (irq = 20, base_baud = 5210526) is a FSL_LPUART
[    0.840359] 40028000.serial: ttyLP1 at MMIO 0x40028000 (irq = 21, base_baud = 5210526) is a FSL_LPUART
[    0.856812] 40029000.serial: ttyLP2 at MMIO 0x40029000 (irq = 22, base_baud = 5210526) is a FSL_LPUART

Especially on higher baud rates and the slower Colibri VF50, overruns (and hence loss of characters) can happen. Check the tty driver statistics if you are suffering from those issues:

# cat /proc/tty/driver/fsl-lpuart
serinfo:1.0 driver revision:
0: uart:FSL_LPUART mmio:0x40027000 irq:20 tx:6131 rx:150 RTS|DTR
1: uart:FSL_LPUART mmio:0x40028000 irq:21 tx:0 rx:0
2: uart:FSL_LPUART mmio:0x40029000 irq:22 tx:121426 rx:110495 oe:19 RTS|DTR

To ensure that no character are lost, use hardware flow control signals such as RTS/CTS or lower baud rates.

Enabling/disabling DMA

The current driver has a weak DMA implementation, which can lead to lock ups, especially on the RX side. The non-DMA (PIO) mode is much more robust, and thanks to the hardware FIFO also quite efficient. The easiest way to disable the DMA mode is to overwrite the dma-names property (see also Device Tree Customization):

--- a/arch/arm/boot/dts/vf-colibri-eval-v3.dtsi
+++ b/arch/arm/boot/dts/vf-colibri-eval-v3.dtsi
@@ -254,6 +254,7 @@
 
 &uart0 {
        status = "okay";
+       dma-names = "", "";
 };
 
 &uart1 {

Releases after V2.5 Beta 1 have a kernel argument to enable/disable DMA. The DMA is by default disabled, to re-enable UART DMA use:

setenv defargs '${defargs} fsl_lpuart.nodma=0'