FTDI and ch341 converters not working properly

I need to use USB-to-DB9 adapters with my J.Nano. They will eventually be used for radio modem communication. However, for now I’m trying to communicate through the adapters to verify they work.

When i connect the two adapters, they are detected:
ftdi_sio 1-2.1:1.0: FTDI USB Serial Device converter detected
ch341 1-2.4:1.0: ch341-uart converter detected

However, when I use GTKTerm (115200-8N1) to send characters they become unreadable at the receiving end.
Sending a ‘d’(64) from FTDI side is received as 04 0F on the ch341 side.
Sending a ‘d’(64) from ch341 side is received as E4 on the FTDI side.

When I do the same in regular Ubuntu (18.04.3 LTS) on my laptop, it works fine.

So, what is the difference in drivers/kernal or how to fix this?

(*To clarify, I open two GTKTerms on the same J.Nano/Laptop and configure them to ttyUSB0 and TTYUSB1 respectively.)

Does the device have options for changing stop bits and parity? What speed is being used? How long are the wires of the DB-9? I’m assuming the wires are of good quality and grounded+twisted pair unless it is custom built (most off the shelf DB-9 cables have shielding, or at least twisted pair).

Noise could cause the issue, so could incorrect parity or stop bits. When speed is too far off there will normally be no throughput at all, but this isn’t guaranteed. For the moment I will assume the speed is set to match.

Also, does the modem use CTS/RTS flow control, or just software flow control?

I can change the stop and parity bits through the GtkTerm but there is no way of directly changing those on the adapter chips.

The adapter cables are 20cm and 100cm, shielded. The null-modem cable I use is about 15cm, not shielded.
And the speed is 115200bps.

I do not believe this is a noise issue since the offset is consistent, and the same hardware setup works as it should when transferred to a laptop running Ubuntu (18.04.3 LTS).

The modem is not connected in this test. It is only Jetson to Jetson, or PC to PC.

I did some more testing and found that the problem stems from the ch341-adapter or its drivers.

Here are the ‘dmesg’ messages when connection the ch341-adapter:

[148211.508299] usb 1-2.1: new full-speed USB device number 12 using tegra-xusb
[148211.529660] usb 1-2.1: New USB device found, idVendor=1a86, idProduct=7523
[148211.529665] usb 1-2.1: New USB device strings: Mfr=0, Product=2, SerialNumber=0
[148211.529668] usb 1-2.1: Product: USB2.0-Ser!
[148211.531001] ch341 1-2.1:1.0: ch341-uart converter detected
[148211.534430] usb 1-2.1: ch341-uart converter now attached to ttyUSB0

[ 420.997330] usb 1-6: new full-speed USB device number 5 using xhci_hcd
[ 421.146126] usb 1-6: New USB device found, idVendor=1a86, idProduct=7523, bcdDevice= 2.54
[ 421.146131] usb 1-6: New USB device strings: Mfr=0, Product=2, SerialNumber=0
[ 421.146134] usb 1-6: Product: USB2.0-Ser!
[ 421.174332] usbcore: registered new interface driver ch341
[ 421.174342] usbserial: USB Serial support registered for ch341-uart

[ 421.174351] ch341 1-6:1.0: ch341-uart converter detected
[ 421.174853] usb 1-6: ch341-uart converter now attached to ttyUSB0

Is the issue due to the missing registrations of usbcore and usbserial?

Is the unshielded 15cm null modem cable twisted pair? If not, then this is highly suspect of noise. Otherwise it shouldn’t be an issue.

This shows success at the Jetson end (the “attached” implies a driver was bound to the device):

[148211.534430] usb 1-2.1: ch341-uart converter now attached to <b>ttyUSB0</b>

This shows success at the host PC end:

[ 421.174853] usb 1-6: ch341-uart converter now attached to <b>ttyUSB0</b>

Detection of a device is the point where USB sees the device and announces its properties. USB is done at this point.

Attaching is where the driver specific to the device takes ownership. All other activity past this point is user space software.

If “ls /dev/ttyUSB0” is present (since that is what the logs showed…this can change depending on what else is attached and in what order devices are detected), then everything is ready for use. Keep in mind that user space software can still change connection configuration, but this is not the responsibility of USB.

When you change certain details via gtkterm (or other apps), then the update of the underlying chip should occur (IOCTL calls are sent to the device special file and the driver interprets this). Some smaller and simpler programs require you to set up a UART separately from the access, but gtkterm does not require separate setup and does this for you simply due to the program arguments or setup in the GUI.

Is it possible to just have ttyUSB0 on the PC and Jetson without any other end device touching this? If so, at each end of the connection, run gtkterm with the same options. So for example, if insert shows each side as ttyUSB0, then start with this being run at both ends (use sudo if needed):

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

Then type a pattern in and see if the pattern is the same. My suggestion to type this over and over:


If we see something unexpected at the other end, then we will be able to match it to the ASCII table and look for bit patterns to see if they are shifting by one, or having a bit masked.

Hi again.

I’ve performed the test and the results are (in hex):

Sending: abcdabcdabcd

PC(FTDI) to Jetson(ch341): 01 1F 02 1F 03 1F 04 1F 01 1F 02 1F 03 1F 04 1F 01 1F 02 1F 03 1F 04 1F
Jetson(ch341) to PC(FTDI): E1 E2 C3 E4 E1 E2 C3 E4 E1 E2 C3 E4

And just for reference:
Sending: abcdabcdabcd
PC(ch341) to Jetson(FTDI): 61 62 63 64 61 62 63 64 61 62 63 64
Jetson(FTDI) to PC(ch341): 61 62 63 64 61 62 63 64 61 62 63 64

Important note before reading: The base ASCII characters are “7-bit clean”. You don’t use the 8th bit until you add extended ASCII characters, but technically this is 8-bit. The whole point of what follows is not to suggest if one should be 8-bit or other-bit, but is instead designed to show differences between the settings on the two sides of the communications.

The “61 62 63 64” is the correct hexadecimal for ASCII “abcd”. In binary this would be:

1100001 1100010 1100011 1100100

…with a leading “0” to show 8-bit instead of 7-bit clean:

01100001 01100010 01100011 01100100

…without spaces, 8-bit clean instead of 7-bit clean:


Converting “E1 E2 C3 E4 E1 E2 C3 E4 E1 E2 C3 E4” hexadecimal (not characters) to binary:


Comparing original 8-bit clean “abcd” above to hexadecimal E1…E4, and adding a space into the E1…E4, then repeating “abcd”:

Original: 01100001 01100010 01100011 01100100 01100001 01100010 01100011 01100100 01100001 01100010 01100011 01100100
E1...E4:  11100001 11100010 11000011 11100100 11100001 11100010 11000011 11100100 11100001 11100010 11000011 11100100

The basic data stream is valid. Only the logic of interpreting the stream is incorrect. Both ports are therefore operating at the same bit rate and the physical interface is doing as it should.

Notice that only the most significant bit is invalid, and that when I turned the 7-bit clean into 8-bit clean I used a “0”, whereas the operating system used a “1”. An actual “frame” is 11 bits, and bits not considered control in some form are not shown in the end user applications. Perhaps the error is one end thinking there is parity (“abcd” has an odd number of “1” bits in all cases, so the parity bit would be constant until data has an even number of bits), but the other not, or an extra stop bit. Sometimes this would occur from manual settings, and at other times this might be an error because the terminal application has the wrong idea about the character encoding (more on this in a moment). Each side of the communications must understand the same encoding if the data is something like ASCII and not just binary data.

At the terminal (text console, not serial app) on each side of the communications, what do you see from:

echo $LANG

…do both sides match?

Within gtkterm, if you go to port settings, do both sides of communications show speed 115200, 8-bit, no parity, and 1 stop bit? CTS/RTS flow control won’t matter for this case since this is about stopping/starting, and there would be no data most cases if this were wrong (but you might check CTS/RTS matches anyway).