Pure Python FTDI device driver for USB-to-serial/GPIO/SPI/I2C/JTAG bridge devices
—
GPIO control functionality with multiple controller types supporting different operating modes: asynchronous bitbang, synchronous clocked operation, and high-performance MPSSE mode for various digital I/O applications.
PyFtdi provides three types of GPIO controllers optimized for different use cases.
class GpioAsyncController:
"""Asynchronous GPIO controller using bitbang mode."""
class GpioSyncController:
"""Synchronous GPIO controller with clock signal."""
class GpioMpsseController:
"""High-performance MPSSE-based GPIO controller."""Setup and configure GPIO controllers with pin direction and timing control.
def configure(self, url: str, **kwargs):
"""
Configure GPIO controller with FTDI device.
Parameters:
- url: FTDI device URL (e.g., 'ftdi:///1')
- direction: Initial pin directions (bitmask)
- frequency: Clock frequency for sync/MPSSE modes
- initial: Initial pin states
"""
def terminate(self):
"""Terminate GPIO controller and release device."""Configure pins as inputs or outputs with individual pin control.
def set_direction(self, pins: int, direction: int):
"""
Set GPIO pin directions.
Parameters:
- pins: Pin mask (which pins to modify)
- direction: Direction mask (0=input, 1=output)
Example:
- pins=0xFF, direction=0xF0: Set pins 4-7 as outputs, 0-3 as inputs
- pins=0x01, direction=0x01: Set pin 0 as output
"""
def get_direction(self) -> int:
"""
Get current pin direction configuration.
Returns:
int: Direction bitmask (0=input, 1=output)
"""
def set_pins_as_output(self, pins: int):
"""Set specified pins as outputs."""
def set_pins_as_input(self, pins: int):
"""Set specified pins as inputs."""Read and write digital pin states with bit-level control.
def read(self, with_output: bool = False) -> int:
"""
Read GPIO pin states.
Parameters:
- with_output: Include output pin states in reading
Returns:
int: Pin state bitmask
"""
def write(self, value: int):
"""
Write GPIO pin states.
Parameters:
- value: Pin state bitmask to write
"""
def read_pin(self, pin: int) -> bool:
"""
Read single pin state.
Parameters:
- pin: Pin number (0-7 or 0-15 depending on device)
Returns:
bool: Pin state (True=high, False=low)
"""
def write_pin(self, pin: int, state: bool):
"""
Write single pin state.
Parameters:
- pin: Pin number
- state: Pin state (True=high, False=low)
"""Basic GPIO operations using FTDI bitbang mode for simple digital I/O.
class GpioAsyncController:
"""8-bit asynchronous GPIO using bitbang mode."""
def read_all(self) -> int:
"""Read all 8 GPIO pins simultaneously."""
def write_all(self, value: int):
"""Write all 8 GPIO pins simultaneously."""
def toggle_pin(self, pin: int):
"""Toggle single pin state."""
def pulse_pin(self, pin: int, duration: float):
"""Generate pulse on pin with specified duration."""GPIO operations with synchronous clock for precise timing control.
class GpioSyncController:
"""8-bit synchronous GPIO with clock signal."""
def set_frequency(self, frequency: float) -> float:
"""
Set GPIO clock frequency.
Parameters:
- frequency: Desired frequency in Hz
Returns:
float: Actual configured frequency
"""
def write_with_clock(self, data: list, clock_pin: int):
"""
Write data with clock signal on specified pin.
Parameters:
- data: List of pin states to write
- clock_pin: Pin to use for clock signal
"""
def shift_out(self, data: int, data_pin: int, clock_pin: int,
bit_order: str = 'msb'):
"""
Shift out data serially with clock.
Parameters:
- data: Data to shift out
- data_pin: Pin for data signal
- clock_pin: Pin for clock signal
- bit_order: 'msb' or 'lsb' first
"""
def shift_in(self, num_bits: int, data_pin: int, clock_pin: int,
bit_order: str = 'msb') -> int:
"""
Shift in data serially with clock.
Parameters:
- num_bits: Number of bits to read
- data_pin: Pin for data signal
- clock_pin: Pin for clock signal
- bit_order: 'msb' or 'lsb' first
Returns:
int: Data read
"""High-performance GPIO using MPSSE engine for advanced timing and 16-bit operation.
class GpioMpsseController:
"""16-bit high-performance GPIO using MPSSE engine."""
def read_port(self, wide: bool = False) -> int:
"""
Read GPIO port (8 or 16 bits).
Parameters:
- wide: True for 16-bit read, False for 8-bit
Returns:
int: Port value
"""
def write_port(self, value: int, wide: bool = False):
"""
Write GPIO port (8 or 16 bits).
Parameters:
- value: Port value to write
- wide: True for 16-bit write, False for 8-bit
"""
def set_frequency(self, frequency: float) -> float:
"""Set MPSSE clock frequency for timed operations."""
def read_with_timing(self, count: int, interval: float) -> list:
"""
Read GPIO with precise timing intervals.
Parameters:
- count: Number of readings
- interval: Time interval between readings
Returns:
list: List of GPIO readings
"""
def write_sequence(self, sequence: list, timing: list):
"""
Write sequence of GPIO states with precise timing.
Parameters:
- sequence: List of GPIO values
- timing: List of timing intervals
"""GPIO pin availability by FTDI device:
FT232R:
FT232H:
FT2232H:
FT4232H:
from pyftdi.gpio import GpioAsyncController
# Configure GPIO controller
gpio = GpioAsyncController()
gpio.configure('ftdi:///1')
# Set pin directions: pins 0-3 as outputs, 4-7 as inputs
gpio.set_direction(0xFF, 0x0F)
# Write to output pins
gpio.write(0x05) # Set pins 0 and 2 high
# Read input pins
inputs = gpio.read()
print(f"GPIO state: 0b{inputs:08b}")
# Control individual pins
gpio.write_pin(1, True) # Set pin 1 high
gpio.write_pin(3, False) # Set pin 3 low
pin_state = gpio.read_pin(4) # Read pin 4
print(f"Pin 4 is {'high' if pin_state else 'low'}")
gpio.terminate()from pyftdi.gpio import GpioAsyncController
import time
gpio = GpioAsyncController()
gpio.configure('ftdi:///1')
# Configure pins 0-3 as outputs for LEDs
gpio.set_direction(0x0F, 0x0F)
# LED chase pattern
for i in range(10):
for led in range(4):
gpio.write(1 << led) # Turn on single LED
time.sleep(0.2)
# Turn off all LEDs
gpio.write(0x00)
gpio.terminate()from pyftdi.gpio import GpioAsyncController
import time
gpio = GpioAsyncController()
gpio.configure('ftdi:///1')
# Pin 0 = LED output, Pin 4 = button input
gpio.set_direction(0x11, 0x01)
def read_button_debounced(pin, debounce_time=0.05):
"""Read button with debouncing."""
if gpio.read_pin(pin):
time.sleep(debounce_time)
return gpio.read_pin(pin)
return False
# Button-controlled LED
try:
while True:
if read_button_debounced(4):
gpio.toggle_pin(0) # Toggle LED
print("Button pressed - LED toggled")
time.sleep(0.5) # Prevent rapid toggling
time.sleep(0.01)
except KeyboardInterrupt:
gpio.write(0x00) # Turn off LED
gpio.terminate()from pyftdi.gpio import GpioSyncController
gpio = GpioSyncController()
gpio.configure('ftdi:///1', frequency=100000) # 100kHz clock
# Pin assignments: 0=data, 1=clock, 2=latch
gpio.set_direction(0x07, 0x07) # All outputs
# Shift out 8-bit data
def shift_out_8bit(data):
for bit in range(8):
# Set data bit
gpio.write_pin(0, bool(data & (0x80 >> bit)))
# Clock pulse
gpio.write_pin(1, True)
gpio.write_pin(1, False)
# Latch data
gpio.write_pin(2, True)
gpio.write_pin(2, False)
# Send data to shift register
shift_out_8bit(0xAA) # Send 10101010 pattern
gpio.terminate()from pyftdi.gpio import GpioMpsseController
gpio = GpioMpsseController()
gpio.configure('ftdi:///1')
# Configure as 16-bit wide GPIO
gpio.set_direction(0xFFFF, 0xFF00) # Upper 8 bits output, lower 8 bits input
# High-speed operations
gpio.set_frequency(6000000) # 6MHz operations
# Write pattern to outputs
for i in range(256):
gpio.write_port(i << 8, wide=True) # Shift to upper byte
reading = gpio.read_port(wide=True)
print(f"Wrote: 0x{i:02x}, Read: 0x{reading & 0xFF:02x}")
gpio.terminate()from pyftdi.gpio import GpioAsyncController
import time
# Example: Controlling a relay module and reading sensors
gpio = GpioAsyncController()
gpio.configure('ftdi:///1')
# Pin configuration
RELAY_PINS = 0x0F # Pins 0-3 for relays (outputs)
SENSOR_PINS = 0xF0 # Pins 4-7 for sensors (inputs)
gpio.set_direction(0xFF, RELAY_PINS)
def control_relay(relay_num, state):
"""Control individual relay (0-3)."""
current = gpio.read()
if state:
gpio.write(current | (1 << relay_num))
else:
gpio.write(current & ~(1 << relay_num))
def read_sensors():
"""Read all sensor states."""
gpio_state = gpio.read()
return [(gpio_state >> (4 + i)) & 1 for i in range(4)]
# Control system based on sensor input
try:
while True:
sensors = read_sensors()
# Example logic: Turn on relay 0 if sensor 0 is active
control_relay(0, sensors[0])
# Turn on relay 1 if both sensors 1 and 2 are active
control_relay(1, sensors[1] and sensors[2])
print(f"Sensors: {sensors}")
time.sleep(0.1)
except KeyboardInterrupt:
# Turn off all relays
gpio.write(0x00)
gpio.terminate()from pyftdi.gpio import GpioAsyncController, GpioException
from pyftdi.ftdi import FtdiError
try:
gpio = GpioAsyncController()
gpio.configure('ftdi:///1')
gpio.set_direction(0xFF, 0x0F)
gpio.write(0x05)
state = gpio.read()
except GpioException as e:
print(f"GPIO operation error: {e}")
except FtdiError as e:
print(f"FTDI device error: {e}")
finally:
if 'gpio' in locals():
gpio.terminate()# Exception types
class GpioException(FtdiError):
"""GPIO operation error"""
# Direction constants
GPIO_INPUT = 0
GPIO_OUTPUT = 1
# Pin state constants
GPIO_LOW = False
GPIO_HIGH = TrueInstall with Tessl CLI
npx tessl i tessl/pypi-pyftdi