class I2CTarget – an I2C target device¶
An I2C target is a device which connects to an I2C bus and is controlled by an
I2C controller. I2C targets can take many forms. The machine.I2CTarget
class implements an I2C target that can be configured as a memory/register device,
or as an arbitrary I2C device by using callbacks (if supported by the port).
Available on the OpenMV Cam M4 / M7 / H7 / H7 Plus / Pure Thermal / RT1062 / AE3.
Example usage for the case of a memory device:
from machine import I2CTarget
# Create the backing memory for the I2C target.
mem = bytearray(8)
# Create an I2C target. Depending on the port, extra parameters
# may be required to select the peripheral and/or pins to use.
i2c = I2CTarget(addr=67, mem=mem)
# At this point an I2C controller can read and write `mem`.
...
# Deinitialise the I2C target.
i2c.deinit()
Note that some ports require an id, and maybe scl and sda pins, to be
passed to the I2CTarget constructor, to select the hardware I2C instance and
pins that it connects to.
When configured as a memory device, it’s also possible to register to receive events. For example to be notified when the memory is read/written:
from machine import I2CTarget
# Define an IRQ handler, for I2C events.
def irq_handler(i2c_target):
flags = i2c_target.irq().flags()
if flags & I2CTarget.IRQ_END_READ:
print("controller read target at addr", i2c_target.memaddr)
if flags & I2CTarget.IRQ_END_WRITE:
print("controller wrote target at addr", i2c_target.memaddr)
# Create the I2C target and register to receive default events.
mem = bytearray(8)
i2c = I2CTarget(addr=67, mem=mem)
i2c.irq(irq_handler)
More complicated I2C devices can be implemented using the full set of events. For example, to see the raw events as they are triggered:
from machine import I2CTarget
# Define an IRQ handler that prints the event id and responds to reads/writes.
def irq_handler(i2c_target, buf=bytearray(1)):
flags = i2c_target.irq().flags()
print(flags)
if flags & I2CTarget.IRQ_READ_REQ:
i2c_target.write(buf)
if flags & I2CTarget.IRQ_WRITE_REQ:
i2c_target.readinto(buf)
# Create the I2C target and register to receive all events.
i2c = I2CTarget(addr=67)
all_triggers = (
I2CTarget.IRQ_ADDR_MATCH_READ
| I2CTarget.IRQ_ADDR_MATCH_WRITE
| I2CTarget.IRQ_READ_REQ
| I2CTarget.IRQ_WRITE_REQ
| I2CTarget.IRQ_END_READ
| I2CTarget.IRQ_END_WRITE
)
i2c.irq(irq_handler, trigger=all_triggers, hard=True)
Constructors¶
- class machine.I2CTarget(id: int, addr: int, *, addrsize: int = 7, mem: bytearray | None = None, mem_addrsize: int = 8, scl: Pin | None = None, sda: Pin | None = None)¶
Construct and return a new I2CTarget object using the following parameters:
id identifies a particular I2C peripheral. Allowed values depend on the particular port/board. Some ports have a default in which case this parameter can be omitted.
addr is the I2C address of the target.
addrsize is the number of bits in the I2C target address. Valid values are 7 and 10.
mem is an object with the buffer protocol that is writable. If not specified then there is no backing memory and data must be read/written using the
I2CTarget.readinto()andI2CTarget.write()methods.mem_addrsize is the number of bits in the memory address. Valid values are 0, 8, 16, 24 and 32.
scl is a pin object specifying the pin to use for SCL.
sda is a pin object specifying the pin to use for SDA.
Note that some ports/boards will have default values of scl and sda that can be changed in this constructor. Others will have fixed values of scl and sda that cannot be changed.
General Methods¶
- deinit() None¶
Deinitialise the I2C target. After this method is called the hardware will no longer respond to requests on the I2C bus, and no other methods can be called.
- readinto(buf: bytearray) int¶
Read into the given buffer any pending bytes written by the I2C controller. Returns the number of bytes read.
- write(buf: bytes) int¶
Write out the bytes from the given buffer, to be passed to the I2C controller after it sends a read request. Returns the number of bytes written. Most ports only accept one byte at a time to this method.
- irq(handler: Callable[[I2CTarget], None] | None = None, trigger: int = IRQ_END_READ | IRQ_END_WRITE, hard: bool = False) None¶
Install an IRQ
handlerthat is invoked when one of the events selected bytriggerfires.triggeris a bitmask ofIRQ_*constants OR’d together; the default fires on the end of every controller-side read or write.hard=Trueregisters a hard-interrupt handler (no heap allocation in the callback). The default is a scheduled callback. Passhandler=Noneto disable the interrupt.Note
IRQ_ADDR_MATCH_READ,IRQ_ADDR_MATCH_WRITE,IRQ_READ_REQandIRQ_WRITE_REQmust be handled by a hard IRQ callback (hard=True) because the events have to be acknowledged synchronously with the hardware.IRQ_END_READandIRQ_END_WRITEmay be handled by either soft or hard callbacks; all events share a single handler, so if any event needs a hard callback they all do.When a memory buffer is supplied to the constructor the driver suppresses
IRQ_END_WRITEfor the transaction that just writes the memory address. This keeps the end-of-transaction events meaningful even when the soft-IRQ scheduler defers the callback.
- memaddr¶
The integer value of the most recent memory address that was selected by the I2C controller (only valid if
memwas specified in the constructor).
Constants¶
Each
IRQ_*constant is a flag bit. OR them together to build atriggermask forirq(). Inside the handler the set of fired events can be recovered viaself.irq().flags()AND’d with each constant.- IRQ_ADDR_MATCH_READ: int¶
Fires when a controller addresses this target for a read transaction (the address byte has been received with the read/write bit set to
1). Hard-IRQ only.
- IRQ_ADDR_MATCH_WRITE: int¶
Fires when a controller addresses this target for a write transaction (the address byte has been received with the read/write bit set to
0). Hard-IRQ only.
- IRQ_READ_REQ: int¶
Fires when the controller is requesting a byte from the target. The handler must call
write()to supply the byte before the controller’s clock cycle completes. Hard-IRQ only.
- IRQ_WRITE_REQ: int¶
Fires when the controller has clocked in a byte to the target. The handler must call
readinto()to retrieve the byte before the controller sends the next one. Hard-IRQ only.