i2ctarget – Two wire serial protocol target

The i2ctarget module contains classes to support an I2C target.

Example emulating a target with 2 addresses (read and write):

import board
from i2ctarget import I2CTarget

regs = [0] * 16
index = 0

with I2CTarget(board.SCL, board.SDA, (0x40, 0x41)) as device:
    while True:
        r = device.request()
        if not r:
            # Maybe do some housekeeping
            continue
        with r:  # Closes the transfer if necessary by sending a NACK or feeding dummy bytes
            if r.address == 0x40:
                if not r.is_read:  # Main write which is Selected 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 Main read message
                    n = r.write(bytes([regs[index]]))
                #else:
                    # A read transfer is not supported in this example
                    # If the microcontroller 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 device 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

I2CTarget makes use of clock stretching in order to slow down the host. Make sure the I2C host 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.

Available on these boards
  • 0xCB Helios
  • 42. Keebs Frood
  • Adafruit EdgeBadge
  • Adafruit Feather M4 CAN
  • Adafruit Feather M4 Express
  • Adafruit Feather RP2040
  • Adafruit Feather RP2040 CAN
  • Adafruit Feather RP2040 DVI
  • Adafruit Feather RP2040 Prop-Maker
  • Adafruit Feather RP2040 RFM
  • Adafruit Feather RP2040 Scorpio
  • Adafruit Feather RP2040 ThinkInk
  • Adafruit Feather RP2040 USB Host
  • Adafruit Floppsy RP2040
  • Adafruit Grand Central M4 Express
  • Adafruit Hallowing M4 Express
  • Adafruit ItsyBitsy M4 Express
  • Adafruit ItsyBitsy RP2040
  • Adafruit KB2040
  • Adafruit Macropad RP2040
  • Adafruit Matrix Portal M4
  • Adafruit Metro M4 Airlift Lite
  • Adafruit Metro M4 Express
  • Adafruit Metro RP2040
  • Adafruit Monster M4SK
  • Adafruit PyGamer
  • Adafruit PyPortal
  • Adafruit PyPortal Pynt
  • Adafruit PyPortal Titano
  • Adafruit Pybadge
  • Adafruit QT Py RP2040
  • Adafruit QT2040 Trinkey
  • Adafruit Trellis M4 Express
  • AloriumTech Evo M51
  • Arduino Nano RP2040 Connect
  • BBQ20KBD
  • BDMICRO VINA-D51
  • BLOK
  • COSMO-Pico
  • CP32-M4
  • Challenger NB RP2040 WiFi
  • Challenger RP2040 LTE
  • Challenger RP2040 LoRa
  • Challenger RP2040 SD/RTC
  • Challenger RP2040 SubGHz
  • Challenger RP2040 WiFi
  • Challenger RP2040 WiFi/BLE
  • CircuitBrains Deluxe
  • Cytron EDU PICO W
  • Cytron Maker Nano RP2040
  • Cytron Maker Pi RP2040
  • Cytron Maker Uno RP2040
  • Datanoise PicoADK
  • DynOSSAT-EDU-OBC
  • E-Fidget
  • ELECFREAKS PICO:ED
  • Electrolama minik
  • EncoderPad RP2040
  • Fig Pi
  • HEIA-FR Picomo V2
  • Hack Club Sprig
  • LILYGO T-DISPLAY
  • Maple Computing Elite-Pi
  • Melopero Shake RP2040
  • Mini SAM M4
  • Oak Dev Tech BREAD2040
  • Oak Dev Tech Cast-Away RP2040
  • P1AM-200
  • Pajenicko PicoPad
  • Pimoroni Badger 2040
  • Pimoroni Badger 2040 W
  • Pimoroni Inky Frame 5.7
  • Pimoroni Inky Frame 7.3
  • Pimoroni Interstate 75
  • Pimoroni Keybow 2040
  • Pimoroni Motor 2040
  • Pimoroni PGA2040
  • Pimoroni Pico DV Base W
  • Pimoroni Pico LiPo (16MB)
  • Pimoroni Pico LiPo (4MB)
  • Pimoroni Pico dv Base
  • Pimoroni PicoSystem
  • Pimoroni Plasma 2040
  • Pimoroni Plasma 2040W
  • Pimoroni Servo 2040
  • Pimoroni Tiny 2040 (2MB)
  • Pimoroni Tiny 2040 (8MB)
  • PyCubedv04
  • PyCubedv04-MRAM
  • PyCubedv05
  • PyCubedv05-MRAM
  • PyKey 18 Numpad
  • PyKey 44 Ergo
  • PyKey 60
  • PyKey 87 TKL
  • RP2.65-F
  • RP2040 Stamp
  • Raspberry Breadstick
  • Raspberry Pi Pico
  • Raspberry Pi Pico W
  • Robo HAT MM1 M4
  • SAM E54 Xplained Pro
  • SAM32v26
  • Seeeduino Wio Terminal
  • Seeeduino XIAO RP2040
  • Silicognition LLC M4-Shim
  • Silicognition LLC RP2040-Shim
  • SparkFun MicroMod RP2040 Processor
  • SparkFun MicroMod SAMD51 Processor
  • SparkFun Pro Micro RP2040
  • SparkFun Thing Plus - RP2040
  • SparkFun Thing Plus - SAMD51
  • Sprite_v2b
  • TG-Boards' Datalore IP M4
  • The Open Book Feather
  • UARTLogger II
  • VCC-GND Studio YD RP2040
  • W5100S-EVB-Pico
  • W5500-EVB-Pico
  • Waveshare RP2040-LCD-0.96
  • Waveshare RP2040-LCD-1.28
  • Waveshare RP2040-Plus (16MB)
  • Waveshare RP2040-Plus (4MB)
  • Waveshare RP2040-TOUCH-LCD-1.28
  • Waveshare RP2040-Tiny
  • Waveshare RP2040-Zero
  • WeAct Studio Pico
  • WeAct Studio Pico 16MB
  • WisdPi Ardu2040M
  • WisdPi Tiny RP2040
  • nullbits Bit-C PRO
  • splitkb.com Liatris
  • takayoshiotake Octave RP2040
  • uGame22

class i2ctarget.I2CTarget(scl: microcontroller.Pin, sda: microcontroller.Pin, addresses: Sequence[int], smbus: bool = False)

Two wire serial protocol target

I2C is a two-wire protocol for communicating between devices. This implements the target (peripheral, sensor, secondary) side.

Parameters:
  • scl (Pin) – The clock pin

  • sda (Pin) – The data pin

  • addresses (list[int]) – The I2C addresses to respond to (how many is hardware dependent).

  • smbus (bool) – Use SMBUS timings if the hardware supports it

deinit() None

Releases control of the underlying hardware so other classes can use it.

__enter__() I2CTarget

No-op used in Context Managers.

__exit__() None

Automatically deinitializes the hardware on context exit. See Lifetime and ContextManagers for more info.

request(*, timeout: float = -1) I2CTargetRequest

Wait for an I2C request.

Parameters:

timeout (float) – Timeout in seconds. Zero means wait forever, a negative value means check once

Returns:

I2CTargetRequest or None if timeout=-1 and there’s no request

Return type:

I2CTargetRequest

class i2ctarget.I2CTargetRequest(target: I2CTarget, address: int, is_read: bool, is_restart: bool)

Information about an I2C transfer request This cannot be instantiated directly, but is returned by I2CTarget.request().

Parameters:
  • target – The I2CTarget object receiving this request

  • address – I2C address

  • is_read – True if the main target is requesting data

  • is_restart – Repeated Start Condition

address: int

The I2C address of the request.

is_read: bool

The I2C main controller is reading from this target.

is_restart: bool

Is Repeated Start Condition.

__enter__() I2CTargetRequest

No-op used in Context Managers.

__exit__() None

Close the request.

read(n: int = -1, ack: bool = True) bytearray

Read data. If ack=False, the caller is responsible for calling I2CTargetRequest.ack().

Parameters:
  • n – Number of bytes to read (negative means all)

  • ack – Whether or not to send an ACK after the n’th byte

Returns:

Bytes read

write(buffer: circuitpython_typing.ReadableBuffer) int

Write the data contained in buffer.

Parameters:

buffer (ReadableBuffer) – Write out the data in this buffer

Returns:

Number of bytes written

ack(ack: bool = True) None

Acknowledge or Not Acknowledge last byte received. Use together with I2CTargetRequest.read() ack=False.

Parameters:

ack – Whether to send an ACK or NACK