Using any of ttyS0, ttyTHS1, or ttyTHS2 for user process communication

I need a way to communicate via a UART between a Jetson Nano dev kit and another microcontroller. How do I configure any of ttyS0, ttyTHS1, or ttyTHS2 to do that?

The following configuration of my Jetson Nano dev kit isn’t enough to make it possible.

$ ls -l /dev/ttyS0 /dev/ttyTHS*

crw-rw---- 1 root dialout   4, 64 May 18 09:00 /dev/ttyS0
crw-rw---- 1 root dialout 238,  1 May 18 09:27 /dev/ttyTHS1
crw-rw---- 1 root dialout 238,  2 May 17 16:31 /dev/ttyTHS2

$ cat /etc/issue

Ubuntu 18.04.6 LTS \n \l

$lsb_release -a

No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 18.04.6 LTS
Release:        18.04
Codename:       bionic

$systemctl status serial-getty@ttyS0.service

● serial-getty@ttyS0.service - Serial Getty on ttyS0
   Loaded: loaded (/lib/systemd/system/serial-getty@.service; indirect; vendor p
   Active: inactive (dead) since Wed 2022-05-18 07:21:53 PDT; 2h 16min ago
     Docs: man:agetty(8)
           man:systemd-getty-generator(8)
           http://0pointer.de/blog/projects/serial-console.html
  Process: 4877 ExecStart=/sbin/agetty -o -p -- \u --keep-baud 115200,38400,9600
 Main PID: 4877 (code=killed, signal=TERM)

May 17 16:31:27 rq-b50c systemd[1]: Started Serial Getty on ttyS0.
May 18 07:21:53 rq-b50c systemd[1]: Stopping Serial Getty on ttyS0...
May 18 07:21:53 rq-b50c systemd[1]: Stopped Serial Getty on ttyS0.

$systemctl status nvgetty.service

● nvgetty.service - UART on ttyTHS0
   Loaded: loaded (/etc/systemd/system/nvgetty.service; disabled; vendor preset:
   Active: inactive (dead)

$sudo lsof /dev/ttyS0

lsof: WARNING: can't stat() fuse.gvfsd-fuse file system /run/user/120/gvfs
      Output information may be incomplete.

$ sudo lsof /dev/ttyTHS1

lsof: WARNING: can't stat() fuse.gvfsd-fuse file system /run/user/120/gvfs
      Output information may be incomplete.

$ sudo lsof /dev/ttyTHS2

lsof: WARNING: can't stat() fuse.gvfsd-fuse file system /run/user/120/gvfs
      Output information may be incomplete.

FYI, when the “group” ownership is “dialout”, then the port is available for you to use. If the “group” ownership is “tty”, then the port is already owned by the serial console and should not be touched. The default setting of the ports will be 115200 8N1, and the voltage expected is 3.3V.

If the port at both ends is set correctly, then simply open that file as a regular file and read or write. As a loopback test you can open one of those ports with a serial console program, e.g., minicom or gtkterm, and type in text. If the TX and RX are shorted together, then the port will echo back the text you type in. If the remote port is instead connected, then instead you would run a serial console program at each side. The echo would go to the remote end.

Incidentally, if your user is not a member of group “dialout”, then you will need to access the port as root (using “sudo”), but it is better to add your user to group “dialout”. An example, if your user name is “nvidia”, then you would add like this:
sudo usermod -aG dialout nvidia

1 Like

I’m skeptical, but admit to not fully understanding how Nvidia has modified ubuntu to handle the serial console. Obviously, one could also make the user a member of “tty” and accomplish the same results.
As I showed with the systemctl status for both serial-getty and nvgetty, those services were stopped when I made the attempt. Using lsof I showed that no user space process had any of ttyS0, ttyTHS1, or ttyTHS2 open.

The part I know NVIDIA modified is related to the serial UART driver: The hardware is capable of DMA, and also of using a legacy driver. The legacy driver is “standard”, and when used, produces device special files of the naming convention “ttyS#”; when run instead by the NVIDIA DMA-capable driver, the naming convention becomes “ttyTHS#” (“Tegra High Speed”). The earlier boot stages do not have access to the THS driver, and thus serial console (for earlier boot stages) must use the legacy driver for boot stage serial console messages. Traditionally, the Linux kernel also uses the legacy driver while Linux runs to avoid switching drivers mid-stream (which would perhaps require hardware to reset content and lose something at the moment of switching drivers).

The previous post I made still applies, e.g., is your other end of connection 3.3V? Have you tried loopback with TX and RX tied together?

FYI, “tty” as a group is something only the kernel should own. In part this is a security issue, but consider that the driver itself (along with udev in some cases) is what initially sets permissions. If the device special file is group tty, then it means there is already software intent on using this port. Any other process using this means two processes are fighting over the port. lsof will not show what the driver itself is doing (the driver is not a process unless you think of the kernel as PID 0…lsof won’t show kernel access of the file). A user space process fighting against the kernel’s driver is not a good idea.

Thank you for this informative reply.
From your explanation, can I assume I should NOT attempt to use /dev/ttyS0 (J50 pins 3 and 4 on the Nano dev kit) as a general-purpose UART, regardless of stopping serial-getty and nvgetty services?
Where is the detailed documentation (or forum post) describing how to use /dev/ttyTHS1 (J41 pins 8 and 10 on the Nano dev kit) as a general-purpose UART? And, just what is the purpose of the service “nvgetty”?

In this case ttyS0 was group “dialout”, and so it could be used by you, at least when Linux is running. Here is the “gotcha” though: During boot stages prior to Linux running this might be serial console for the boot loader (I don’t know for sure in this case, but it might be). If this is serial console during boot stages, then it is possible stray activity will occur on the port. Some of that would be random console log to your device, and if your device sends anything, then the boot loader might halt at some point when it says “press any key to…”.

When running in Linux there is technically no reason to not use “ttyS0” if group “dialout”. However, there would likely also be a “ttyTHS#” associated with the same pins. For most cases you could use either (just don’t mix both). In theory there is an advantage of the “ttyTHS#”, but the advantage probably is negligible at lower speeds. Running at the default speed of 115200 probably has some advantage for the Tegra High Speed driver since it uses DMA.

On Linux there are a number of services which start up in some particular order during boot. The very first thing (and technically the only thing the kernel runs) is process ID 1, “init”. “init” will in turn start “systemd”, which is the tool for starting various services. “nvgetty.service” is itself a definition for some mix of what to start and what must be started before it before attempting start. The command line tool “systemctl” is the user interface for manually interacting with “systemd”. One can also directly enter a systemd directive on the kernel’s command line when starting the kernel, but pretty much everything else a user might adjust is via that command or a file edit.

To illustrate, run this command to find related files (these are all plain text):
find /etc/systemd -name 'nvgetty.*'

These three files will probably show up (there might be a difference depending on release):

/etc/systemd/nvgetty.sh
/etc/systemd/system/nvgetty.service
/etc/systemd/system/multi-user.target.wants/nvgetty.service
  • Notice that “nvgetty.service” is the base definition of what that service does, and this is where you would start if looking at it.
  • multi-user.target.wants/nvgetty.service” is how another service says it wants “nvgetty” started before it starts. FYI, “multi-user.target” is the stage of boot where many people can log in, but it is still text-based. Each “getty” (not “TTY” in its name) is a terminal service. “nvgetty” is the terminal service customized by NVIDIA to run a TTY on serial console. Likely it is the same UART that boot stages used, but it isn’t a guarantee (someone could purposely make it differ, but that’d be a mess).
  • Some part of systemd might be told to run the script “nvgetty.sh”. When "wanted by multi-user.target" you will see the script is named as a way to start the getty. This is part of the orchestrated startup of prerequisites of service start and stop.

I can’t answer your last question on documentation for that UART. This is however part of these components:

  • Carrier board model.
  • Device tree (which specifies logically “serial@<hex address>”). This names things like how to route the UART lanes, plus it names possible drivers…you will find it lists both the legacy driver and the THS driver in the “compatible” part.
    • The active device tree can be examined in “/proc/device-tree”. Look at:
      find /proc/device-tree -name "serial@*"
      (then examine the file…it is a plain text reflection of the device tree node which sets up the initial UART)
  • The kernel command line also has options for device tree, but typically you’ll just see tty (getty) setup options there. To examine kernel command line:
    cat /proc/cmdline
    (note that there are typically two tty setup options, one for serial, and the other for standard terminals)

Someone else would have to say which document describes the pins of the Jetson Nano dev kit carrier board. There are documents with just images which show the pins and what it might be named as, but those don’t describe any details.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.