i2ctarget – Two wire serial protocol target
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 =  * 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 > 15: break index = b b = r.read(1) if b: regs[index] = b 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 == 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
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
- 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.
- __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.
timeout (float) – Timeout in seconds. Zero means wait forever, a negative value means check once
I2CTargetRequest or None if timeout=-1 and there’s no request
- Return type:
- 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
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
- __enter__() I2CTargetRequest
No-op used in Context Managers.
- read(n: int = -1, ack: bool = True) bytearray
Read data. If ack=False, the caller is responsible for calling
n – Number of bytes to read (negative means all)
ack – Whether or not to send an ACK after the n’th byte
- write(buffer: circuitpython_typing.ReadableBuffer) int
Write the data contained in buffer.
buffer (ReadableBuffer) – Write out the data in this buffer
Number of bytes written
- ack(ack: bool = True) None
Acknowledge or Not Acknowledge last byte received. Use together with
ack – Whether to send an ACK or NACK