A Python library for DLN2 SPI adapters with spidev-compatible API. Originally developed for Pico USB IO Board.
Project description
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-spidevusage - 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 resourcesxfer2(data): Perform full-duplex SPI transferxfer(data): Alias forxfer2()(spidev compatibility)xfer_per_byte(data, delay_ms=5.0): Transfer bytes individually with CS togglingwritebytes(data): Write-only SPI transferreadbytes(length): Read-only SPI transfer (sends zeros)
Properties
max_speed_hz(int): SPI clock frequency in Hzmode(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 transfersdebug(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 testbpw_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
plugdevgroup - 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:
- Fork the repository
- Create a feature branch:
git checkout -b feature-name - Make your changes and add tests
- Ensure code passes linting and tests
- 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-spidevlibrary API - Thanks to the USB and embedded development communities
Related Projects
- Pico USB IO Board: Raspberry Pi Pico-based USB-to-SPI/I2C/GPIO adapter
- py-spidev: Original spidev Python bindings
- libusb: USB library for cross-platform USB device access
- DLN2 Linux Driver: Official Linux kernel driver
For more examples and detailed documentation, visit the project repository.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file dln2_spi_wrapper-0.1.1.tar.gz.
File metadata
- Download URL: dln2_spi_wrapper-0.1.1.tar.gz
- Upload date:
- Size: 21.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1db157571e16d6b520c6367cb79c92952c1bb4ed18bf532e52ff3a6a362d5194
|
|
| MD5 |
3be302b9e87b79d2490095c147fccae1
|
|
| BLAKE2b-256 |
77ed4e2a9ee8bbe08ab323d95159d9a7caa4a2cac490823636953917ca337069
|
File details
Details for the file dln2_spi_wrapper-0.1.1-py3-none-any.whl.
File metadata
- Download URL: dln2_spi_wrapper-0.1.1-py3-none-any.whl
- Upload date:
- Size: 19.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
04f625d4b971e5cc72c4d95cbfda94db0a1a69c5c09dc4910c9cd66140821e77
|
|
| MD5 |
cf67bd52939b9dbb6d7e277908669db4
|
|
| BLAKE2b-256 |
1197274a3b3d3e29acf1dfe21e574d210aa948ec4f0670eb0257e4aa71b44427
|