Skip to content

ipmgroup/dln2_spi_wrapper

Repository files navigation

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.

About

Pico USB SPI(DLN2) Board Python Wrapper

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors