Adafruit CircuitPython Bus Device
Adafruit CircuitPython Bus Device provides helper classes, `I2CDevice` and `SPIDevice`, to simplify managing transaction state on I2C and SPI buses. It handles bus locking, device addressing for I2C, and chip select and protocol changes for SPI. The library is actively maintained by Adafruit, with frequent releases to address bug fixes and add minor enhancements. The current version is 5.2.16.
Common errors
-
ImportError: No module named 'adafruit_bus_device.i2c_device'
cause The `adafruit_bus_device` library is not installed, or the `adafruit_bus_device` folder is missing from the `lib` directory on a CircuitPython board, or there's a conflict with a built-in version.fixFor CPython, run `pip install adafruit-circuitpython-busdevice`. For CircuitPython, ensure the `adafruit_bus_device` folder from the latest library bundle is copied to `CIRCUITPY/lib`, and check if your firmware has it built-in (see warnings). -
AttributeError: 'I2C' object has no attribute 'readinto' (or 'write', 'writeto_then_readfrom')
cause You are attempting to use `I2CDevice` methods directly on a `busio.I2C` object, or outside of its context manager (`with i2c_device:` block). `I2CDevice` provides these methods and manages bus locking.fixAlways interact with I2C devices through an `I2CDevice` instance and preferably within a `with` statement. Example: `with i2c_device: i2c_device.readinto(buf)`. -
TypeError: function takes 1 positional arguments but 2 were given
cause This specific `TypeError` has been observed when using `DebugI2C` from `adafruit_debug_i2c` with the core `adafruit_bus_device` implementation, indicating a mismatch in expected arguments for certain internal methods, possibly related to `probe` or initialization.fixThis points to a known compatibility issue. Consult the Adafruit CircuitPython GitHub issues (specifically `adafruit/circuitpython#10890`) for the most up-to-date workarounds or fixes. Temporarily, some users have resorted to using the pure Python `adafruit_bus_device` implementation if debugging is critical. -
ValueError: Incompatible .mpy file
cause The pre-compiled Python module (`.mpy` file) for `adafruit_bus_device` (or a library that depends on it) was created with a different major version of CircuitPython than what is currently running on the board.fixUpdate all CircuitPython libraries on your board using the latest Adafruit CircuitPython Library Bundle that matches your board's firmware version. This ensures all `.mpy` files are compatible.
Warnings
- gotcha On CircuitPython boards running v6.3.0 or newer firmware, `adafruit_bus_device` may be built-in. Installing an additional copy into the 'lib' directory can cause import conflicts and lead to unexpected errors in libraries that depend on it.
- gotcha `ImportError: No module named 'adafruit_bus_device'` in CPython (e.g., Raspberry Pi) often indicates the library or a core dependency like `adafruit-blinka` is missing.
- gotcha Encountering `AttributeError: 'DebugI2C' object has no attribute 'probe'` when using `DebugI2C` with `adafruit_bus_device` can occur due to an incompatibility between `DebugI2C` and the core CPython implementation of `adafruit_bus_device`.
- gotcha CircuitPython `.mpy` files (pre-compiled modules) are version-specific. An `ValueError: Incompatible .mpy file` will occur if `adafruit_bus_device` (or a library depending on it) was compiled for a different major CircuitPython version than currently running on your board (e.g., 6.x vs 7.x).
- gotcha The `SPIDevice` class might fail to initialize if `libgpiod` bindings are absent on certain Linux systems when using direct hardware SPI, as noted in release 5.2.15.
Install
-
pip install adafruit-circuitpython-busdevice -
Download the Adafruit CircuitPython Library Bundle from circuitpython.org/libraries and copy the 'adafruit_bus_device' folder to the 'lib' directory on your CIRCUITPY drive.
Imports
- I2CDevice
from adafruit_bus_device import I2CDevice
from adafruit_bus_device.i2c_device import I2CDevice
- SPIDevice
from adafruit_bus_device import SPIDevice
from adafruit_bus_device.spi_device import SPIDevice
Quickstart
import board
import busio
import digitalio
from adafruit_bus_device.i2c_device import I2CDevice
from adafruit_bus_device.spi_device import SPIDevice
# --- I2C Example ---
# Replace with your actual I2C device address (e.g., 0x68 for DS3231)
I2C_DEVICE_ADDRESS = 0x68
I2C_REGISTER_ADDRESS = 0x0E # Example register
print("--- I2C Device Example ---")
try:
# Initialize I2C bus
i2c = busio.I2C(board.SCL, board.SDA)
# Create an I2CDevice object
i2c_device = I2CDevice(i2c, I2C_DEVICE_ADDRESS)
# Perform an I2C transaction
with i2c_device:
i2c_device.write(bytes([I2C_REGISTER_ADDRESS]))
result = bytearray(1)
i2c_device.readinto(result)
print(f"I2C read from 0x{I2C_DEVICE_ADDRESS:02X}, register 0x{I2C_REGISTER_ADDRESS:02X}: {result[0]:02X}")
except Exception as e:
print(f"I2C Example Error: {e}")
finally:
if 'i2c' in locals() and i2c.locked: i2c.unlock() # Ensure bus is unlocked
# --- SPI Example ---
# Replace with your actual SPI settings and CS pin
SPI_REGISTER_ADDRESS = 0xD0 # Example register for BMP280
print("\n--- SPI Device Example ---")
try:
# Initialize SPI bus and Chip Select pin
spi_bus = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO)
cs_pin = digitalio.DigitalInOut(board.D5) # Use an appropriate digital pin
# Create an SPIDevice object
spi_device = SPIDevice(spi_bus, cs_pin)
# Perform an SPI transaction
with spi_device as spi:
spi.write(bytes([SPI_REGISTER_ADDRESS]))
result = bytearray(1)
spi.readinto(result)
print(f"SPI read from register 0x{SPI_REGISTER_ADDRESS:02X}: {result[0]:02X}")
except Exception as e:
print(f"SPI Example Error: {e}")
finally:
if 'spi_bus' in locals() and spi_bus.locked: spi_bus.unlock() # Ensure bus is unlocked
print("Examples complete.")