Troubles with usb-serial adapter ch341

Usb-serial adapter with ch341 chip doesn’t work properly on jetson agx. I connected can-bus controller via usb-rs232 adapter to jetson, but getting only non printable ascii chars. It works properly on win 10 and desktop ubuntu 18.04.
System: L4T 32.4.4.
For example, in python with pyserial lib on PC i’m getting “S123F00 C0165010.000 E0012143.0 R077.0 H1200 j060 ZCA94 \r\n” from controller. On jetson i got in hexadecimal 6 strings: ‘0212090202020501020a’, ‘120a’, ‘13120902120513130902020512020202120a’, ‘1302120d0505130a’, ‘080113051a12060102021a010a’, ‘130d0a’.
dmesg log:
[18668.694745] usb 1-4.4: new full-speed USB device number 25 using tegra-xusb
[18668.715721] usb 1-4.4: New USB device found, idVendor=1a86, idProduct=7523
[18668.715728] usb 1-4.4: New USB device strings: Mfr=0, Product=2, SerialNumber=0
[18668.715731] usb 1-4.4: Product: USB2.0-Ser!
[18668.716561] ch341 1-4.4:1.0: ch341-uart converter detected
[18668.717750] usb 1-4.4: ch341-uart converter now attached to ttyUSB1

I also tried to patch ch341.c as was mentioned in one topic here on forum, but nothing changed and i dont think it was necessary as kernel version is 4.9.

Getting data tends to imply the driver is installed correctly. Having incorrect throughput is often a case of having a mismatch in UART settings between the two sides of the communications.

For example, if one side thinks there is 1 stop bit, but the other side thinks there are 2 stop bits, then you get a bit shifted data stream.

Most of the time when the speed is wrong you won’t see any data flow at all, but in some cases you will also see corrupted data.

Make sure the UART at each side uses the same settings.

I cant change controller settings but i have its parameters in documentation, so i set same params when open port on jetson. Also i tried brute force parameters, nothing works.

What settings did you use on the Jetson side?

Btw, if the USB side of the UART is connected to the Jetson, then you can do some testing in loopback mode. What you’d do is jumper the DB-9’s TX and RX together (CTS and RTS too if using that for flow control) and open the USB end with a serial console program. If the settings are the same as when you used this with the other hardware, and if typing content on the console does not corrupt, then you know the settings are likely valid.

The idea is that a serial UART talking to itself will probably agree on settings. Does loopback show typed in content matching?

There are also times when the terminals at each side of the connection are sending valid data, but it would appear mismatched if the character set encoding differs between the two systems (e.g., UTF-8 mixed with UTF-16).

9600 8N1.

Tried jumper TX and RX and output corrupted. For “\x47\x48” i got “\x1c\x18\x14\x17\x1c\x18\x14\x18”. In console program it’s unreadable message.
Is there a chance to get normal result with another chip(e.g, PL2303RA).

Very interesting error…it is converting 2 bytes into 8 bytes (3:1 multiplication). If this were a UTF-8 to UTF-16 error, then I’d think it would be a 2:1 multiplication, so I think that can be ruled out (unless there is some more complicated series of issues).

For reference, here is the binary for the input and output:

01000111 01001000
x0001110 x0000110 x0000010 x1000001 x0111000 x1110000 x0110000 x0010100 x00011000

(note that I have added leading edge “0” to your input to make it an even 8-bits, but the output is also not an even 8 bits per byte the way I have done this, so the method is very flawed…I used the “x” instead of a “0” in the output to attempt 1 extra bit per byte, but no luck)

I don’t see any obvious alignments (bit shifting), but I am only checking the entire 2 bytes and not checking if each individual byte has bit shifting. If there is some other software running on the port, then that would account for random bytes (for example, if the terminal has serial console or your other embedded device injecting bytes, then I’d expect extra bytes).

Can you try that same thing with gtkterm at speed 115200 8N1? If you don’t have gtkterm, then “sudo apt-get install gtkterm”. Command would be like this (but adjust for the actual device you send to, ttyUSB0 is just a placeholder):

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

Then, if this fails, try this:

sudo -s
export LANG=en_US.UTF-8 gtkterm -b 8 -t 1 -s 115200 -p /dev/ttyUSB0

Regardless of the command used, does the input always result in an unchanging output? Or does the error produce randomized output?

Note: If you can provide both the ASCII output of the echo and the hexadecimal, then it might provide clues to 7-bit versus 8-bit.

A better test pattern (alternating bits, leading edge “1”, second byte inverted bits):

Sorry, I made a mistake and forgot about -e while echoing. So for \x47\x48 it returns 07 08, for \xAA\x55 - 0A 15. But still its only control chars in ASCII. Sending this via ‘send hexadecimal data’ in gtkterm returns same output.

So it is masking out at least one of the most significant bits. Least significant bits are coming through ok. What happens if you send this as a binary stream:
0x0f 0x1f 0x2f 0x4f 0x8f 0xf0 0xff

Got as output: 0F 1F 0F 0F 0F 10 1F.

Placing the input and output data as base 2 for reference, and adding a space at the point where they diverge (top line is input, bottom line is output…the hex code above or below that):

0f 1f 2f 4f 8f f0 ff
0000111100011111001011110 10011111,00011111,11100001,1111111
0000111100011111000011110 00011110,00011110,00100000,0011111
0F 1F 0F 0F 0F 10 1F

Note that I have made sure leading edge “0” is consistent. 25 bits are a match if we include the 4 bits of leading edge 0 content I added. This means 3 bytes are valid, and only the first bit of the next byte are valid. Byte 4 is the beginning of corruption.

On byte 4 and on I’m adding some separators (comma) for clarity.

It looks like in all cases a “1” is becoming a “0”, and the inverse of a “0” becoming a “1” does not occur.

If there is a bit shift, then this would imply a “1” would become a “0”, but the reverse case of a “0” becoming a “1” does not occur with a bit shift. Perhaps it is a bit shift? Or a mask. However, I don’t know how that could be the case with the end of the bit pattern when the start of the bit pattern has no such shift.

This could be noise, but I don’t think it is.

Can I verify that the ch341 has its USB side on the Jetson? Or is this the Jetson’s internal UART talking to the serial side of the ch341 during this test?

Can we also verify the output from the following hex input of all “0xff” (note that this is 8 bytes, or 64 bits…0xF repeated 16 times, or 0xFF repeated 8 times):
…and with all zero bits (64 bits total), in hexadecimal (0x0 repeated 16 times, or 0x00 repeated 8 times):

I am guessing the all “1” bits will be altered, but the all “0” bits will remain constant (a zero flipped to a zero will remain zero and so far this seems to be what we see). Perhaps this doubling of the number of bits from 32 to 64 will reveal a pattern.

For 0xF 16 times: 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F .
For 0xFF 8 times: 1F 1F 1F 1F 1F 1F 1F 1F
0x00 8 times: 00 00 00 00 00 00 00 00
And 0x0 16 times: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

USB side is on jetson.

It looks like 5 bits are sent normally every time, and 3 bits are being masked with every byte (0xFF is one byte, 0xF is a 4-bit nibble). A rather interesting issue.

If the UART were told to use the wrong number of stop bits, or perhaps mistake a parity bit, then the content would shift every single new byte, but no bit shifting is taking place.

If we were just talking about characters and not binary data, then we might be able to say there is a character or localization difference, but this is binary data, so there is something in the data to or from the UART which is literally masking the 3 most significant bits.

Are you absolutely certain that your pyserial program is not doing this before sending it? Or masking what it receives? Masking the 3 MSB before send or after send would be indistinguishable as to which one was occurring.

I sent it with terminal and receive with gtkterm. On desktop pc on linux or windows everything is fine in pyserial and in terminal programs. I compared localization on ubuntu and jetson, everything is the same. I want to try to connect directly to uart on jetson or use adapter with another chip.

I’m not sure what to tell you, but if you have some way to verify input is not being masked it would be useful debug information.

One way is to take a file with binary content of all “0xff” repeated many times, and “cat the_file.bin > /dev/ttyUSB#” (where you provide the actual ttyUSB instead of my placeholder, and “the_file.bin” is some file you’ve created with lots of “0xff” bytes).

If you use a terminal to echo there is a chance of the terminal performing some sort of character set or encoding trickery which gets in the way; if you redirect a file you’ve confirmed to be all binary bytes, then it should provide some confidence that the input is not being altered. A program like “hexedit” or “ghex” should help in editing binary files.

Using gtkterm should be ok, but the “View” should be set to “Hexadecimal” (I’m guessing you’re already doing that, but adding to be thorough).

Got same output. For every FF i got 1F.

This is quite odd. I don’t think I am going to be able to figure this one out without actually sitting down and debugging. I’ve not seen an 8-bit input masked to the 5 least significant bits before. I’m thinking it may follow the ch341 driver. Do you have any USB serial UARTs which use a different driver? If possible see if the issue follows the driver. If something like an FTDI chipset serial UART does not have the same problem, then this will be an issue of the ch341 driver (or ch341 driver configuration). As much of a pain as it is to buy another serial UART I think it will save you a lot of debug time if you have something like an FTDI UART to test with.

Problem was in ch341, changed to pl2302 and it works fine.