CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-pyftdi

Pure Python FTDI device driver for USB-to-serial/GPIO/SPI/I2C/JTAG bridge devices

Pending
Overview
Eval results
Files

gpio.mddocs/

GPIO Control

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.

Capabilities

GPIO Controller Types

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."""

Controller Configuration

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."""

Pin Direction Control

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."""

Digital I/O Operations

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)
    """

Asynchronous GPIO (Bitbang Mode)

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."""

Synchronous GPIO (Clocked Mode)

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
        """

MPSSE GPIO (High Performance)

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
        """

Device Support

Pin Assignments

GPIO pin availability by FTDI device:

FT232R:

  • 8 GPIO pins (CBUS0-CBUS7)
  • Asynchronous mode only

FT232H:

  • 16 GPIO pins (AD0-AD7, AC0-AC7)
  • All modes supported
  • MPSSE mode: Full 16-bit operation

FT2232H:

  • 16 GPIO pins per interface (AD0-AD7, AC0-AC7)
  • Independent operation per interface

FT4232H:

  • 4 GPIO pins per interface (CBUS0-CBUS3)
  • Limited GPIO per interface

Electrical Characteristics

  • Logic levels: 3.3V CMOS
  • Drive strength: 4mA per pin (typical)
  • Input threshold: 1.4V typical
  • Pull-up resistors: Internal 75kΩ (when enabled)

Usage Examples

Basic GPIO Control

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()

LED Control

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()

Button Input with Debouncing

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()

Synchronous Serial Communication

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()

High-Speed MPSSE GPIO

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()

Interfacing with External Devices

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()

Exception Handling

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()

Types

# Exception types
class GpioException(FtdiError):
    """GPIO operation error"""

# Direction constants
GPIO_INPUT = 0
GPIO_OUTPUT = 1

# Pin state constants  
GPIO_LOW = False
GPIO_HIGH = True

Install with Tessl CLI

npx tessl i tessl/pypi-pyftdi

docs

core-ftdi.md

eeprom.md

gpio.md

i2c.md

index.md

jtag.md

serial.md

spi.md

usb-tools.md

tile.json