I don’t know what failed for you, but perhaps some general UART information will help. This isn’t in any specific order.
The default UART requires a 3.3V logic level. There are many UART ports out there which use different levels, e.g., 1.8V or 5V. The RS-232 uses a wide range of values. A 1.8V device would not likely damage the Nano, but higher voltanges than 3.3V might. So be careful that the UART you connect to this is also rated at 3.3V.
Serial UARTs just convert bytes into a series of bits over time. One side sends bits, the other side reassembles the bits as bytes.
UARTs also typically support multiple forms of flow control. Software flow control does not require any extra wiring beyond the TX and RX and ground wires. CTS/RTS flow control has a Clear To Send wire and a Request To Send wire, and these work together if and only if the UARTs were set to use this. You could wire the physical connections and not worry since any UART told to not use CTS/RTS flow control would ignore those wires, and in cases where this hardware flow control is used, then the wires would be used.
Each UART has only a very limited buffer space. This is one why flow control is important (software or hardware). If you were to keep sending before the other end can use the data, then data is lost.
Each UART can be told to use a different number of bits for the byte size. The default is 8-bits for 1-byte.
Some form of error detection is available in the form of a parity bit. This is sent separately from your data and is not visible to the consumer or producer of data.
Stop bits are extra bits set up specially at the end of the actual data and parity to tell the UART about the end of a byte. The default is one stop bit, but in some cases two stop bits are used.
The overall specification “115200 8N1” means baud rate of 115200 (sort of like bit rate, but adjusts for parity and stop bits rather than just data bits), 8 bits per byte, no parity, and one stop bit. This is what the serial console uses and is common.
Above 115200 speed you might need to use two stop bits. This is a limitation of the Jetson hardware, not UARTs in general.
When the device driver loads for a UART a device special file is created in “/dev”. If the more generic driver is used, and not renamed by some part of the system, then it would be number as “/dev/ttyS#” (where ‘#’ starts at 0). If the NVIDIA DMA-capable high speed driver is used instead, then the name will be something like “/dev/ttyTHS#” (the “THS” stands for “Tegra High Speed” and is more efficient). Note that one can have both a legacy driver and a THS driver available simultaneously, but it would be undefined as to what would happen if you use both. As an example, “/dev/ttyTHS2” and “/dev/ttyS2” refer to the same UART/hardware, but the S2 version is handled by the legacy generic driver, while the THS version uses the NVIDIA driver.
The serial “/dev” files actual like a file…you can cat the file to read it, you can echo and redirect to write to it. Flow control may not like doing this in certain ways, but any treatment of these as files to read or write will be basically valid.
Those files also have IOCTL control (I/O control). See “man ioctl” on a system with man pages installed. IOCTL calls usually talk to the driver to set different bit rates, stop bit settings, parity, so on. There are front end command line apps to work with this, e.g., “stty” or “setserial”. Lots of tutorials on the web explain this. These IOCTL commands can also be run from a programming language, e.g., from C.
Drivers can be told to do many things in terms of settings. However, UARTs are not plug-n-play and cannot usually report their settings. When you query a UART for its settings you are actually asking the driver what its settings are. If the UART can handle those settings, then these will be the actual settings. If not, then you will have failures.
The serial console is a special case because the boot stages prior to Linux running have serial drivers for serial console. The reason the serial console uses the older “ttyS#” driver is so that the UART does not need to reset and stop functioning during the transition from boot loader stages to running Linux…this preserves continuity of service during that transition.
Long wires, wires which are not twisted pair, so on, can cause data corruption. A twisted pair inside of a shielded ethernet cable works well.
I often use gtkterm to see if two UARTS can talk correctly. So for example if a 3.3V UART on the Jetson side is “ttyTHS2”, and it talks to a UART which on a PC is set up as “ttUSB0” (serial UARTs provided by a USB cable typically rename to “ttyUSB#” and is quite common on a PC), then I might do the following to type and listen between the two:
# Jetson side:
gtkterm -b 8 -t 1 -s 115200 -p /dev/ttyTHS2
# Host PC side:
gtkterm -b 8 -t 1 -s 115200 -p /dev/ttyUSB0
Note that the settings would result in IOCTL calls and set the UARTs up for you.
Sometimes you will find one side of the connection works, but the other does not…one way transmission. This might be due to having CTS/RTS flow control enabled on one side, but not the other.
Sometimes as speed goes up I recommend using CTS/RTS, but at 115200 or slower, this probably won’t matter. Hardware flow control can be better behaved at higher speeds versus software flow control.
You can wire the TX to the RX of a single port, or CTS directly to RTS of a single port. This means you are using the port in “loopback”. This is quite useful for testing since you’ll know wiring is too short to worry about noise, and the UART will never disagree with its own settings. In the case of separate UARTs you may not be positive that commands to set both UARTs to a given settings was actually honored, but a port will never disagree with itself.