Skip to content

Latest commit

 

History

History
389 lines (272 loc) · 9.7 KB

File metadata and controls

389 lines (272 loc) · 9.7 KB

DLN2 SPI Wrapper

A Python library for interfacing with DLN2 USB-to-SPI adapters with a spidev-compatible API. This package allows existing Python code written for py-spidev to work with DLN2 devices with minimal modifications.

Originally developed for the Pico USB IO Board - a Raspberry Pi Pico-based USB-to-SPI/I2C/GPIO adapter that implements the DLN2 protocol.

Features

  • spidev-compatible API: Drop-in replacement for most py-spidev usage
  • Cross-platform support: Works on Linux, Windows, and macOS
  • Multiple transfer modes: Single transfers, per-byte transfers with CS control
  • Configurable parameters: SPI mode, frequency, bits per word
  • Built-in examples: Ready-to-use test scripts and utilities
  • Pure Python: No compiled extensions, easy to install and distribute
  • Pico USB IO Board support: Native support for Raspberry Pi Pico-based DLN2 adapters

Supported Hardware

  • Pico USB IO Board - Raspberry Pi Pico-based USB-to-SPI/I2C/GPIO adapter with DLN2 protocol implementation
  • DLN2 devices - USB-to-SPI adapters implementing the DLN2 protocol (VID: 0x1d50, PID: 0x6170)
  • Compatible devices - Any USB device that implements the DLN2 SPI interface

Installation

From PyPI (recommended)

pip install dln2-spi-wrapper

From source

git clone https://github.com/ipmgroup/dln2_spi_wrapper.git
cd dln2_spi_wrapper
pip install .

Development installation

git clone https://github.com/ipmgroup/dln2_spi_wrapper.git
cd dln2_spi_wrapper
pip install -e ".[dev]"

Prerequisites

  • Python 3.7+
  • pyusb: Automatically installed as a dependency
  • DLN2-compatible device:
    • Pico USB IO Board (recommended)
    • Any DLN2 USB-to-SPI adapter (VID: 0x1d50, PID: 0x6170)

USB permissions (Linux)

On Linux, you may need to set up udev rules to access the DLN2 device without root privileges:

# Create udev rule for DLN2 device
echo 'SUBSYSTEM=="usb", ATTR{idVendor}=="1d50", ATTR{idProduct}=="6170", MODE="0666", GROUP="plugdev"' | sudo tee /etc/udev/rules.d/99-dln2.rules
sudo udevadm control --reload-rules
sudo udevadm trigger

Make sure your user is in the plugdev group:

sudo usermod -a -G plugdev $USER
# Log out and log back in for the group change to take effect

Quick Start

Basic Usage

from dln2_spi_wrapper import SpiDev

# Create SPI device instance
spi = SpiDev()

# Open the device (bus and device parameters are ignored for DLN2)
spi.open(0, 0)

# Configure SPI parameters
spi.max_speed_hz = 1000000  # 1 MHz
spi.mode = 0               # SPI mode 0 (CPOL=0, CPHA=0)
spi.bits_per_word = 8      # 8 bits per word

# Perform SPI transaction
tx_data = [0x9F, 0x00, 0x00]  # Example: JEDEC ID command
rx_data = spi.xfer2(tx_data)
print(f"Received: {[hex(b) for b in rx_data]}")

# Close the device
spi.close()

Context Manager Usage

from dln2_spi_wrapper import SpiDev

with SpiDev() as spi:
    spi.open(0, 0)
    spi.max_speed_hz = 1000000
    spi.mode = 0
    
    # Send command and receive response
    response = spi.xfer2([0x9F, 0x00, 0x00, 0x00])
    print(f"Device ID: {' '.join(f'{b:02x}' for b in response)}")

Advanced Usage

from dln2_spi_wrapper import SpiDev

spi = SpiDev()
spi.open(0, 0)

# Configure advanced options
spi.max_speed_hz = 10000000  # 10 MHz
spi.mode = 1                # SPI mode 1
spi.bits_per_word = 16      # 16-bit words
spi.host_hold_cs = True     # Keep CS asserted between transfers

# Per-byte transfers with CS toggling
data = [0x01, 0x02, 0x03]
response = spi.xfer_per_byte(data, inter_byte_delay_ms=1.0)

# Write-only operation
spi.writebytes([0xAA, 0xBB, 0xCC])

# Read-only operation  
received = spi.readbytes(4)

spi.close()

API Reference

SpiDev Class

The main class providing spidev-compatible interface.

Methods

  • open(bus, device): Open SPI device (bus/device ignored for DLN2)
  • close(): Close SPI device and release resources
  • xfer2(data): Perform full-duplex SPI transfer
  • xfer(data): Alias for xfer2() (spidev compatibility)
  • xfer_per_byte(data, delay_ms=5.0): Transfer bytes individually with CS toggling
  • writebytes(data): Write-only SPI transfer
  • readbytes(length): Read-only SPI transfer (sends zeros)

Properties

  • max_speed_hz (int): SPI clock frequency in Hz
  • mode (int): SPI mode (0-3, sets CPOL and CPHA)
  • bits_per_word (int): Word size in bits (1-16)
  • host_hold_cs (bool): Keep CS asserted between transfers
  • debug (bool): Enable debug output

Low-level API

For advanced use cases, you can access the low-level DLN2 client:

from dln2_spi_wrapper import Dln2Usb, find_device

# Find and connect to DLN2 device
device = find_device()
client = Dln2Usb(device, debug=True)

# Enable SPI
client.spi_enable()

# Configure SPI settings
client.spi_set_frequency(1000000)
client.spi_set_mode(0)

# Perform raw SPI transfer
tx_bytes = b'\x9f\x00\x00'
rx_bytes = client.spi_read_write(tx_bytes, leave_ss_low=False)

# Clean up
client.spi_disable()
client.close()

Command Line Tools

The package includes command-line utilities:

SPI Test Tool

Test SPI communication with automatic backend detection:

dln2-spi-test --backend dln --verbose

Options:

  • --backend {auto,dln,native}: Choose SPI backend
  • --host-cs: Use host-controlled chip select
  • --verbose: Enable debug output
  • --per-byte: Send bytes individually
  • --inter-byte-delay DELAY: Delay between bytes in milliseconds

Bits-per-Word Tester

Test different word sizes (4-16 bits):

dln2-spi-bpw-test

This utility cycles through different bits-per-word settings and sends test patterns.

Examples

See the examples/ directory for more usage examples:

  • spidev_test.py: Basic SPI communication test
  • bpw_tester.py: Bits-per-word functionality test

Compatibility

spidev API Coverage

This library implements the most commonly used parts of the py-spidev API:

Feature Status Notes
open() / close() Bus/device params ignored
xfer() / xfer2() Full duplex transfers
writebytes() / readbytes() Half duplex transfers
max_speed_hz Frequency control
mode SPI modes 0-3
bits_per_word 1-16 bit words
Context manager with SpiDev() as spi:
cshigh / lsbfirst 📝 Properties exist but limited DLN2 support

Platform Support

  • Linux: Full support with udev rules for device access
  • Windows: Full support with libusb-win32/WinUSB drivers
  • macOS: Full support with libusb

Python Version Support

  • Python 3.7+
  • Tested on CPython and PyPy

Troubleshooting

Device Not Found

ValueError: DLN2 device not found (VID:PID 1d50:6170)

Solutions:

  • Check device is connected and powered
  • Verify USB cable and connection
  • On Linux, check udev rules and user permissions
  • Try running with sudo (not recommended for production)

Permission Denied (Linux)

usb.core.USBError: [Errno 13] Access denied (insufficient permissions)

Solutions:

  • Set up udev rules (see installation instructions)
  • Add user to plugdev group
  • Check that the device isn't claimed by kernel driver

Import Errors

ModuleNotFoundError: No module named 'usb'

Solution:

pip install pyusb

Transfer Errors

RuntimeError: SPI transfer failed: result=X

Check:

  • SPI device is properly connected
  • Correct SPI mode and frequency settings
  • Adequate power supply for target device
  • Proper wiring (MOSI, MISO, SCK, CS)

Development

Setting up Development Environment

git clone https://github.com/ipmgroup/dln2_spi_wrapper.git
cd dln2_spi_wrapper

# Create and activate virtual environment
python3 -m venv venv
source venv/bin/activate

# Install in development mode with all dependencies
pip install -e ".[dev]"

Building and Publishing

# Build package
make build

# Check package integrity  
make check

# Upload to TestPyPI (requires API token)
make upload-test

# Upload to PyPI (requires API token)
make upload

# Or use the interactive script
./publish.sh

For detailed publishing instructions, see PUBLISHING.md and QUICKSTART.md.

Running Tests

pytest tests/

Code Formatting

black dln2_spi_wrapper/

Type Checking

mypy dln2_spi_wrapper/

Contributing

Contributions are welcome! Please:

  1. Fork the repository
  2. Create a feature branch: git checkout -b feature-name
  3. Make your changes and add tests
  4. Ensure code passes linting and tests
  5. Submit a pull request

License

This project is licensed under the Apache License 2.0. See LICENSE for details.

Acknowledgments

  • Originally developed for the Pico USB IO Board project
  • Based on DLN2 protocol implementation
  • Inspired by the py-spidev library API
  • Thanks to the USB and embedded development communities

Related Projects


For more examples and detailed documentation, visit the project repository.