Skip to content

FTDI FT2232HL Support for Arduino Emulator

Phil Schatzmann edited this page Oct 6, 2025 · 9 revisions

Warning: this functionality is experimental and not fully tested. Please provide some feed back to confirm what's working and what's not!

I have implemented FTDI support (for the FT2232HL) in the Arduino Emulator, which is providing GPIO, SPI, and I2C functionality through USB.

image

Overview

The FTDI FT2232HL is a dual-channel USB-to-UART/SPI/I2C converter that provides:

  • Dual independent channels (Channel A and Channel B)
  • MPSSE mode for high-speed serial protocols (SPI, I2C)
  • Bitbang mode for GPIO operations
  • 16 GPIO pins (8 per channel: ADBUS0-7, BDBUS0-7)

Hardware Requirements

FTDI FT2232HL Device

  • USB connection to host computer
  • External pull-up resistors for I2C (typically 4.7kΩ on SCL and SDA lines)

Pin Mapping

Channel A (Pins 0-7)

  • GPIO Mode: ADBUS0-ADBUS7 available as digital I/O
  • SPI Mode:
    • ADBUS0: SCK (Clock)
    • ADBUS1: MOSI (Master Out, Slave In)
    • ADBUS2: MISO (Master In, Slave Out)
    • ADBUS3-7: Available for CS or other GPIO
  • I2C Mode:
    • ADBUS0: SCL (Clock) - requires 4.7kΩ pull-up
    • ADBUS1: SDA_OUT (Data Out)
    • ADBUS2: SDA_IN (Data In) - requires 4.7kΩ pull-up
    • ADBUS3-7: Available for other functions

Channel B (Pins 8-15)

  • GPIO Mode: BDBUS0-BDBUS7 available as digital I/O
  • Similar protocol support as Channel A

Software Requirements

Dependencies

  • libftdi1: FTDI device communication library
  • pkg-config: For finding libftdi1 (Linux/macOS)
  • FTDI D2XX drivers: Alternative high-performance drivers (optional)

Driver and Library Installation

Linux (Ubuntu/Debian)

Method 1: Using Package Manager (Recommended)

# Install libftdi1 development library and pkg-config
sudo apt-get update
sudo apt-get install libftdi1-dev pkg-config

# Verify installation
pkg-config --libs libftdi1
# Should output: -lftdi1

Method 2: Build from Source

# Install dependencies
sudo apt-get install cmake build-essential libusb-1.0-0-dev

# Clone and build libftdi
git clone https://github.com/libftdi/libftdi.git
cd libftdi
mkdir build && cd build
cmake ..
make
sudo make install
sudo ldconfig

Permissions Setup (Important!)

# Create udev rule for FTDI devices (prevents need for sudo)
sudo tee /etc/udev/rules.d/99-ftdi.rules << EOF
# FTDI FT232/FT2232 devices
SUBSYSTEM=="usb", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001", MODE="0666", GROUP="dialout"
SUBSYSTEM=="usb", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6010", MODE="0666", GROUP="dialout"
SUBSYSTEM=="usb", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6011", MODE="0666", GROUP="dialout"
SUBSYSTEM=="usb", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6014", MODE="0666", GROUP="dialout"
EOF

# Add your user to dialout group
sudo usermod -a -G dialout $USER

# Reload udev rules and restart
sudo udevadm control --reload-rules
sudo udevadm trigger
# Log out and back in, or restart system

Linux (Fedora/CentOS/RHEL)

# Install development libraries
sudo dnf install libftdi1-devel pkgconfig

# Or on older versions:
sudo yum install libftdi1-devel pkgconfig

# Set up permissions (same udev rules as above)

Linux (Arch Linux)

# Install from official repository
sudo pacman -S libftdi pkg-config

# Install from AUR for latest version
yay -S libftdi-git

macOS

Method 1: Using Homebrew (Recommended)

# Install Homebrew if not already installed
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

# Install libftdi
brew install libftdi pkg-config

# Verify installation
pkg-config --libs libftdi1

Method 2: Using MacPorts

# Install MacPorts, then:
sudo port install libftdi1 +universal

Method 3: Build from Source

# Install dependencies
brew install cmake libusb pkg-config

# Clone and build
git clone https://github.com/libftdi/libftdi.git
cd libftdi
mkdir build && cd build
cmake .. -DCMAKE_INSTALL_PREFIX=/usr/local
make
sudo make install

Windows

Method 1: Using vcpkg (Recommended for Development)

# Install vcpkg
git clone https://github.com/Microsoft/vcpkg.git
cd vcpkg
.\bootstrap-vcpkg.bat

# Install libftdi1
.\vcpkg install libftdi1:x64-windows
# Or for 32-bit: .\vcpkg install libftdi1:x86-windows

# Integrate with Visual Studio
.\vcpkg integrate install

Method 2: Pre-built Libraries

  1. Download FTDI D2XX drivers:

    • Go to FTDI website
    • Download "D2XX Direct Drivers" for Windows
    • Install the driver package
  2. Download libftdi1 binaries:

    • Download from libftdi releases
    • Extract to C:\libftdi1\
    • Add C:\libftdi1\bin to PATH

Method 3: MSYS2/MinGW

# In MSYS2 terminal
pacman -S mingw-w64-x86_64-libftdi mingw-w64-x86_64-pkg-config

Windows Driver Notes

  • Windows 10/11: Drivers are usually installed automatically
  • Older Windows: May need manual driver installation from FTDI website
  • Driver conflicts: If device doesn't work, check Windows Device Manager
  • Virtual Serial Port: Windows may create COM ports - disable if using direct FTDI access

Verification Steps

Test FTDI Device Detection

# Linux/macOS: List USB devices
lsusb | grep -i ftdi
# Should show something like: "Bus 001 Device 005: ID 0403:6010 Future Technology Devices International, Ltd FT2232C/D/H Dual UART/FIFO IC"

# Check device permissions (Linux)
ls -l /dev/bus/usb/001/005  # Use actual bus/device numbers
# Should show readable/writable permissions for your user

# Test with libftdi tools (if available)
ftdi_eeprom --help

Test Library Installation

// Simple test program
#include <ftdi.h>
#include <iostream>

int main() {
    struct ftdi_context *ftdi = ftdi_new();
    if (!ftdi) {
        std::cout << "Failed to create FTDI context" << std::endl;
        return -1;
    }
    
    // Try to open first FTDI device
    int ret = ftdi_usb_open(ftdi, 0x0403, 0x6010);
    if (ret == 0) {
        std::cout << "FTDI device opened successfully!" << std::endl;
        ftdi_usb_close(ftdi);
    } else {
        std::cout << "Failed to open FTDI device: " << ftdi_get_error_string(ftdi) << std::endl;
    }
    
    ftdi_free(ftdi);
    return 0;
}
# Compile test (Linux/macOS)
g++ test_ftdi.cpp -lftdi1 -o test_ftdi
./test_ftdi

Building with FTDI Support

CMake Configuration

# Enable FTDI support during configuration
cmake -B build -S . -DUSE_FTDI=ON

# Optional: Also enable other features
cmake -B build -S . -DUSE_FTDI=ON -DUSE_RPI=ON

# Build the project
cmake --build build

Example Sketch CMakeLists.txt

cmake_minimum_required(VERSION 3.11...3.19)

# Simple FTDI sketch
arduino_sketch(my_ftdi_project main.ino)

# FTDI sketch with additional libraries  
arduino_sketch(sensor_project sensor.ino LIBRARIES MySensorLib)

Usage Examples

Basic Setup

#include "Arduino.h"

#ifdef USE_FTDI
#include "HardwareSetupFTDI.h"
#endif

void setup() {
  Serial.begin(115200);
  
#ifdef USE_FTDI
  // Initialize FTDI with default parameters (VID:0x0403, PID:0x6010)
  if (FTDI.begin()) {
    Serial.println("FTDI initialized successfully");
  } else {
    Serial.println("FTDI initialization failed");
  }
#endif
}

GPIO Operations

void setup() {
  // Configure pins
  pinMode(0, OUTPUT);    // ADBUS0 as output
  pinMode(1, INPUT);     // ADBUS1 as input
  pinMode(8, OUTPUT);    // BDBUS0 as output (Channel B)
}

void loop() {
  // Digital write/read
  digitalWrite(0, HIGH);
  int state = digitalRead(1);
  
  // Channel B GPIO
  digitalWrite(8, !digitalRead(8)); // Toggle pin 8
  
  delay(1000);
}

SPI Communication

#include <SPI.h>

void setup() {
  SPI.begin();
  pinMode(3, OUTPUT); // Use ADBUS3 as chip select
  digitalWrite(3, HIGH);
}

void loop() {
  digitalWrite(3, LOW);  // Select device
  
  SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE0));
  uint8_t response = SPI.transfer(0x42);
  SPI.endTransaction();
  
  digitalWrite(3, HIGH); // Deselect device
  
  Serial.print("SPI Response: 0x");
  Serial.println(response, HEX);
  delay(1000);
}

I2C Communication

#include <Wire.h>

void setup() {
  Wire.begin();
  Wire.setClock(100000); // 100kHz
}

void loop() {
  // Write to I2C device at address 0x48
  Wire.beginTransmission(0x48);
  Wire.write(0x01); // Register address
  Wire.write(0xAB); // Data
  uint8_t error = Wire.endTransmission();
  
  if (error == 0) {
    Serial.println("I2C write successful");
  }
  
  // Read from I2C device
  Wire.requestFrom(0x48, 1);
  if (Wire.available()) {
    uint8_t data = Wire.read();
    Serial.print("I2C data: 0x");
    Serial.println(data, HEX);
  }
  
  delay(1000);
}

Device Selection

void setup() {
  // Select specific FTDI device by VID/PID
  FTDI.setDeviceParams(0x0403, 0x6010);
  
  // Or by description/serial
  FTDI.setDeviceParams(0x0403, 0x6010, "My FTDI Device", "FT123456");
  
  if (FTDI.begin()) {
    Serial.println("Specific FTDI device found");
  }
}

API Reference

HardwareSetupFTDI Class

class HardwareSetupFTDI {
public:
  bool begin(bool asDefault = true);
  void end();
  void setDeviceParams(int vendor_id, int product_id, 
                      const char* description = nullptr, 
                      const char* serial = nullptr);
  
  HardwareGPIO_FTDI* getGPIO();
  HardwareI2C_FTDI* getI2C();
  HardwareSPI_FTDI* getSPI();
};

// Global instance
extern HardwareSetupFTDI FTDI;

Supported Arduino Functions

  • GPIO: pinMode(), digitalWrite(), digitalRead()
  • SPI: Full SPI library compatibility
  • I2C: Full Wire library compatibility

Limitations

  • No analog I/O (analogRead/analogWrite) - FT2232HL is digital only
  • No PWM support - use external PWM controller if needed
  • No tone generation - use external buzzer controller
  • No pulse measurement functions - would require custom implementation

Troubleshooting

Common Issues

1. "Failed to open FTDI device"

  • Check USB connection
  • Verify device permissions (sudo or udev rules)
  • Ensure correct VID/PID values

2. "libftdi1 not found"

  • Install libftdi1-dev package
  • Check pkg-config can find libftdi1: pkg-config --libs libftdi1

3. I2C Communication Fails

  • Verify pull-up resistors on SCL and SDA (typically 4.7kΩ)
  • Check device address (7-bit vs 8-bit addressing)
  • Ensure proper connections

4. SPI Issues

  • Verify wiring: SCK, MOSI, MISO connections
  • Check SPI mode and clock settings
  • Ensure proper chip select timing

5. PWM

Frequency Guide
Use Case Recommended Hz Notes
LED dimming 200-1000 Avoid visible flicker (>100 Hz)
Motor control 500-2000 Balance between smoothness and accuracy
Servo 50 Standard RC servo frequency
Fan control 25-100 Low frequency for quiet operation
Audio tone 100-5000 Limited quality, for beeps only
Jitter Guidelines
Jitter (µs) Rating Action
< 10 Excellent No action needed
10-50 Good Acceptable for most uses
50-100 Fair Consider optimization
> 100 Poor Enable real-time priority or reduce frequency
Enable Real-Time Priority
One-time setup (requires reboot):
sudo nano /etc/security/limits.conf
# Add these lines (replace 'username'):
username    soft    rtprio    99
username    hard    rtprio    99
Verify after reboot:
ulimit -r
# Should show: 99

Cross-Platform Build Instructions

Linux Build

# After installing dependencies above
cmake -B build -S . -DUSE_FTDI=ON
cmake --build build

# Run example
./build/examples/ftdi-test/ftdi-test

macOS Build

# Same as Linux after installing via Homebrew
cmake -B build -S . -DUSE_FTDI=ON
cmake --build build

Windows Build (Visual Studio)

# Using vcpkg toolchain
cmake -B build -S . -DUSE_FTDI=ON -DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake
cmake --build build --config Release

# Or open in Visual Studio and build

Windows Build (MSYS2/MinGW)

# In MSYS2 MinGW64 terminal
cmake -B build -S . -DUSE_FTDI=ON -G "MinGW Makefiles"
cmake --build build

Common Installation Issues

Linux Issues

  • Permission denied: Check udev rules and user groups
  • Library not found: Run sudo ldconfig after installation
  • CMake can't find libftdi1: Install pkg-config package

macOS Issues

  • Homebrew not found: Install Homebrew first
  • Library architecture mismatch: Use brew install libftdi --universal
  • Permission issues: Usually not needed on macOS

Windows Issues

  • Driver not installed: Install FTDI D2XX drivers from FTDI website
  • Library not found: Ensure libftdi1 DLLs are in PATH
  • COM port conflicts: Disable VCP drivers in Windows Device Manager if using direct access

Debug Output

Enable debug logging:

void setup() {
  Serial.begin(115200);
  Logger.setLevel(LogLevel::Debug); // Enable debug messages
}

Performance Notes

  • GPIO: Suitable for moderate-speed digital I/O
  • SPI: Up to ~10MHz clock speeds supported
  • I2C: Standard (100kHz) and Fast (400kHz) modes supported
  • Latency: USB communication introduces some latency compared to native hardware
Clone this wiki locally