WCH CH341 USB to Serial Chip Gets Linux Drivers to Control GPIOs over USB

USB to serial chips are often used as a debug interface either directly on the target board, or via a dedicated debug board. But some models have extra pins exposed, and one of those is WCH CH341, which also includes I2C & SPI interfaces and up to 8 GPIOs.

But software support for those extra pins is not currently built-in into the drivers found in Linux mainline, and you’d also have to find a board that breakout the relevant pins. It turns out there are few of things including “CH341A ALL IN 1 USB to SPI/I2C/IIC/UART/TTL/ISP serial adapter” board going for $10 shipped on Aliexpress, and which Zoobab successfully used to control 6 (out of 8) GPIOs over USB.

The board comes with a USB board to connect to your computer, several header for I2C, UART, SPI, some LEDs, and jumper to select I2C/SPI or UART mode and voltage (5V/3.3V).

The board is recognized differently whether you use I2C/SPI or UART mode in Linux:

  • I2C-SPI mode

  • UART mode

You’ll however need the out of tree i2c-ch341-usb driver to expose the 8 GPIOs and control them over USB/I2C. He set the direction to output for 6 of the pin in the source code (6-7 could not be set to output for whatever reason):

After after build the module, and load the module:


gpio0 to gpio5 would should in /sys/class/gpio, which means you can control them with the usual sysfs commands:


He also benchmarked the pins with a shell script to turn on and off connected LED, and managed to do that at around 2.2KHz. It may be a little faster by changing the I2C bus speed (100 kHZ by default) and/or using C code instead. Alternatively, using spi-ch341-usb driver from the same developer (gschorcht) may speed things up a little bit despite the documented “slow SPI”.

Another shell script with 6 LEDs connected to the board is demonstrated below.

Anyway that good news since that means you can add (extra) GPIOs to any Linux board with USB relatively easily and cheaply. But if you’re not quite willing to spending $10 on that option, there are cheaper options such as a CH341 USB programmer going for $2.30 + shipping on Electrodragon, or CJMCU-341 board sold for around $5 including shipping on Aliexpress or eBay.

Share this:

Support CNX Software! Donate via cryptocurrencies, become a Patron on Patreon, or purchase goods on Amazon or Aliexpress

ROCK Pi 4C Plus
Subscribe
Notify of
guest
The comment form collects your name, email and content to allow us keep track of the comments placed on the website. Please read and accept our website Terms and Privacy Policy to post a comment.
22 Comments
oldest
newest
agumonkey
6 years ago

Very nice, thanks

animtakhnet
animtakhnet
6 years ago

LOL, i used an FTDI chip for this years ago. It ran a Nixie tube clock with some shift registers. It was controlled by a WR703n with OpenWRT. I also made a LED version, but it wasn’t that cool and ended up in a drawer ( i think).

willmore
willmore
6 years ago

What’s the performance in I2C mode like?

are
are
6 years ago

Out of tree drivers suck badly. Is it going to be merged upstream?

Bert Vermeulen
Bert Vermeulen
6 years ago

It seems to me this would be a lot easier to control with the userspace I2C interface (if the kernel exposes this when detecting that board in I2C mode), or else just with libusb. This large out-of-tree kernel driver is really overkill.

willmore
willmore
6 years ago

After thinking about this a bit more, it occurs to me that using something like a Blue Pill board for this kind of functionality might make a lot more sense. You could put firmata on it or program it directly to perform whatever task you need.

James
James
6 years ago

Only 6 out of 8 GPIO’s work and the software end is incomplete. Some things never change 🙂

DurandA
6 years ago

Is this device suitable to talk to i2c slaves from a Linux laptop? Do you have any other recommendation for this purpose?

hex
hex
6 years ago

hi cnx, do you suggest FT232H (yes H) to utilize spi ,uart etc ?

Malem
Malem
6 years ago

@willmore

Yeah or just your run of the mill Arduino (clone) https://github.com/BLavery/virtual-GPIO

zoobab
6 years ago

@willmore
yes I found a firmware for the stm32 that does GPIOs over USB, with a userspace tool on the host side to control them. Now they do not support the bluepill yet, but it is on my todolist: https://chromium.googlesource.com/chromiumos/platform/ec/+/master/chip/stm32/

zoobab
6 years ago

@are
Maybe one day. I don’t know if the original author has the will/energy to make a pull request to the kernel. Plus let’s say the “mainline” status of such USB chip with some GPIOs drivers is pretty a disaster, not to mention the tendency of the GPIO maintainers stack to consider sysfs “legacy”. There were attempts in the past to merge sysfs gpio drivers for FTDI: failed (http://www.zoobab.com/ftdi-gpios-sysfs), same for PL2303 (the PL2303TB version has 12 GPIOs) (http://www.zoobab.com/pl2303hxd-gpio), not to mention Cypress (http://www.zoobab.com/pl2303hxd-gpio#toc6).

michael
michael
6 years ago

a Pi0 with his own OS (otg-mode, power supply via usb cable, no sd requiered) may be an option (5-9 $ + usb-cable+shipping) : https://www.raspberrypi.org/blog/gpio-expander/

zoobab
6 years ago

See also this board with atmega8 with sysfs and 22 gpios:

https://github.com/amitesh-singh/usb-gpio-board

Not an off te shelf board though.

Falay
Falay
6 years ago

Excellent solution

zoobab
6 years ago

@zoobab
I wonder if an AVR programmer based on Atmega8 could be reflashed to run it…

Drone
Drone
6 years ago

Or just bit-bang a 74HC194 4-bit bidirectional universal shift register from a user-land snippit.

arina nuha
arina nuha
6 years ago

6-7 could not be set to output for whatever reason

At least the USB vendor protocol doesn’t allow writing to D7 because the sevent bit on the command frame is used to indicate data direction (write or read)

#define CH341_CMD_UIO_STM_IN 0x00 // UIO interface IN command (D0~D7)
#define CH341_CMD_UIO_STM_OUT 0x80 // UIO interface OUT command (D0~D5)
#define CH341_CMD_UIO_STM_DIR 0x40 // UIO interface DIR command (D0~D5)
#define CH341_CMD_UIO_STM_END 0x20 // UIO interface END command
#define CH341_CMD_UIO_STM_US 0xc0 // UIO interface US command

zoobab
6 years ago

Next step is to write a sysfs and a gpiochar driver for an stm32 bluepill board with the right firmware.

willmore
willmore
6 years ago

@zoobab
How about a firmata to native Linux driver shim?

zoobab
6 years ago

@willmore
I am gonna play with the chromium-ec firmware, because there not much to do, just to try it out first, if you have the right stm32 supported board, some nucleo I have is supported.

Then I will look at firmata.

Khadas VIM4 SBC