Sam Hooke

These are rough notes from whatever I was working on, interested in or thinking about at the time. They vary greatly in quality and length, but prove useful to me, and hopefully to you too!

Calling MPSSE over FTDI from Python on CentOS 7

If wanting to use MPSSE commands with an FTDI device, you cannot simply use Python pyserial’s serial.Serial(). Instead you must use the FTDI driver in order to switch the device into MPSSE mode.

First the FTDI driver libftdi (and its dependency libusbx) need to be installed on CentOS 7:

yum install libusbx libftdi

Next the udev rules need to be configured to set the correct MODE for the FTDI device.

/etc/udev/rules.d/11-ftdi.rules
SUBSYSTEM=="usb", ATTR{idVendor}=="0403", ATTR{idProduct}=="6001", MODE="0666"
SUBSYSTEM=="usb", ATTR{idVendor}=="0403", ATTR{idProduct}=="6011", MODE="0666"
SUBSYSTEM=="usb", ATTR{idVendor}=="0403", ATTR{idProduct}=="6010", MODE="0666"
SUBSYSTEM=="usb", ATTR{idVendor}=="0403", ATTR{idProduct}=="6014", MODE="0666"
SUBSYSTEM=="usb", ATTR{idVendor}=="0403", ATTR{idProduct}=="6015", MODE="0666"

(Optional: use the GROUP attribute to permit only certain users access).

Install pylibftdi, which allows calling FTDI methods from the libftdi driver.

Finally, you can write Python code to send MPSSE commands:

from pylibftdi import Device

BITMODE_MPSSE = 0x02
INTERFACE_A = 1

DIRECTION_MASK = 0x00

with dev as Device(interface_select=INTERFACE_A):
    dev.baudrate = 9600

    # This is the crucial part!!
    dev.ftdi_fn.ftdi_set_bitmode(DIRECTION_MASK, BITMODE_MPSSE)

    dev.write('\xDE\xAD\xBE\xEF')

The values for BITMODE_MPSSE and INTERFACE_A come from the FTDI documentation. Note that you will want to use either INTERFACE_A through INTERFACE_D accordingly depending upon your situation. Different FTDI chips have different numbers of interfaces.

Issues

I found that testing this in the Python REPL worked fine, but upon integrating it with a larger code base Python would die with “Segmentation fault” upon the call to Device(). As a workaround, I found using lazy_open to delay opening the port along with disabling auto_detach to disable automatically closing the port fixed the issue. For example:

dev = Device(
    interface_select=INTERFACE_A,
    lazy_open=True,
    auto_detach=False,
)
dev.open()
# Do stuff
dev.close()

Alternatives

pyftdi is more stable and contains more features than pylibftdi, however as of v0.22.1 it is Python 3 only, whereas pylibftdi supports Python 2 and 3.

There also exists libmpsse and FTD2XX which I have not tried.

<< Previous: Hugo tag and category pages
Next: Bind hugo to localhost for development >>