CH341 USB-serial device at 921600 baud rate different on Linux vs. Windows (?) - Page 1
Forum section: electronics / general

author: JBeale
author_rank: Frequent Contributor
timestamp: April 10, 2023, 07:42:39 pm
content: Sorry if this is the wrong forum. Recently I got a slightly unusual device, a board with a STM32F103C8T controlling a TCD1304 linear CCD, with an included CH341 USB-serial cable. It came from a far-east online shopping site. Always risky, but the listing had enough technical data to convince me someone, if not the seller, did some real development with it. Took a month to get here and the thing seemed totally dead when I tried talking with it, following the specified protocol and using the included cable. Figured I was out of luck.However, in response to my request, the seller then sent me a folder including two Windows .exe programs he thought would work. Another risk, but I did have a non-networked old Windows laptop I was willing to run suspicious .exe files on, and lo and behold they DID work. Long story short, the protocol details on the shopping site were totally wrong; perhaps for some different version of firmware. More strangely, I found doing the right protocol from my Linux machine still didn't work. Then my scope showed me, using the CH341 device from Linux inhterm0.8.8 when I send a 0xA1 byte at 921600 baud 8-N-1 my scope says I'm really sending 0x41 (the high-order three bits of the byte are read inverted) I assume because of a timing error. The scope shows this 8-N-1 byte takes 9.36 microseconds total in that case.However, doing the same thing using the WIndows .exe which is a Chinese languageSSCOMv5.13.1 serial program, the scope decoder shows it is sending 0xA1 as specified. That byte takes 8.66 microseconds, so the very same physical device using the same displayed nominal bitrate setting is running about 8% faster. The SSCOM program has a .ini file with a large number of numerical constants in it. I can't understand the Chinese comments there but does that include some timing tweaks or offsets(?) or is there something else I'm missing here?'dmesg' output when cable is connected, FWIW:Code:[2253165.542530] usb 1-5.4: new full-speed USB device number 46 using xhci_hcd[2253165.763548] usb 1-5.4: New USB device found, idVendor=1a86, idProduct=7523, bcdDevice=81.34[2253165.763553] usb 1-5.4: New USB device strings: Mfr=0, Product=2, SerialNumber=0[2253165.763555] usb 1-5.4: Product: USB Serial[2253165.771147] ch341 1-5.4:1.0: ch341-uart converter detected[2253165.772125] usb 1-5.4: ch341-uart converter now attached to ttyUSB1

author: JBeale
author_rank: Frequent Contributor
timestamp: April 10, 2023, 09:30:21 pm
content: I should note, 8-N-1 means 10 bits times but my scope timing is showing 8 bit times (falling edge of start bit to rising edge of 2nd to last bit, as the last bit and the stop bit are both high = idle level so they are not visible on the scope). So the WIndows program is delivering 8.66us / 8 = 1.083 usec or 923.8 kbps from this cable, so that is only 0.2% above the nominal 921.6 kbps. meanwhile the Linux program is delivering 9.36 us / 8 = 1.170 usec or 854.7 kbps which is 7.3% below the nominal rate. So I guess the question I should really be asking is why the Linux driver for this device is so far wrong. The total combined UART timing error (sender + receiver) is supposed to be less than 0.5 bits out of 10 bits which is a 5% error so that puts the Linux version well out of spec.

author: RoGeorge
author_rank: Super Contributor
timestamp: April 10, 2023, 09:41:51 pm
content: The oscilloscope usually measures by counting pixel on the oscilloscope display. Same for the serial decoding, it's usually made by looking at the display image, so it might decode the same signal different at different timescales.The two attachements are at 2us/div, respectivly 1us/div. Zoom them the same, and they'll measure and decode the same, no matter Windows or Linux.

author: tom66
author_rank: Super Contributor
timestamp: April 10, 2023, 09:58:41 pm
content: CH34x is a pretty rubbish UART converter in my experience. There's a reason FTDI, and FTDI-clones, are popular.My guess is the Linux driver is calculating the wrong BRG, perhaps an off by one bug that isn't so noticeable at lower baud rates or at a different ratio of crystal to baud rate. It's also possible the EEPROM for the CH34x is programmed incorrectly and the frequency of the crystal is set wrong, and the Windows driver is ignoring this but the Linux driver isn't.

author: mwb1100
author_rank: Frequent Contributor
timestamp: April 10, 2023, 11:37:06 pm
content: WCH has source code for updated Linux drivers for the CH341 driver here:https://www.wch.cn/downloads/CH341SER_LINUX_ZIP.html(the page is in Chinese - the direct download link for the zip is:https://www.wch.cn/downloads/file/177.html)The README.md says:QuoteMaybe their driver will work better than the mainlined driver? At the very least you can compare the ch341.c that's in the kernel you're running with the one in the zip package to see what might be different.The hterm program isn't open source, but maybe the author can help. There's also a newer 0.8.9 build that might be worth a try (but if the problem is in the driver, it's unlikely to help).Quote-https://der-hammer.info/pages/terminal.htmlSource for the sscom program might be available, But there are number of sscom projects on github - who knows which one might be the right one?

author: mwb1100
author_rank: Frequent Contributor
timestamp: April 10, 2023, 11:43:06 pm
content: Also,Code:stty -F /dev/ttyUSB1will tell you at least if the driver is set correctly (and if it is would pretty much guarantee the driver as at fault).

author: sleemanj
author_rank: Super Contributor
timestamp: April 10, 2023, 11:46:50 pm
content: What kernel version are you using, is it recent?I have a problem with some CH34x on my ancient workstation with a 4.4.0 kernel, but they work on 5.15.0 kernel in a VM on that same hardware, I assume there was an updated driver rolled into the kernel at some point.

author: JBeale
author_rank: Frequent Contributor
timestamp: April 11, 2023, 01:37:31 am
content: Just in case of doubts about the scope scale, included is a 1 usec/div screen from Linux showing my Siglent SDS1202X-E scope does decode the signal as 0x41 and not 0xA1 as intended. Also I captured this CH341 USB cable output using a Windows system running the Windows version of HTerm 0.8.9 (blue trace) on the same screen as the Linux version of HTerm 0.8.8 (yellow trace) showing the timing difference is pretty noticeable, and not just a pixel or two.Here is what stty on Linux 5.4.0-144-generic #161-Ubuntu SMP Fri Feb 3 14:49:04 UTC 2023 has to say about it:Code:$ stty -F /dev/ttyUSB1speed 921600 baud; line = 0;min = 0; time = 0;-brkint -icrnl -imaxbel-opost-isig -icanon -iexten -echoI see someone here mentioned an updated driver, so I will try that next.EDIT: it works.

author: JBeale
author_rank: Frequent Contributor
timestamp: April 11, 2023, 02:50:43 am
content: Yes, the updated driver works! I agree with the vendor's lament about keeping things up to date. Now Linux and Windows show exactly the same timing on the same device set at 921600 bps, and the 0xA1 byte is decoded correctly by my scope. Sometimes it's not obvious which exact version of a Linux serial port driver is in use, but the behavior of this one is different. 'demesg' shows a kernel taint notice, and the device is named differently. Previously it had been /dev/ttyUSB1 but now it is named /dev/ttyCH341USB0(...which HTerm 0.8.8 will not automatically recognize as a USB serial device, but you can manually type it in and that will work.)Code:[ 159.941987] usb 1-5.4: new full-speed USB device number 10 using xhci_hcd[ 160.162920] usb 1-5.4: New USB device found, idVendor=1a86, idProduct=7523, bcdDevice=81.34[ 160.162924] usb 1-5.4: New USB device strings: Mfr=0, Product=2, SerialNumber=0[ 160.162926] usb 1-5.4: Product: USB Serial[ 160.268026] ch341: loading out-of-tree module taints kernel.[ 160.268100] ch341: module verification failed: signature and/or required key missing - tainting kernel[ 160.268584] usb_ch341 1-5.4:1.0: ttyCH341USB0: ch341 USB device[ 160.268927] usbcore: registered new interface driver usb_ch341[ 160.268930] ch341: USB serial driver for ch340, ch341, etc.[ 160.268930] ch341: V1.6 On 2022.08Best of all, now my Linux Python program actually works to read out the sensor data. Success!Code:#!/usr/bin/env python"""communicates with this TCD1304 + STM32F103C8T device, a black PCB marked "YX_TCD1304 ver1.7"from [url=http://www.aliexpress.us/item/3256803138125304.html]www.aliexpress.us/item/3256803138125304.htmlOn linux, needs https://www.wch.cn/downloads/CH341SER_LINUX_ZIP.htmlbecause as of Ubuntu Linux 5.4 on March 2023, mainline CH341 driver is old & broken at this bitrateJ.Beale, April 10 2023"""import serialimport timeserport = "/dev/ttyCH341USB0"def readSerPort(ser):while (ser.in_waiting > 0):bytesIn = ser.in_waitingserdata = ser.read(bytesIn)print(serdata.hex())ser = serial.Serial(serport, baudrate=921600) # module uses this baud ratepacket = bytearray()packet.append(0xA1) # read TCD1304 module (12 bpp, 7296 bytes)# packet.append(0xA2) # read TCD1304 module (8 bpp, 3648 bytes)# packet.append(0xA3) # read data min/max summary from firmwareser.write(packet)time.sleep(0.1)readSerPort(ser)ser.close() # close the port

author: mwb1100
author_rank: Frequent Contributor
timestamp: April 11, 2023, 07:28:28 am
content: I'm glad to see that a straightforward solution was found.Quote from: JBeale on April 11, 2023, 02:50:43 amThat comes with loading a module that is built "out of tree" (ie., not part of the kernel's source tree). It's just there to let anyone you might ask for support from know that the kernel has some non-standard/non-supportable bits in it.Quote from: JBeale on April 11, 2023, 02:50:43 amThere are two places the "ttyCH341USB" string is specified in the driver source. You might get the usual "ttyUSB1" name if you modify those two strings, but I'm honestly not sure if that might cause other side-effects (like a conflict with another serial driver). Might be worth a try or it might be more trouble than it's worth.

author: tom66
author_rank: Super Contributor
timestamp: April 11, 2023, 10:55:43 am
content: Quote from: JBeale on April 11, 2023, 02:50:43 amI have a feeling that wouldn't work because Linux normally assigns the devices under /dev according to udev rules. The udev rules try to keep assigning the same device the same file name. It may work if you never plug in a mainline /dev/ttyUSBx device, as it would not conflict, but since the driver is loaded outside the kernel, it would not be in the udev rule set.

author: alm
author_rank: Super Contributor
timestamp: April 11, 2023, 08:37:56 pm
content: Quote from: JBeale on April 11, 2023, 02:50:43 amA lament written by the person who could and should do the work to keep it up to date in the mainline kernel. Somehow the others like FTDI can do it, but not this vendor. I'd say avoid this chipset for Linux to avoid the headache of compiling custom drivers. Been there, done that, but I'd now rather spend a few extra dollars on a serial cable with proper drivers. Alternatively you might be able to build aDKMS packageout of it if no one has done this yet, so you don't go insane having to recompile after every kernel update.

author: LesWright
author_rank: Newbie
timestamp: October 16, 2024, 05:52:36 pm
content: Thanks for the script! I have one of these and now have it spitting out data. Did the manufacturer provide the rest of the protocol to control this please?

author: RoGeorge
author_rank: Super Contributor
timestamp: October 17, 2024, 08:17:12 pm
content: Doh, now I've realized why in one of my virtual machines the serial communication was sometimes dropped: that VM was with an older kernel, where the CH340 driver was producing wrong baud speeds.Took the latest driver from the manufacturer githubhttps://github.com/WCHSoftGroup/ch341ser_linuxcompiled and installed it in the VM. Checked with the oscilloscope, and now the speed is correct.Thanks for waking up this old topic.