# PyFtdi drives FTDI chips from Python without a kernel module

> PyFtdi is a pure Python user-space driver for FTDI devices, covering UART, GPIO, SPI, I2C and JTAG over the same chips that usually need a kernel module or a vendor library. It needs only pyusb and pyserial, supports Python 3.9 to 3.13, and the README states a BSD-3-Clause licence even though a licence GitHub cannot classify.

**eblot/pyftdi** — FTDI device driver written in pure Python

- Repository: https://github.com/eblot/pyftdi
- Stars: 593 · Forks: 252
- Language: Python
- License: NOASSERTION
- Published: 2026-10-22 · Updated: 2026-10-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/eblot-pyftdi

## A user-space driver written entirely in Python

PyFtdi aims at providing a user-space driver for popular FTDI devices, implemented in pure Python language. That sentence covers the project, and the interesting part is the second half of it.

An FTDI chip is a USB-to-serial bridge that most people meet through the kernel. On Linux, the cdc_acm or ftdi_sio driver takes over the device and exposes a tty, and on Windows the vendor driver does the same. That is the right arrangement when all you want is a serial port. It is the wrong arrangement when the chip's other channels matter: the GPIO pins, the bitbang engine, the MPSSE engine that implements SPI and I2C in hardware, the JTAG state machine. Those are usually only reachable through the vendor's own library, which ties your code to a native dependency and to a platform-specific build.

PyFtdi goes around the vendor library and talks to the device over plain USB. The dependency list in setup.py is short enough to state outright: pyusb at 1.0.0 or later with 1.2.0 explicitly excluded, and pyserial at 3.0 or later. That exclusion is worth noticing, since it is the kind of detail that saves an afternoon when a pip resolution picks a broken version.

The repository layout confirms the shape of a conventional, well-organised Python package: a pyftdi/ directory holding the code, a setup.py and setup.cfg, a requirements.txt and a test-requirements.txt for the test dependencies, a MANIFEST.in, a .flake8 and a .pylintrc for linting, and a _config.yml for the documentation site.

The copyright headers in setup.py go back to 2010 for Neotion and 2010 to 2025 for Emmanuel Blot, which is a hint about how long the codebase has been in service.

## Which FTDI parts are covered, and at what speed

The README splits the supported devices into two groups, and the split is by capability rather than by family.

The first group is UART and GPIO bridges: the FT232R at a single port and 3Mbps, and the FT230X, FT231X and FT234X, also single port and 3Mbps. The second group is the wider set that also handles the multi-serial protocols, meaning SPI, I2C and JTAG: the FT2232C/D at dual port with clock up to 6 MHz, the FT232H at single port with clock up to 30 MHz, the FT2232H at dual port up to 30 MHz, and the FT4232H/HA/HP at quad port up to 30 MHz.

The pattern is clear. The older and cheaper parts give you serial and GPIO, and the H-series parts give you high-speed MPSSE. The 30 MHz figure is the MPSSE clock, and it is the number that matters for anyone driving a fast SPI peripheral, since it is the rate at which the hardware engine can shift bits.

The port count also determines how much you can do at once. A quad-port FT4232H gives you four independent channels, each of which can be a UART, an MPSSE engine or a GPIO bank, and PyFtdi exposes them as separate device instances. That is what makes a single chip usable as a multi-protocol test fixture.

The README does not list FT4232HA and FT4232HP separately from FT4232H, treating the three variants as one line, which is a reasonable simplification given that the difference is in the pin and voltage variants rather than in the protocol engine.

## The feature list tells you what is first class

The features section is where the driver's real scope shows, and two of the entries carry caveats that are stated rather than hidden.

The UART support goes up to 12Mbps depending on the FTDI device capability, which is faster than the 3Mbps figure attached to the FT232R in the device list, so the two numbers refer to different parts of the same family.

GPIO and bitbang come in four shapes: 8-bit asynchronous, 8-bit synchronous, and 8- or 16-bit MPSSE variants. The distinction that matters in practice is between the plain bitbang engine, where the CPU toggles a pin byte by byte and timing depends on your loop, and the MPSSE engine, where the hardware generates the clock and the transfers are queued. For anything timing-sensitive, the MPSSE path is the one you want.

The protocol support follows that structure. SPI master with simultaneous GPIO support, up to 12 pins per port, with support for non-byte sized transfer. I2C master with simultaneous GPIO support, up to 14 pins per port. And basic JTAG master capabilities, where the word basic is doing real work, since the README is not claiming full JTAG functionality.

Two entries are explicitly qualified. EEPROM support comes with the note that some parameters cannot yet be modified, only retrieved, which is the honest way to describe a partially implemented feature. And CBUS support is marked experimental, on selected devices, at 4 pins per port.

Putting those two together, if you need to rewrite an EEPROM or use the CBUS pins, this driver is not the finished answer.

## Installing it and connecting to a device

The installation is a pip install, and the README points to the documentation site for the details rather than spelling them out.

PyFtdi documentation is available from https://eblot.github.io/pyftdi/

The dependency pair is given in the repository's requirements.txt, and it is worth seeing exactly how they are pinned there:

```text
pyusb>=1.0, != 1.2.0
pyserial >= 3.0
```

The same two entries appear in setup.py as install requirements, with the upper version constraint written slightly differently but equivalently:

```python
    'pyusb >= 1.0.0, != 1.2.0',
    'pyserial >= 3.0',
```

The Python version requirement is stated separately: PyFtdi requires Python 3.9+, with the README pointing at pyftdi/doc/requirements.rst for more details. The setup.py classifiers confirm the range, listing Python 3.9 through 3.13, and the most recent release, v0.56.0, was titled Add support for Python 3.13.

What the requirements do not tell you is the host-side part. pyusb needs a working libusb on the machine, and on Linux that usually means a udev rule granting your user access to the device, because the default permission on an FTDI USB node is root only. The README's supported operating systems list includes macOS, Linux, FreeBSD, and Windows, although not officially supported.

The pyftdi/doc/requirements.rst file referenced in the README is the place where the supported combinations are spelled out, and it is the file to consult before committing to a version of Python or a platform.

## The licence question the repository does not settle

There is a genuine discrepancy in this project, and it is the kind of thing that matters if you intend to redistribute anything.

The README's License section states a single SPDX identifier:

```text
SPDX-License-Identifier: BSD-3-Clause
```

The same identifier appears at the top of setup.py as a comment, and the copyright lines there name Emmanuel Blot for 2010-2025 and Neotion for 2010-2016.

But GitHub cannot classify the licence on this repository, with a note to see the LICENSE file. So the SPDX identifier in the README and the licence the repository shows are two different claims, and the README is not the authority on which terms the project has settled.

The practical guidance is to read the LICENSE file before you rely on the BSD-3-Clause terms, and to note the copyright holders. Neotion appears as a copyright holder for the 2010 to 2016 period, which suggests the code has a corporate history behind the current maintainer, and that history is exactly what a licence file settles.

For context on the rest of the project layout, the top level contains a .github/ directory holding the CI workflows, and the README carries three of them as badges: a Python package workflow, a mock tests workflow, and a syntax checks workflow. The separate mock test workflow is the more interesting of the two test paths, since it implies the test suite can run against a mocked USB layer, which is how a driver gets tested without hardware on every machine.

## Where PyFtdi fits, and where it stops

The comparison worth making is with the two other ways to reach an FTDI chip: the kernel driver plus a serial port, and the vendor's native library.

Against the kernel driver, the difference is what you can reach. If you only need a serial port, the kernel tty is simpler, needs no Python at all, and is the better answer. PyFtdi earns its keep when you want the GPIO pins, the MPSSE engine, or the JTAG state machine, because those are exactly the features the kernel does not expose as a serial device. In practice PyFtdi does not replace the kernel driver for serial work; it adds channels next to it.

Against the vendor library, the difference is packaging. A native library means a compiled dependency per platform and per architecture, and often an awkward cross-compilation story. A pure Python driver means pip install and no build step, which matters in a test harness, a CI job or an embedded deployment where compiling a C library is the hard part.

The limits are the ones the README states. The device list is closed: if your FTDI part is not named, it is not supported. JTAG support is described as basic. CBUS is experimental and limited to selected devices at 4 pins per port. EEPROM parameters can be retrieved but not all modified. Windows is supported but not officially supported, which in practice means you may hit something the maintainer does not intend to fix.

On maintenance, the picture is mixed and should be stated plainly. The last push to the repository was on 2026-06-03, the repository is not archived, and the single listed release is v0.56.0 from 2024-11-23, which added Python 3.13 support. That combination suggests a codebase that is still touched but whose packaging has not been cut in a while. A user on Python 3.13 is covered by that release; a user on a newer Python is in the territory the maintainer has not committed to yet.

For a Python developer who needs bitbang, MPSSE or multi-protocol access to an FTDI chip, this is a mature, dependency-light and well-documented option. For a general serial-port user, it is more machinery than the problem requires.

## Conclusion

PyFtdi suits a Python developer who needs to talk to an FTDI chip from a script or a test harness without installing a kernel module or writing against a vendor library, since the whole protocol stack sits in the pyftdi/ package and the dependencies are limited to pyusb and pyserial. It is the wrong tool if you need a device outside the listed FTDI parts, or if you need the EEPROM parameters to be modified rather than read, since the README says some of them cannot yet be modified, only retrieved. Before installing, check that your kernel exposes the device through libusb on the host, since that is where the driver meets the system, and note that the BSD-3-Clause identifier in the README and the licence GitHub shows for the repository are not the same thing, so read the LICENSE file before shipping it in a product.

## FAQ

### What is PyFtdi?

PyFtdi is a user-space driver for popular FTDI devices, implemented in pure Python. It covers UART and GPIO bridges such as the FT232R and the FT230X/FT231X/FT234X, and the multi-protocol parts such as the FT2232H and the FT4232H that also drive SPI, I2C and JTAG.

### What does PyFtdi depend on?

Only pyusb, at 1.0.0 or later with version 1.2.0 excluded, and pyserial at 3.0 or later. The same pair appears in the repository's requirements.txt and in the install requirements of setup.py.

### Which Python versions does PyFtdi support?

PyFtdi requires Python 3.9 or newer, with details in pyftdi/doc/requirements.rst. The setup.py classifiers list Python 3.9 through 3.13, and the release v0.56.0 from 2024-11-23 added support for Python 3.13.

### Can PyFtdi modify the FTDI EEPROM?

Only partly. The README lists EEPROM support with the note that some parameters cannot yet be modified, only retrieved. CBUS support is also marked experimental and limited to selected devices at 4 pins per port.

### Which operating systems does PyFtdi run on?

macOS, Linux and FreeBSD are listed as supported, along with Windows, although not officially supported. On Linux the driver reaches the device through pyusb, so a working libusb and appropriate device permissions are needed.

### What licence is PyFtdi released under?

The README states SPDX-License-Identifier: BSD-3-Clause, and setup.py carries the same identifier in its header with copyright for Emmanuel Blot from 2010 to 2025 and Neotion from 2010 to 2016. GitHub cannot classify the licence for this repository, so the LICENSE file is the authoritative text.

## Sources

- [eblot/pyftdi on GitHub](https://github.com/eblot/pyftdi)
- [Issues](https://github.com/eblot/pyftdi/issues)
- [README](https://github.com/eblot/pyftdi/blob/main/README.md)
- [Releases](https://github.com/eblot/pyftdi/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/eblot-pyftdi
