Serial communication between Jetson nano and Arduino through GPIO

For a future project I’m planning to use Jetson nano as a companion computer to Ardupilot controller. For that I need to make use of the UART in the J41.8 and J41.10 pins.

As a sanity check I was trying to use an Arduino Uno to read/write to Jetson Nano.

I found this tutorial, which also provides some code examples on how to make it work.

Given that the UART in Jetson nano works at 3.3 volts and arduino at 5V, I using a Logic Level converter.

Nevertheless there’s still something I can’t quite figure out which is, what device should I connect too?

The only tty devices I can find registered are the following (gotten with dmesg):

[    0.001850] console [tty0] enabled
[    1.055849] console [ttyS0] disabled
[    1.055922] 70006000.serial: ttyS0 at MMIO 0x70006000 (irq = 63, base_baud = 25500000) is a Tegra
[    1.056028] console [ttyS0] enabled
[    1.057075] 70006040.serial: ttyTHS1 at MMIO 0x70006040 (irq = 64, base_baud = 0) is a TEGRA_UART
[    1.057608] 70006200.serial: ttyTHS2 at MMIO 0x70006200 (irq = 65, base_baud = 0) is a TEGRA_UART

Any suggestion would be gratefully appreciated!

hello raven.cv,

you may access Nano Product Design Guide and check UART chapter for [Table 11-6. Jetson Nano UART Pin Description].
these UARTs were register to ttyTHS* serial port during kernel initialization stage.

you may also look into device tree for the mappings between serial ports and uarts.
for example,
$L4T_Sources/r32.4.3/T210/Linux_for_Tegra/source/public/hardware/nvidia/soc/t210/kernel-dts/tegra210-soc/tegra210-soc-base.dtsi

        uarta: serial@70006000 {
        uartb: serial@70006040 {
...

Hi Jerry,

Thank you for you answer. Although I’m a bit lost.

So, from the Nano Product Design Guide UART #1 (pins 203 and 205) is the one being used which refers to the 40-pin expansion.
Are you saying that ttyTHS* are actually mapped to the UART #1? As it stands there are always 2, ttyTHS1 and ttyTHS2. Is that referring somehow to the TXD and RXD UART pins?

hello CVicente,

for example,
according to kernel messages,

[    1.543081] 70006040.serial: ttyTHS1 at MMIO 0x70006040 (irq = 64, base_baud = 0) is a TEGRA_UART

and you may also refer to device tree definition,

uartb: serial@70006040 {

this means UART-B has register to ttyTHS1 for the usage,
UART-B is using uart2_tx_pg0/uart2_rx_pg1. which is pin-203, 205 on the 40-pin expansion header.

I just use USB to USB C to connect my jetson nano and arduino due and it works perfectly, just had to make the ttyACM0 linked to arduino by using udev rules files but you shouldn’t need that :D
Be sure to do : sudo apt-get install libusb-1.0

You can use : dmesg | grep ttyACM or usb-devices to find your arduino if wired on USB.

Here is my code (I tried a lot of ways and this is the most robust for nano<->arduino UART) :

Initialization :

    tcgetattr(due, &port_options);	// Get the current attributes of the Serial port
    due = open("/dev/ttyACM0", O_RDWR | O_NONBLOCK);//O_NOCTTY);//
    tcflush(due, TCIFLUSH);
    tcflush(due, TCIOFLUSH);
    if (due == -1){perror("Could not open Arduino");ArduinoSerial=false;getdue::PreDue();}
    else{
        ArduinoSerial=true;
        port_options.c_cflag &= ~PARENB;            // Disables the Parity Enable bit(PARENB),So No Parity
        port_options.c_cflag &= ~CSTOPB;            // CSTOPB = 2 Stop bits,here it is cleared so 1 Stop bit
        port_options.c_cflag &= ~CSIZE;	            // Clears the mask for setting the data size
        port_options.c_cflag |=  CS8;               // Set the data bits = 8
        port_options.c_cflag &= ~CRTSCTS;           // No Hardware flow Control
        port_options.c_cflag |=  CREAD | CLOCAL;                  // Enable receiver,Ignore Modem Control lines
        port_options.c_iflag &= ~(IXON | IXOFF | IXANY);          // Disable XON/XOFF flow control both input & output
        port_options.c_iflag &= ~(ICANON | ECHO | ECHOE | ISIG);  // Non Cannonical mode
        port_options.c_oflag &= ~OPOST;                           // No Output Processing
        port_options.c_lflag = 0;               //  enable raw input instead of canonical,
        port_options.c_cc[VMIN]  = VMINX;       // Read at least 1 character
        port_options.c_cc[VTIME] = 0;           // Wait indefinetly
        cfsetispeed(&port_options,BAUDRATE);    // Set Read  Speed
        cfsetospeed(&port_options,BAUDRATE);    // Set Write Speed
        int att = tcsetattr(due, TCSANOW, &port_options);
        if (att != 0 ){printf("ERROR in Setting Arduino port attributes");}
        else{printf("SERIAL DUE Port Good to Go.\n");}
        tcflush(due, TCIFLUSH);
        tcflush(due, TCIOFLUSH);
        //getdue::ReadDue();
    }

To read from arduino :

    memset(serial_message, 0, 255);
    tcflush(due, TCIOFLUSH);
    rx_length = read(due, (void*)rx_buffer, VMINX);
    serial_message[nread] = rx_buffer[0];
    printf("Event %d, rx_length=%d, Read=%s\n",  nread+1, rx_length, rx_buffer );

To write to arduino :

    p_tx_buffer = &tx_buffer[0];
    for(int i=0;i<(int)arduinoIn.length();i++){
        *p_tx_buffer++ = arduinoIn[i];
    }
    if (due != -1){
        count = write(due, &tx_buffer[0], (p_tx_buffer - &tx_buffer[0]));		//Filestream, bytes to write, number of bytes to write
        if (count < 0){perror("Arduino UART TX error\n");}
    }

Hope I could save you some time :)
Regards,
Planktos

Hi Jerry,

I do understand why you’re able to map ttyTHS1 to uartb.

uartb: serial@70006040 {
                compatible = "nvidia,tegra114-hsuart";
                reg = <0x0 0x70006040 0x0 0x40>;
                reg-shift = <2>;
                interrupts = <0 37 0x04>;
                iommus = <&smmu TEGRA_SWGROUP_PPCS>;
                dmas = <&apbdma 9>, <&apbdma 9>;
                dma-names = "rx", "tx";
                clocks = <&tegra_car TEGRA210_CLK_UARTB>,
                        <&tegra_car TEGRA210_CLK_PLL_P>;
                clock-names = "serial", "parent";
                resets = <&tegra_car TEGRA210_RST_UARTB>;
                reset-names = "serial";
                nvidia,adjust-baud-rates = <115200 115200 100>;
                status = "disabled";
        };

But from where did you map UART-B to uart2_tx_pg0/uart2_rx_pg1.

Having that said, from your example it seems that ttyTHS1 could be use to open a serial connection. Is that right? If that’s the case (since I’ve tried it already), it might be just a case of post miss-configuration on my side.

Although, in a previous attempt to use serial port using TTL to USB Serial Cable with a Windows machine (following this example), I did try to disable the serial console by issuing:
systemctl stop nvgetty systemctl disable nvgetty
$ udevadm trigger

Not sure if that’s all it disables.

Hi Planktos,

Thank you very much for your answer and the suggestion, although I’m really looking for only using the GPIO pins from Jetson nano and rx/tx pins from arduino. As I want to communicate with a Arduino Flight Controller serial port, I want to be sure that I’m able to use GPIO in a more controlled environment first.

you may access Pinmux spreadsheets for reference.
or,
you could disassembler the dtb file into text file for checking.
for example, $ dtc -I dtb -O dts -o output.txt tegra210-p3448-0002-p3449-0000-b00.dtb

                        uart2_tx_pg0 {
                                nvidia,pins = "uart2_tx_pg0";
                                nvidia,function = "uartb";
...
                        uart2_rx_pg1 {
                                nvidia,pins = "uart2_rx_pg1";
                                nvidia,function = "uartb";

Hi Jerry,

Lovely. Many thanks for the reference. By the way could you point me to the document describing the uart configuration parameters, e.i. how many bits, if there are stop bits, parity, etc?

I’m also wondering if I need to use RTS/CTS.

please access Tegra X1 TRM, you should check Chapter-36 for the details of UART controller.

Hi Jerry,

Thank you very much! I’ll have a look.

So… I’ve worked with Serial ports several in various circumstances… specially when working with XBee radios. Now, all that time working with XBee radios and using FTDI drivers should had rang a bell sooner… but noooo! I couldn’t by the life of me remember to add the user I was working with on the Jetson nano to the “dialout” group!

Yes… that was just it… I mean… I don’t get clear data back and forth from the Arduino to the Jetson nano (more on that later)… but at least there’s some data moving around.