i2cslave — Two wire serial protocol slave

The i2cslave module contains classes to support a I2C slave.

Classes

Example emulating 2 devices:

import board
from i2cslave import I2CSlave

regs = [0] * 16
index = 0

with I2CSlave(board.SCL, board.SDA, (0x40, 0x41)) as slave:
    while True:
        r = slave.request()
        if not r:
            # Maybe do some housekeeping
            continue
        with r:  # Closes the transfer if necessary by sending a NACK or feeding the master dummy bytes
            if r.address == 0x40:
                if not r.is_read:  # Master write which is Slave read
                    b = r.read(1)
                    if not b or b[0] > 15:
                        break
                    index = b[0]
                    b = r.read(1)
                    if b:
                        regs[index] = b[0]
                elif r.is_restart:  # Combined transfer: This is the Master read message
                    n = r.write(bytes([regs[index]]))
                #else:
                    # A read transfer is not supported in this example
                    # If the Master tries, it will get 0xff byte(s) by the ctx manager (r.close())
            elif r.address == 0x41:
                if not r.is_read:
                    b = r.read(1)
                    if b and b[0] == 0xde:
                        # do something
                        pass

This example sets up an I2C slave that can be accessed from Linux like this:

$ i2cget -y 1 0x40 0x01
0x00
$ i2cset -y 1 0x40 0x01 0xaa
$ i2cget -y 1 0x40 0x01
0xaa

Warning

I2CSlave makes use of clock stretching in order to slow down the master. Make sure the I2C master supports this.

Raspberry Pi in particular does not support this with its I2C hw block. This can be worked around by using the i2c-gpio bit banging driver. Since the RPi firmware uses the hw i2c, it’s not possible to emulate a HAT eeprom.