smbus2

repository·master·Indexed 42 days ago

https://github.com/kplindegaard/smbus2

A pure Python, drop-in replacement for the Linux SMBus bindings (smbus-cffi/smbus-python). It provides a familiar interface for SMBus operations and adds advanced I2C features such as combined transactions via i2c_rdwr, Packet Error Checking (PEC), and the ability to bypass the 32-byte SMBus block transfer limit. Compatible with Linux systems exposing I2C adapters via /dev/i2c-N, including Raspberry Pi and NVIDIA Jetson.

Tokens
10.1K
Snippets
41
Records
62
Agent score
49%

What's inside smbus2

  1. Overview of smbus2

    master

    smbus2 is a pure-Python, drop-in replacement for the python-smbus and python3-smbus Linux SMBus bindings. It works by wrapping the Linux kernel's I2C/SMBus ioctl interface directly without requiring C extensions.

    Key features include:

    • Compatibility with the standard smbus API.
    • Support for combined read/write transactions using i2c_rdwr.
    • Support for Packet Error Checking (PEC).
  2. Introduction to smbus2

    master

    smbus2 is a pure Python, drop-in replacement for the python-smbus / python3-smbus Linux SMBus bindings. It provides a familiar interface for users of smbus while supporting extended Linux I2C/SMBus functionality like i2c_rdwr and Packet Error Checking (PEC).

    Note: While it is a drop-in replacement in terms of API, you must change the module import name from smbus to smbus2.

    from smbus2 import SMBus
  3. Platform and hardware requirements for smbus2

    master

    Platform Support

    smbus2 is a Linux-only library. It requires the Linux kernel's I2C subsystem and access to /dev/i2c-N character devices.

    Supported Hardware

    Any Linux system exposing an I2C adapter via /dev/i2c-N is supported, including:

    • Raspberry Pi (all models)
    • NVIDIA Jetson Nano / Xavier
    • BeagleBone Black / Green
    • Orange Pi, Rock Pi, and other Allwinner / Rockchip SBCs
    • Desktop/server systems with SMBus-capable chipsets
    • Any embedded Linux board with CONFIG_I2C_CHARDEV enabled in the kernel.

    Python Version Support

    • Targeted: Python 3.7 and later.
    • Legacy Support: While v0.6.1 may work on Python 2.7 through 3.6, these versions are no longer actively tested in CI and should be used at your own risk.
  4. Understand smbus2 functionality flags and I2C capabilities

    master
    The capabilities of your I2C bus (such as support for 10-bit addressing or specific SMBus transaction types) are exposed via bus.funcs (or the I2cFunc type in smbus2). These flags are derived from the Linux kernel's I2C_FUNCS flags. You can check these flags to ensure the bus supports the specific operations you intend to perform.
  5. How i2c_rdwr and i2c_msg work together

    master

    The i2c_rdwr method allows for combined read and write transactions, which is useful for reading/writing more than 32 bytes or performing a write followed by a read with a repeated start (no stop bit).

    Transactions are constructed using i2c_msg objects. You can create messages using i2c_msg.read(address, length) or i2c_msg.write(address, [data]).

    from smbus2 import SMBus, i2c_msg
    
    with SMBus(1) as bus:
        # Single transaction: Read 64 bytes from address 80
        msg = i2c_msg.read(80, 64)
        bus.i2c_rdwr(msg)
    
        # Single transaction: Write bytes to address 80
        msg = i2c_msg.write(80, [65, 66, 67, 68])
        bus.i2c_rdwr(msg)
  6. Perform combined transactions with i2c_rdwr

    master

    The i2c_rdwr method allows you to execute one or more i2c_msg objects in a single kernel ioctl call using repeated-start semantics. This is essential for:

    1. Transfers > 32 bytes: Bypasses the SMBus block limit.
    2. Atomic Write-then-Read: Ensures the slave address is not released between the write and read phases.

    Important: i2c_rdwr does not return data. You must access the data stored within the i2c_msg object using list(msg), iteration, or msg.buf.

    from smbus2 import SMBus, i2c_msg
    
    with SMBus(1) as bus:
        # Single write
        write_msg = i2c_msg.write(0x50, [0x00, 0x01, 0x02])
        bus.i2c_rdwr(write_msg)
    
        # Single read (e.g., 64 bytes)
        read_msg = i2c_msg.read(0x50, 64)
        bus.i2c_rdwr(read_msg)
        data = list(read_msg)
    
        # Dual message: Write register then read 2 bytes (Repeated Start)
        write = i2c_msg.write(0x50, [0x00])
        read = i2c_msg.read(0x50, 2)
        bus.i2c_rdwr(write, read)
        result = list(read)
  7. Use 10-bit I2C addresses

    master
    smbus2 does not have a dedicated 10-bit address API. You can check if your adapter supports 10-bit addressing by inspecting bus.funcs & I2cFunc.ADDR_10BIT, but there are no built-in convenience methods for sending to 10-bit addresses.
  8. Share an SMBus instance across modules

    master

    To avoid conflicts, do not create multiple SMBus objects for the same physical bus within a single process. Use a singleton pattern to ensure only one instance exists.

    Note: If your application is multi-threaded, you must wrap each bus operation in a threading.Lock to ensure thread safety.

    import atexit
    from smbus2 import SMBus
    
    class _BusHolder:
        _instance = None
    
        def __new__(cls):
            if cls._instance is None:
                cls._instance = SMBus(1)
                atexit.register(cls._instance.close)
            return cls._instance
    
    def get_bus() -> SMBus:
        """Return the shared SMBus instance."""
        return _BusHolder()
  9. Convert unsigned SMBus values to signed integers

    master

    The smbus2 library always returns unsigned integer values. To interpret these values as signed integers (e.g., for temperature sensors), use Python's ctypes module to cast the result. This works for both 8-bit bytes and 16-bit words.

    To send a signed Python integer as an unsigned byte on the wire, wrap the value in c_uint8() before passing it to a write method.

    from ctypes import c_int8, c_uint8, c_int16, c_uint16
    from smbus2 import SMBus
    
    with SMBus(1) as bus:
        # Read an unsigned byte and convert to signed
        unsigned_byte = bus.read_byte_data(0x50, 0x00)  # e.g. 200
        signed_byte = c_int8(unsigned_byte).value         # → -56
    
        # Convert a signed Python integer to the unsigned byte value sent on the wire
        signed_value = -123
        bus.write_byte_data(0x50, 0x00, c_uint8(signed_value).value)  # writes 133
    
        # Same pattern for 16-bit words
        unsigned_word = bus.read_word_data(0x50, 0x02)
        signed_word = c_int16(unsigned_word).value
  10. Verify smbus2 installation and I2C bus access

    master

    To verify that smbus2 is installed correctly, check the version via the command line:

    python -c "import smbus2; print(smbus2.__version__)"

    To verify that your I2C bus is actually accessible and the library can open it, run the following Python snippet (replacing 1 with your target bus number):

    python -c "import smbus2; print(smbus2.__version__)"
  11. Diagnose I2C bus issues with i2c-tools

    master

    The i2c-tools package is useful for manual bus discovery and device interrogation alongside smbus2. Common diagnostic commands include:

    • Scan for devices: Use i2cdetect -y <bus_number> to see which device addresses are responding on a specific bus. This is the recommended first step if a device is not found.
    • Dump registers: Use i2cdump -y <bus_number> <address> to view all registers of a device at a specific address.
    • Manual transactions: Use i2ctransfer -y <bus_number> <transaction_string> to perform complex write-then-read operations (similar to smbus2's i2c_rdwr).
    # Scan bus 1 for responding device addresses
    i2cdetect -y 1
    
    # Dump all registers of the device at address 0x50 on bus 1
    i2cdump -y 1 0x50
    
    # Perform a write-then-read transaction (write 1 byte to 0x50, then read 2 bytes from 0x50)
    i2ctransfer -y 1 w1@0x50 0x00 r2@0x50
  12. Install smbus2 via pip, conda, or source

    master

    You can install smbus2 using several package managers:

    Using pip

    Install the latest stable release via PyPI:

    pip install smbus2

    If you use uv, you can use uv add smbus2 for managed projects or uv pip install smbus2 for ad-hoc environments.

    Using conda

    Install from the conda-forge channel:

    conda install -c conda-forge smbus2

    From Source

    Clone the repository and install manually:

    git clone https://github.com/kplindegaard/smbus2.git
    cd smbus2
    python setup.py install

    For development, it is preferred to install in editable mode:

    pip install -e .