There was a time when USB to serial hardware meant one company: FTDI. But today there are quite a few to choose from and one of the most common ones is the WCH CH341. There’s been support for these chips in Linux for a while, but only for use as a communication port. The device actually has RS232, I2C, SPI, and 8 general purpose I/O (GPIO) pins. [ZooBaB] took an out-of-tree driver that exposes the GPIO, and got it working with some frightening-looking CH341 boards.
He had to make a slight mod to the driver to get six GPIOs in /sys/class/gpio. Once there though, it is easy to manipulate the pins using a shell script or anything that can write to the virtual files corresponding to the GPIO pins.
For example, he did a speed test that was this simple:
#!/bin/bash x=100000 while ((x--)); do i=$((i+1)) echo 0 > /sys/class/gpio/gpio1/value echo 1 > /sys/class/gpio/gpio1/value done
He got about 2.2 kHz out of the output pin, and although he didn’t say the exact hardware configuration it gives you some idea about the possible speed.
There are some other examples, and a look at several inexpensive boards that expose the I/O pins. There’s also some discussion of some mods of those boards.
The ability to share and hack drivers is one of the things that makes Linux so great for hackers. Your Linux system probably has all the tools you need and, if not, they are a package manager command away. Even if you aren’t comfortable building a whole driver, patching one like [ZooBab] did is very doable.
Of course, there are faster ways to drive I/O. We looked at the details of the CH340 and CH341 way back in 2014.
64 thoughts on “Linux Adds CH341 GPIO”
Regarding faster ways of using GPIO, the sysfs-interface to the GPIO-pins, while handy, is deprecated nowadays. The character-device based interface that one should use now is a helluva lot faster in many ways, like e.g. you can toggle or setup multiple pins in one go. Even when toggling single GPIO-pins, I went from a couple of hundred KHz to several MHz speeds when I tested it on a couple of different SBCs.
I think the problem is that the character device way still needs to make its way into libraries and tutorials – hopefully, it happens soon!
Unlikely; the char-dev interface has been around for years now, but I see no one ever expressing interest in it, other than myself. I do get that it’s not quite as accessible as the sysfs-one, but god damn, if it ain’t a lot faster.
I’m slightly confused – ages ago (back when the LDD book was still in the 1st edition), I wrote a device driver and, as I understood, there were only char or block device drivers. From seeing how this device driver operates, to me at least, it still looks like it’s behaving like a char device with the only differentiation between ‘sysfs’ and ‘char’ being the level of abstraction in the device tree (in that more of the device’s controls are presented via the file system or done through different characters in a single ‘file’). Is there something more fundamentally different about the two?
I don’t know what sort of a reply you’re specifically seeking, but I’ll try:
The sysfs-interface only allows you to access a single GPIO-pin at a time and only allow for one operation on it at a time, ie. you can only change the pin to INPUT or OUTPUT, then you have to access it again to change whether it’s HIGH or LOW and so on. Then there’s the whole thing about the kernel having to emulate a filesystem, the conversion to/from text, including ignoring upper-/lowercase and such that slow things down even further. The char-dev approach, however, operates using binary data, so you can operate on up to 32 GPIO-pins in one go, there’s no need for converting the values to/from text and so on.
Just simply being able to skip the filesystem-emulation and text-conversion alone speeds things up enormously, but also the fact that you don’t have to keep opening/closing the char-dev all the time skips a whole lot of needless overhead.
With the sysfs interface you can write “high” and “low” to the direction file to directly turn an input to an output driving high or low. That’s a single syscall if you are smart.
As for the character device interface, how exactly do you change a pin from input to output and back? As far as I can see, you need to close the old file descriptor and create a new one with the new direction. That’s two syscalls.
Thanks. I think you did answer my question :-)
Both are essentially ‘char’ drivers (they operate via a file-stream interface), it’s just the interface presented for this GPIO control pushes it all to many, many ‘files’, each only handling a limited number of bytes (in this case “0” and “1”). So the differentiation is really how much is pushed to being managed via the file-system versus being encoded as more characters on a single ‘file’.
I wonder if the driver would handle something like ‘echo “0101010” > /sys/class/gpio/gpio1/value’ ?
…and to answer my own question…
I wonder if the driver would handle something like ‘echo “0101010” > /sys/class/gpio/gpio1/value’ ?
Looking through some of the documentation for it, this should work fine and give faster toggle results than the example “speed test” mentioned above (not only is it skipping the shell processing each line but it doesn’t need to keep opening and closing the file before sending a single byte).
Wait, where’s the documentation for that? If it’s anything like SPI, I’d love to be using that over sysfs.
There isn’t any particularly good documentation, but the code-snippets at https://github.com/torvalds/linux/tree/master/tools/gpio go a long way towards allowing you to use the system, and there’s some documentation in https://github.com/torvalds/linux/tree/master/Documentation/gpio
What’s so frightening about that board? That it would be easy to accidentally break a USB connector with it?
Seriously, compared to some things we see on this site, that board looks professional.
Good Post ????
After seeing this article, I did some research and as far as I can tell, the WCH CH34x chips are really just preprogrammed PIC chips because they accidentally(?) labeled them as such. I did a search for things that would match and PIC16F1459-I/SS appears to be a perfect match to their specs and capabilities.
Since they are sold below market price, I suspect they paid for a batch to be made with the stolen IP from Microchip.
I find that unlikely. You can buy the wch chips in bulk cheaper than the Microchip ones. It’d be simpler for them to just make their own usb serial chips at that scale anyway, especially since they already make so many other chips.
I find the base from which you make your suggestion (Labeled on the linked page: “Type: MCU USB PIC”) woefully unfulfilling. Frankly, that ‘Type’ field looks more like a list of keywords associated with the product, probably even a rudimentary form of SEO on the part of the (re?)seller – someone who searches for “PIC” would be exposed to the product, possibly resulting in a sale. We know that relabeling chips happens all the time on the open, international market.
This kind of thing kills rational discourse, especially discourse over important things. People love to jump all over something that “looks bad” and make a big deal out of it, even when when there’s bupkis for supporting evidence. Spread FUD, grab popcorn, sit back and watch people fight each other.
Then again, there’s probably still nothing new under the sun.
I’m almost entirely outside the microchip supply market, and I can think of a few common reasons why their prices may be “below market” – genuinely making their own chips and undercutting a big supplier (insert list of possible compromises which could be made to do so here), loss-leading to gain entry into the market, legally purchasing and reselling production line discards. Again, I’m out of the market, but I’d be surprised to hear that those were less likely than IP theft from one of the biggests IC makers.
That said, decapping and dieshotting is a thing, so maybe they did reverse-engineer the chip. It remains possible, but I think [tylerl]’s response makes more sense – why risk retaliatory action from one of the largest players in the game? If [tylerl] is correct, the company has a lot to lose if they are found to be copying designs, and that’s a risk that most people would greatly hesitate to take.
So I entreat you, [Gravis], if you have substantial information, share it with someone – if not us, then perhaps with Microchip themselves – I’m sure they’d love to have information on someone ripping off their designs. If not… maybe don’t stir up FUD with wild speculation?
Risk of IP theft?
Sue a chinese company for copyright theft? really?
Never do business again in china.
Have you seen the pandering to the regieme that brands make if/when they offend the political viewpoint, accidently, even when operating outside of china.
It’s a global market thanks to the internet, making fun (even unintentionally) of china in europe – they will get to hear of it and your bottom line may well suffer.
Never mind actually going after a chinese company internally with political connections (you dont get big in china without political connections) for wrong doing in the global market. It’s considered sport.
But I’m just racist of course.
But of course you are.
You dared to suggest that those poor Chinese manufacturers might be dishonest instead of just misunderstood and discriminated against.
Obviously you should be imprisoned immediately. No need for trivial formalities such as a trial.
That is just a mistake on the Alibaba page. The CH341 doesn’t even match up with a PIC for power pins.
What is a preprogrammed PIC is the Microchip MCP2200 USB to serial. If you wire it up to a PIC programmer then it identifies itself as a 18F14K50 but with locked out flash. You can erase it but you lose the MCP2200 code. No clue if they’re 100% working 18F14K50s or semi dud ones that are good enough to use with the MCP2200 code.
Just for reference – I did a side-by-side driver comparison of several USB-to-UART ICs in Windows. The WCH Windows drivers, based on some of their unintended side-behaviors, appear to be genuinely written by themselves (or a contracted consulting company, etc.). They behave uniquely compared to FTDI, Silabs, Prolific, Microchip, and some third-party USB-UART licensed driver solutions (J-link, etc.)
They were also definitely better than the Microchip solution, which I believe had a much lower maximum baud rate, and quite a few reliability-breaking bugs in their code (I looked at things like driver robustness to random disconnects, error rate, reliability of error flags, buffer overflow indicators, etc.) FTDI by far had the most reliable drivers, then Silabs and WCH tied (but they were definitely NOT identical drivers, unless WCH deliberately fixed a few features and broke other ones…). I concluded that for highest reliability, particularly when you have no robustness to errors on your lines, FTDI is the best chip at the highest cost; for the best price/performance, WCH beats everyone else; and the Silabs chipset isn’t a bad compromise. I could not find a reason to ever design in the Microchip UART chipset – it was slow and buggy, and I believe had some irrecoverable driver crashes in some disconnect scenarios.
Prolific might have actually been okay, but from what I heard, the market has been swamped with poor quality clones, which they tried too hard to deliberately reject with their drivers. Either their drivers are so sensitive to finding fake clones that my real chipset does not function reliably, or it’s virtually impossible to find a genuinely prolific chipset anymore. Suffices to say, I had a few pretty severe crashes with their chipset and gave up.
Now get the USB parallel-port CH34x adapters working. Half the USB-LPT cables on eBay are those, and half of them are Prolific PL2303s. Guess which ones work on Linux and which ones don’t? Hint: the ones with the Prolific chips work fine… of course, which one you wind up with is sort of a game of chance, since the idiots who do the listing, in my experience, never quite know what they’re selling…
agreed, there are a few ch34x cables of various type out there that have poor to none at all linux support in ways that matter. After writing a few drivers myself for the uclinux/linux platforms I can say thats it’s not easy to get a good stable driver direct from the manufacturer for linux.
On a side note this would make a cheap jtag bit banger , almost filling the FTDI shoes in that area.
PL-2305 is Prolific’s parallel port chip.
Does anyone here have a description of the vendor-specific device control requests that are mentioned in revision 1.1 of the PL-2305 datasheet? Without them one is limited to the USB printer class requests and can’t directly control the strobe, auto feed, select in, and init pins.
Does anyone remember FT245?
Yes! I have one here which I want to hook up to the Z80 bus on the RC2014. And then, to the bus on a 6502 or 6809.
Replying to self after having found my old notes. parupl.sys from wd_pl2305_v31011 contains symbols. According to these there exist at least the following vendor requests:
Get 1284 Register: device req 3, 16 bit value, index=0, IN variable
Set 1284 Register: device req 4, 16 bit value, index=0
Get 1284 Status: interface req 3, value=0, index=0, IN variable
Scan 1284 Mode: interface req 4, 9 bit value, index=0, IN variable
ECP Write Command: interface req 5, 8 bit value, index=0
ECP Get Command: interface req 6, value=0, index=0, IN 1 byte
EPP Write Register: interface req 7, value=0, index=0, OUT variable <= 255 bytes
EPP Get Register: interface req 8, value=0, index=0, IN variable <= 255 bytes
Set Control: interface req 9, 16 bit value, 16 bit index
Get Control: interface req 10, value=0, index=0, IN 4 bytes
Direct Control: interface req 11, 16 bit value, 16 bit index, IN variable
EPP Write Addr: interface req 12, 8 bit value, index=0
Get Release Number: interface req 254, value=0, index=0, IN 2 bytes
Set EEPROM String: device req 255, value=0, index=0, OUT variable
The exact semantics of course still have to be worked out.
This is really interesting! And a simple bash interface is incredibly useful, thanks for bringing this to attention! Sinking my teeth into RTOSs and embedded Linux in coursework (ex. for weather balloons and cube satellites) and this is handy
I found a ch34 driver that works from my Linux ide. You have to use Google translate to track it down from the Chinese web, but they are supported.
It should be mentioned, that the CP2104, a popular USB to serial converter from Silicon Labs, also has GPIOs.
The CP2104 is available since many years, there are also cheap modules from China, and even some commercial products, like software switchable power strips.
And here, the official Linux drivers don’t support the GPIOs as well, so you have to compile your own.
does it also support input? how does one switch pin between input and output? i’ve seen them to be use only for output (i.e. the I is missing in GPIO). Just yesterday I was thinking how I could bitbang SPI throught such CP2104 adapter. Also I wondered if I could use DCD/DTR RTS/CTS and read/write them directly via some standard serial ioctl, that would be good enough for CLK,MISO,MOSI, googled and didn’t find anyone doing it
This is the question I had as well, and it is answered on the linked github https://github.com/gschorcht/i2c-ch341-usb
echo out > /sys/class/gpio/gpio4/direction
Apparently D0-D5 are bidirectional and D6-D7 are input only? *shrug*
yes, thanks, but I was asking about cp2104
maybe this helps: https://github.com/ondrej1024/crelay
p.s. it seems that you can use libusb to talk to the CP2104 directly, so you don’t need a kernel driver at all.
Have you looked at the CP2130? It’s a USB to SPI converter and there’s a USB library available.
Why are most of the programmers of Arduino chips are so complicated? should it be just Serial to Parallel chip with a driver?
I really don’t know a lot about USB interfaces, if someone can point me to some good learning materials I would appreciate it.
Not free but Jan axleson’s books were well written. Not sure how current they are but I sometimes find going back to older tech makes for an easier intro to newer tech.
Jan’s “USB Complete” was NOT a good book. Mostly just rehashed the USB standard and a few datasheet, but very little useful info about software and drivers.
They aren’t that complicated, the basic AVR programmers are just an ATTiny and some passives. The more advanced ones from Atmel/Microchip do a lot more, hence more complex.
Why even the basic ones need a complete CPU? can’t most of the heavy lifting be done on the PC and leave the rest to even a shift register?
again, I’m not an expert, I’m trying to understand what magic can the ATTiny do that a PC can’t tell a shift register to do. is it just the USB “handshake”?
It’s mostly a timing thing AFAIK. USB is not good for precisely timed signals, which is what you need to emulate various programming interfaces. You thus need some sort of buffer chip that streams data from the USB and translates it into the precise pulses needed to emulate whatever programming protocol. USB is also a pretty high-level protocol that works at the packet level and uses differential signaling, you don’t really have direct control of the signals sent over the wire, which is what you’d need. In other words, a USB port doesn’t at all work like a GPIO and you don’t really control it directly.
You used to be able to use hardware parallel ports to program some microcontrollers (like the AVR) because they are basically raw I/O connected to the CPU, but those are pretty much extinct and USB parallel adapters are basically the same thing – they require a buffer chip to translate USB to line signals.
You want WinModems? cause that’s how you get WinModems.
I think we’re on the edge of a universal programmer for very cheap, with a little multiplexing or something (universal means program bootloaders to avr, burn gals and proms, and program fpga)
also gui for changing pin outputs live would be awesome
then write one.
The FTDI serial chips had that with their MPSSE feature which did I2C, SPI and JTAG. If it wasn’t covered by MPSSE then you could bitbang it assuming the USB overheads weren’t too great. Shame they pissed off everybody with their driver shenanigans.
I think a microcontroller like a STM32 is probably a better idea than a dedicated chip like the CH341 or FTDI.
Programming parallel devices such as GALs and PROMs will be annoying just because of the oddball programming voltages needed for a lot of them. You’ll need to get all the circuitry needed to handle that and also dig through old datasheets to implement the programming algorithm they want. In most cases, it is easier to just buy a cheap universal programmer unit. The ones I’ve looked at were some horrific kludge of a CPLD with some resistors to prevent it blowing up due to the high voltages on the pins and a clone 8051. Not a great design but worked well enough.
Given the ubiquitous Raspberry Pi, it seems that something reasonable to wish for, would be a USB dongle with a raspberry-pi style pin header, standard hat mounting holes and kernel driver support to make it software compatible That way any computer could run programs that assume the standard Raspberry Pi GPIO setup.
Already exists. https://www.modmypi.com/raspberry-pi/iousbanalogue-expansion-1028/interfacing-1080/ryanteck-rtk.gpio
This is close, but no cigar. It’s really just a rather primitive toy. There is no kernel driver support, so it only works with their python stuff. Also, all of the data goes through a 115200 bps serial port, so it’s not actually usable for any sort of “high speed” application.
You realize there is x instead of i in the code, don’t you?
Looks like ‘x’ counts down and ‘i’ counts up. But ‘i’ isn’t used.
I always say to myself, “I want an FTDI”, but then I look into them and it seems really primitive to me. And for some reason, I saw this CH341 and had to go through the same process.
I think bit-banging over USB is never going to pass my smell test, and I am not really interested in constraining myself to one of the supported protocol modes (I2C, etc).
For the moment, when I need something like this I use one of the STM32 boards that has a second STM32 to be a USBSWD (ST-link) gateway, and I use the debugging interface to communicate. It’s very low throughput but it makes it easy to off-load all of the protocol implementation.
I wish there was an MCU with a more direct and painless USB interface than the SWD debugging though. I guess I have to learn how to use the micro-USB port on these redpills. *sigh*
There is a thing called “firmata” which might fit your need. I believe there are other implementations besides arduino. It has shortcomings, but it supports customization, so you can build on it as required for your application. Maybe someday we will be able to write little state machine engines in a high level language and download them into these dongles so that they can directly execute complex transactions with sensors etc.
If you’re looking for higher performance USB-to-GPIO, check out the Cypress EZ-USB FX2LP. It’s designed for (comparatively) blazing fast parallel applications like USB 2.0 to ATA. Cheap FX2 breakout boards are all over eBay, including in the form of Saleae Logic 8 clones. Sigrok supports the FX2 as a logic analyzer front end, and various other open firmware examples are available. Firmware is loaded over USB on initialization, so there’s no need to flash the chip itself.
wow thanks, that’s exactly what i described.. and the price is right 8051 though?! weird. anyways i’m definitely gonna look into it
“I think bit-banging over USB is never going to pass my smell test, and I am not really interested in constraining myself to one of the supported protocol modes (I2C, etc).”
We already have the alternative: Ethernet. Too bad it’s considered only for networking because it has everything needed for fast communication at great distances in almost real time, plus it’s dirt cheap and open. Also, for board to board connections there’s no need for magnetics and the associated bulky connector.
If I were to design something like this from scratch I’d make a USB device that appears to be an Ethernet adapter with a remote computer attached. Make TCP stream connections to the SPI I2C, etc. ports and blast away with excellent bandwidth and no custom drivers required. Have a nifty web interface to configure it manually, and a REST API for automated setup. It’s abundantly clear that companies like FTDI are not capable of supporting their custom USB protocols in a reasonable way, so I say ditch that crap and use industry standard interfaces like RNDIS and TCP.
Not a good idea. You would have to also provide a DHCP-Server so your simulated network interface on the host side gets an IP. Now how do you keep that server from using an IP range (and with bad luck IP address) already in use on the host? If that happens the host will lose network connectivity.
There are reasons why RS232 is still around.
This is trivial to solve, just make the IP address configurable separately. It’s connected via USB, so the driver can tell it to change addresses over a separate channel.
Microchip has some nice chips for bridging USB to serial protocols (UART, SPI, I2C) or GPIO or parallel, for example 18F2455, it has native USB 2.0 interface, you can program it to communicate via HID, or CDC. I think they even have 16F class micro with native USB interface.
I had bad experiences with a CH340 (or 41?) based Serial-to-USB cable years back – Windows drivers, only in Chinese, very flaky. It left a poor impression.
If the chip itself is actually decent/reliable, this could be the ticket to me using it again : )
Currently the mainline linux driver for it doesn’t initialise hardware handshaking correctly – that was a fun one to debug over Christmas.
Do any of these CH341A-based devices have any reputation, good, bad or indifferent in the community.
I’m looking for something that is a retail product. Probably doesn’t exist, right? Also, does an EZP2010 do everything the CH341A does (and perhaps more)? Thanks. Looking for a recommendation. For the time being all I’m doing is dumping and flashing SOIC8 CMOS chips. I may do more later.
Using a ch341 for this is a bit slow as it’s 2 USB transactions per 4 SPI bytes so lots of busy work on the PC side. There are a few commercial USB SPI bridges. Dediprog and Aardvark and two that spring to mind. Both have Windows / Mac / Linux API support.
Please be kind and respectful to help make the comments section excellent. (Comment Policy)