Serial communication between Jetson TX2 and AT90CAN128 using UART1 on J21 header (how to use )


Host device: Jetson TX2 with Jetpack 4.2 (Ubuntu 18.04 LTS up & running)
Target device: A custom PCB with AT90CAN128 micro-controller by Mircochip .

Use case: Setting up bi-directional communication between the two, using UART1 on TX2 (or any other suitable uart) & UART0 on AT90CAN128 to pass on some string values.

PCB description: A simple PCB with the above µC, a JTAG port (for debugging), an USB port (for serial monitoring) connected to UART1 of µC, a voltage regulator from 12V to 5V, a reset button, and some headers for sensors and communication.
The µC is programmed for serial communication using Atmel Studio, to receive and send strings via UART (Already checked via communication between µC & Arduino). So, µC side is already taken care of for receiving and sending strings via serial communication.

Doubt: 1) I am new to Jetson & Linux (Ubuntu) world, so I don’t know how to use the basic communication peripherals on TX2 (UART, I2C, SPI, I2S). How to program the TX2 so that it can send and receive strings via UART? Using a compiler (Qt? or something from Nvidia?) or any other way, no idea.

Seen some videos and forums, but they setup the serial communication via the USB port on TX2, but I want to do it via the J21 header or any other suitable UART header on TX2.

2) Also in general, how can I use these peripherals to the basic level C programming for any use case (just like Arduino IDE or Atmel Studio), where I want to setup communication simultaneously using all peripherals (I2C, SPI, UART, I2S)? What do I have to install or change in Ubuntu (or TX2, I’d say)? Do I have to program in different language?

Would be great if someone can guide me through this or post relevant threads.


I can’t answer all of your questions (this is almost entirely about the serial UART part), but this might help to start.

One serial port is already taken for use by the serial console. That port has two logical names, which are also files. The serial console is “/dev/ttyS0” or “/dev/ttyTHS0”. The naming depends on which driver is being used by the hardware. Because of a need for compatibility with U-Boot, the result is that actual serial console is “/dev/ttyS0”. For other UARTs you would probably instead use the “ttyTHS#” name. The “ttyTHS#” (see “ls /dev/ttyTHS*” to see what is there) uses the “Tegra High Speed” driver instead of the older 8250 style driver.

On the TX2 the J17 connector is probably what you want to use. This is “/dev/ttyTHS2” and is a standard layout for serial UART ports.

Every UART essentially talks to another UART. The TX of one goes to the RX of the other, and vice versa. Flow control is not always used, but if it is, then CTS of one talks to DTS of the other.

If you were to test the J17 serial port on the TX2 via loopback, then you might do the following:

  • Wire the connector's TX to its own RX.
  • Optionally wire the connector's CTS to its own RTS.
  • Point a serial terminal program at "/dev/ttyTHS2", e.g., I like "gtkterm", but a lot of people use "minicom".

If a port is in loopback and working, then whatever you type in should be echoed back even with the serial terminal not providing local echo (if local echo is on, then you’d see two copies of everything you type). When you look at the settings in the serial terminal, then you know those settings work with that serial UART. Both sides of the communication need to be using the same settings. Loopback is a good test because a UART will never disagree with itself as to the settings being used.

A serial terminal simply echos characters you type to the TX and listens for characters received on the RX.

FYI, this port uses a 3.3V logic level. If your device uses any other level, then you need a level shifter.

Typically one has as a minimum setting the speed, number of bits, and stop bits. Serial console uses 115200 8N1. This means 115200 bit/sec, 8 bits, no parity, and 1 stop bit. If you were to increase the speed you likely need 2 stop bits.

If you want to you can install “gtkterm” with “sudo apt-get install gtkterm”. You could then point it at J17 with 115200 8N1 settings via:

gtkterm -b 8 -t 1 -s 115200 -p /dev/ttyTHS2

Any programming which writes to a file or reads from a file can write or read to the UART. There may be cases where you need permission to do so, but otherwise it is rather simple and uncomplicated. FYI, the files in “/dev” are not real files, they are “pseudo” files. This means the file is actually the result of a running driver, and does not exist on the hard drive. Extra commands to control a driver associated with a pseudo file are custom to the particular driver, but in general any custom abilities are done through an “ioctl” call. The rest is just ordinary file read and write type lines. The language you use to do this is unimportant (it could be C, C++, Python, Java…anything).

Hi linuxdev,

Thanks for the support, cleared out some of my doubts!

I installed gtkterm, but when I open it, it says “Cannot open /dev/ttyS0: Permission denied”.
How do I get access?

If /dev/ttyTHS2 is the UART on J17, then which ports are /dev/ttyS0, /dev/ttyTHS1, /dev/ttyTHS3?

I tried the following:

The loopback test worked. Then I opened the port by

gtkterm -b 8 -t 1 -s 115200 -p /dev/ttyTHS2

and connected the TX to RX of Arduino and RX to TX of Arduino which in turn was connected to a Windows PC via normal USB. Uploaded the Software Serial example on Arduino.
Note: The TX and RX pins on Arduino are the ones mentioned in the C code example and not the TX, RX named on Arduino. (10,11: TX,RX in my case). Keeping the baudrate 115200 on serial monitor and changing in the code as well.

So, the communcation was like, whatever I typed on gtkterm, it was reflected on the serial monitor of PC, and vice versa.

I got a step closer, thanks to you.

What I would like to know now is, how can I program on the Jetson side (opening the port and reading and writing values on it), so whenever I open the code and run it, I can monitor the communication.

Lets say the communication is something like:
An actuator and sensor are connected and controlled by Arduino and if sensor senses something, Arduino sends the signal to Jetson, and Jetson in turn sends a stop signal (some string) to Arduino for stopping the actuator. The code on Arduino is taken care of.
I would like to know, how to code on Jetson for reading and writing serial values on its own.

Using some compiler?
Do I have to open the specific port (/dev/ttyTHS2) everytime before I run the code, I mean enable it? Or is it possible to write in it the code itself?

I don’t know how of much this is understandable, but I thank you for your efforts!

Wording might become a bit confusing, so I’m going to make a distinction here before I go on…

Every serial UART is a piece of hardware. A console is a text mode login shell for end users to talk to the operating system (a “login” is key). A serial console is a console (keyboard input and display of output) over a UART. When I say serial console I mean much more than when I say UART. If I say a serial console program, I’m talking about a program which can talk to a serial UART by connecting the keyboard to write to the UART and having an output area to show what the UART has sent to you…but whether or not this is a login session is actually unrelated. You need a serial console program (like gtkterm) to talk to a serial login, but a serial console program can also be used with more than a serial login…two people could type remote messages to each other without the shell interpreting it as Linux commands. An old fashioned telephone modem could serialize data, turn it into tones at one end, and then turn tones back into characters at the other end (each end has a UART). Loopback is you talking to yourself, serial console login is you talking to the operating system. J17 (/dev/ttyTHS2) is wide open and not bound to anything…it is free to use.

Don’t use “/dev/ttyS0” or “/dev/ttyTHS0” (same hardware, different driver): This already has software talking to it. You could connect another serial UART to the J21 TX and RX and talk to the TX2 as if you are logged in locally there. You’d use a serial UART on your host PC, not locally.

There are three issues to consider:

  • As previously mentioned ttyS0 is already in use and you don't want to be sending gibberish to a login prompt (which is what happens if you talk to ttyS0 locally from the is quite different to talk to this with a serial console program from a remote host). Use J17 (/dev/ttyTHS2).
  • Each "/dev/" file has an owner and a group, and permissions for the owner and permissions for the group. If I look at permissions for both ttyS0 and ttyTHS2 I see they differ, but in all cases a regular user (someone who isn't root), and who is not a member of the group (tty or dialout) will be completely denied access (I add my serial users to group "dialout" rather than operating as root):
    # ls -l /dev/ttyS0 /dev/ttyTHS2
    crw--w---- 1 root tty       4, 64 Jul 10 09:42 /dev/ttyS0
    crw-rw---- 1 root dialout 238,  2 Jul 10 09:35 /dev/ttyTHS2
  • The settings on both ends of the UART must match. Drivers cannot detect mismatches and only report what they've been told to do. Often a mismatch results in not output at all, but sometimes gibberish makes its way through.

In terms of permissions, if your user name is “ubuntu”, then you can add a supplemental membership for group “dialout” to user “ubuntu” via this:

sudo usermod <b>-a -G dialout</b> ubuntu

Although there might conceivably be a reason to add a developer to group “tty”, in this case such an addition would be a mistake sense you don’t want to randomly send commands to a UART which is already bound to a function.

Incidentally, using the GPU requires being root or being in group “video”. Regular users using CUDA would be added in the same way by making those users a member of group “video”. To see current members:

grep video /etc/group

Note that an Arduino is no different than a serial console program, except it isn’t someone typing messages…some program is running. If the previous three conditions are met, then communications should work. Sometimes people don’t realize the wiring matters though, and long wires, lack of twisted pair and shielding, so on, can cause failure (short wires typically don’t care, but I like using ethernet cable for anything more than a few inches since it is quality twisted pair). Above speed 115200 you will need two stop bits, not one. I’m not sure if the Arduino would allow setting two stop bits or not.

When you echo correctly in loopback mode, then you validate the port is operating correctly at those settings, and if another UART is mated to the connector at the same settings, then it should work. The other UART would have to also use the same 3.3V TTL logic level…other levels might cause damage or simply not work. Generally you won’t get damage by using 3.3V with 1.8V, but it also won’t work.

Any C program on the TX2 would open “/dev/ttyTHS2” for read/write. Any special settings would be via IOCTL calls. The loopback testing verifies if the port is able to operate with those specific settings.

C programming examples for a serial UART are very common on google searches since UARTs have been around longer than the PC. Just a general search:…33i299l2j33i160.795.8952…9092…0.0…0.87.1776.30…0…1…gws-wiz…0…0j0i131j0i22i30j0i8i13i30j33i22i29i30.a5XiR1KOrZE

This is one I’ve used before:

You’ll find mention of different tools for setting a serial port speed, but mostly you won’t need to use those. You’d use those to set values on command line from boot software, but your C program will probably be setting things up instead (e.g., speed). Note that some of those tools won’t show what you expect, and you have to make a distinction that UARTs are not plug-n-play devices…there is no way for drivers to actually query most serial UARTs for their settings. When you use a command to make or query a setting, then you are asking the driver what it is doing, and if the UART doesn’t work with those settings, then the driver won’t know. Loopback tests if the driver actually works with those settings. The command line parameters used with gtkterm result in IOCTL calls to set the port settings prior to data being sent/received. Your program can make similar calls.

There are other serial UARTs, but some may be bound to a function, e.g., talking to the bluetooth or routed to the M.2 slot. Others may not be used, but also might not have any kind of external wiring available without using a different carrier board. I couldn’t tell you what all of the other UARTs are connecting to.