Programming FTDI devices in Python: Part 2

Using pylibftdi on Linux

Linux and pylibftdi

In the first part, I used the FTDI Windows D2XX driver and Python ftd2xx library to do some simple I/O testing on an FTDI module. However, when attempting to run the same code on Linux, I had problems getting the d2xx driver to cooperate with the ftd2xx library, so switched to using the pylibftdi library, which uses the open-source libftdi driver in place of d2xx.

Installation is as you’d expect: use sudo apt-get (or equivalent) to install libftdi 1.x, then sudo pip (or pip3) to install pylibftdi. There are then a couple of Linux-specific issues:

  • If you want to avoid running all your code as root, you need to give permission for user-space applications to access the USB device. FTDI devices usually have a PID of 0403, so to allow user access to all FTDI devices, create a file /etc/udev/rules.d/99-libftdi.rules with the contents:
    SUBSYSTEMS=="usb", ATTRS{idVendor}=="0403", GROUP="dialout", MODE="0660"

    Then re-plug the device for the new rule to take effect. This rule will apply to all devices with the FTDI vendor ID, for security reasons you may need to restrict it to devices that match a specific product ID as well.

  •  By default, Linux will load ftdi_sio and usbserial kernel modules when the device is plugged in. Various ways of preventing this have been posted on the Internet, but fortunately libftdi works fine without having to unload the modules.

To see if the library is working, try listing all the FTDI devices:

import sys, pylibftdi as ftdi

This should return a list of devices, each with manufacturer, description and serial number, e.g.

[('FTDI', 'FT2232H MiniModule', 'FT2FNDAR')]

Device I/O

Enabling bitbang mode is similar to the D2XX function calls used in part 1:

d = ftdi.Device()                  # Open first device
OP = 1                             # Bit 0 will be an output
d.ftdi_fn.ftdi_set_bitmode(OP, 1)  # Return 0 if bitbang mode set OK

A baud rate of 9600 is set by default, so the O/P bit clock rate should be 16 times that, as discussed in the previous post.

The differences in Python 2.7 and 3.x byte string handling are still a potential problem, though the pylibftdi library goes some way towards addressing this by using a ‘Latin 1’ encoder to translate between unicode and binary strings. However, to simplify the manipulation and storage of transmit & receive data, I am retaining the list-of-integers storage method used in the first part;

def ft_write(d, data):
    s = str(bytearray(data)) if sys.version_info<(3,) else bytes(data)
    return d.write(s)
ft_write(d, (OP, 0))

def ft_read(d, nbytes):
    s =
    return [ord(c) for c in s] if type(s) is str else list(s)
ft_read(d, 1)

As before, the read cycle returns [254], since the unused pins are floating high, and we have set bit 0 low.

See the next post for an example of code that runs on Linux and Windows.

Copyright (c) Jeremy P Bentham 2018. Please credit this blog if you use the information or software in it.

Caterpillar pic chip small

Programming FTDI devices in Python: Part 1

If you are a Python programmer, and need a simple USB interface for some hardware, read on…

FTDI are well known for their USB-to-serial chips, but the later models (such as FT2232C and FT232H) have various other capabilities; when combined with Python, you get a simple yet powerful method of controlling & monitoring a wide variety of hardware devices.


Various FTDI-equipped modules and cables are available.


A few points to bear in mind:

  • The module may need to have some of its pins linked together, otherwise it won’t power up.
  • If the module has a 5 Volt output pin, take care when connecting it up; if mis-connected, a sizeable current may flow, causing significant damage.
  • Each FTDI device has a unique set of capabilities; check the datasheet to make sure the part has the facilities you need.

Device driver

As standard, when an FTDI device is plugged into a Windows PC, the operating system loads the default Virtual Com Port driver, that can only handle asynchronous serial (RS232-type) protocols. However, we want to be a bit more adventurous, so need to substitute the ‘d2xx’ driver, available from the FTDI drivers page. A quick way to check which driver is active is to look at the Device Manager; if the FTDI part appears as a COM port, it is asynchronous-only.

Use ‘pip’ to install a Python library that will access the d2xx driver; there are several available (such as pyftdi, pylibftdi) but the only one that worked seamlessly with Python 2.7 and 3.x on my systems was the simplest: ftd2xx, which is just a CTYPES wrapper round the d2xx API

pip install ftd2xx

A quick check to see if all is well (Python 2.7 or 3.x):

import sys, ftd2xx as ftd
d =    # Open first FTDI device

This should print some dictionary entries for the device, e.g.

{'serial': 'FT28C9AHA', 'type': 4L, 'id': 67330064L, 'description': 'DLP2232M A'}

If this fails, it is usually because the device is still using the VCP driver, or the Python library can’t find the necessary FTDI files (ftd2xx.lib, and ftd2xx.dll or ftd2xx64.dll);  they need to be somewhere on the executable PATH.

Linux drivers are discussed in the next post.


Before sending any data to the device, we need to establish which pins does what, as all pin functions are pre-assigned. Each chip has 1 or more ‘channels’, i.e. protocol engines, so a 2-channel device can drive 2 separate protocol streams, though there may be a limitation on the protocols a channel can handle. Each channel is assigned to one or more ports, which are usually 8-bit, but may have as many as 10 or as few as 4 bits. The first port of the first channel is identified as ADBUS; if that channel has a second port, it would be ACBUS. The first port of the second channel (if present) is BDBUS, the second port of that channel would be BCBUS.

The serial I/O functions are generally constrained to the lower few bits of the first port, the rest of the lines act as general status or handshake I/O. For example, the 2-channel FT2232C device channel A has pins ADBUS 0 – 7 and ACBUS 0 – 3:

CHANNEL A                           CHANNEL B
ADBUS0   TxD    D0        TCK/SK    BDBUS0   TxD    D0        -
ADBUS1   RxD    D1        TDI/DO    BDBUS1   RxD    D1        -
ADBUS2   RTS    D2        TDO/DI    BDBUS2   RTS    D2        -
ADBUS3   CTS    D3        TMS/CS    BDBUS3   CTS    D3        -
ADBUS4   DTR    D4        GPIOL0    BDBUS4   DTR    D4        -
ADBUS5   DSR    D5        GPIOL1    BDBUS5   DSR    D5        -
ADBUS6   DCD    D6        GPIOL2    BDBUS6   DCD    D6        -
ADBUS7   RI     D7        GPIOL3    BDBUS7   RI     D7        -
ACBUS0   TXDEN  WR        GPIOH0    BCBUS0   TXDEN  WR        -
ACBUS1   SLEEP  RD        GPIOH1    BCBUS1   SLEEP  RD        -
ACBUS3   TXLED  OSC       GPIOH3    BCBUS3   TXLED  OSC       -

The GPIOL and GPIOH prefixes refer to the low & high byte output commands that we’ll encounter later when using MPSSE mode for synchronous protocols; also note that channel B is unusable in that mode.

A possible source of confusion is that pins 1 and 2 in MPSSE mode are identified as TDI/DO and TDO/DI, implying that they can act as inputs or outputs. This is incorrect: in MPSSE mode, pin 1 is normally an output, and pin 2 is an input. The reason for the TDI and TDO labels is that they refer to the JTAG protocol, which is defined from the point of view of the device being controlled, not the controller – so the DO and DI labels apply in normal usage.

Also note that the device has a tendency to keep its previous settings, even after a reset. For this reason, all programs using the ftd2xx library normally start by clearing everything in the device to zero, just in case a preceding program has left some settings active. For simplicity, the code given below ignores this requirement, and assumes the device has been  re-plugged just before the code was run.

Bitbang mode: toggling an I/O pin

‘bitbashing’ which FTDI call ‘bitbanging’, refers to driving the I/O pins directly, rather than using an I/O protocol embedded in the device.

The FTDI device powers up in ‘reset mode’ and must be set to bitbang mode using the setBitmode function. One advantage of using the Python ftd2xx library is that the function arguments are as documented in the FTDI ‘D2XX Programmers Guide’:

OP = 0x01            # Bit mask for output D0
d.setBitMode(OP, 1)  # Set pin as output, and async bitbang mode
d.write(str(OP))     # Set output high
d.write(str(0))      # Set output low

Having set our chosen pin as an output, and enabled bitbang mode, writing a string to the device handle will set its state. The ‘write’ functions returns the number of characters written, which is 1 in this case. If your application involves sending out a succession of O/P pulses, you’ll want to know how fast the operation is; sending the following commands:

d.write(chr(OP)); d.write(chr(0))

results in a positive pulse somewhere between 500 microseconds and 2 milliseconds wide. This will be too variable and too slow for many applications, so an alternative is to write a string containing multiple data values, e.g.

d.write(chr(OP) + chr(0))

This results in a pulse 50 nanoseconds wide, which is probably too narrow for most applications, however in theory you can just duplicate a command to stretch it out, for example to generate a pulse of 200 nanoseconds:

d.write(chr(OP)*4 + chr(0))

This approach is somewhat inefficient, and works fine on Python 2.7, but not on Python 3.x; if you connect an  oscilloscope to the output, you’ll see a couple of cycles of 10 MHz square-wave, instead of a single broad pulse. Using a USB analyser to monitor the data, it is apparent that the code is sending the bytes 01 00 01 00 01 instead of  01 01 01 01 00; the length is correct, but the data values are wrong, because of the different ways Python 2.7 and 3.x store their strings.

Byte values in Python 2.7 and 3.x

The default string type can’t be used for byte data in 3.x, as the characters are 16-bit Unicode values, not bytes. There are various ways round the problem, the simplest is to force the string type to binary:


This is fine for preformatted strings, but gets rather messy if the data is being computed on-the-fly. There are plenty of alternative suggestions on the Internet, but many don’t work in special cases, such as bit 7 being set. The ‘bytearray’ type would be useful, except that it is rejected as an unknown type by the ftd2xx library. The ‘bytes’ datatype is good on v3, but works very differently on v2.7, so for my development I reluctantly decided to store all outgoing data as lists of integers, with a version-dependant conversion function on writing, e.g.

def ft_write(d, data):
    s = str(bytearray(data)) if sys.version_info<(3,) else bytes(data)
    return d.write(s)

ft_write(d, [OP]*4 + [0])

Slowing down output transitions

Sending multiple output commands to slow down the output transitions is quite inefficient, and unworkable for really long pulses. A better alternative is to program the baud rate generator (the same generator as used for serial communications), which synchronises the transitions, e.g.

ft_write(d, (OP, 0))

The FTDI Application Note states that the output is clocked at 16 times the baud rate, so  9600 baud should result in a timing of 6.51 microseconds per bit. However, on an FT2232H module the time was measured as 20.825 microseconds, so that logic seemingly doesn’t apply to all modules.

Reading input pins

Finally we get to read some data in:


The length of 1 returns an 8-bit value corresponding to the I/O pin states; as before, the returned type depends on the Python version, so I convert it to a list of integers:

def ft_read(d, nbytes):
    s =
    return [ord(c) for c in s] if type(s) is str else list(s)

print(ft_read(d, 1))

Unused inputs float high, and the last output command drove the ADBUS0 output low, so the value printed is 254 in a list, [254].

You can implement quite complex protocols using simple I/ O commands; write-cycles can be chained to output complex sequences, but there is quite a speed-penalty every time a read-cycle has to be interleaved. In recognition of this, many FTDI chips have a more complex capability, which they call MPSSE (Multi-Protocol Synchronous Serial Engine); that’ll be the subject of a later blog post…

See the next post to run the code on Linux…

Copyright (c) Jeremy P Bentham 2018. Please credit this blog if you are using the information or software in it.