class I2CTarget – целевое устройство I2C

Целевое устройство I2C (target) – это устройство, которое подключается к шине I2C и управляется контроллером I2C. Целевые устройства I2C могут принимать различные формы. Класс machine.I2CTarget реализует целевое устройство I2C, которое может быть настроено как устройство памяти/регистров или как произвольное устройство I2C с использованием функций обратного вызова (если поддерживается портом).

Доступно на OpenMV Cam M4 / M7 / H7 / H7 Plus / Pure Thermal / RT1062 / AE3.

Пример использования для случая устройства памяти:

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()

Обратите внимание, что некоторые порты требуют передачи в конструктор I2CTarget параметра id, а возможно, и выводов scl и sda, чтобы выбрать аппаратный экземпляр I2C и выводы, к которым он подключён.

При настройке в качестве устройства памяти также возможна регистрация для получения событий. Например, чтобы получать уведомления о чтении/записи памяти:

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)

Более сложные устройства I2C можно реализовать, используя полный набор событий. Например, чтобы увидеть необработанные события по мере их возникновения:

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)

Конструкторы

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)

Создаёт и возвращает новый объект I2CTarget, используя следующие параметры:

  • id идентифицирует конкретное периферийное устройство I2C. Допустимые значения зависят от конкретного порта/платы. У некоторых портов есть значение по умолчанию, и в этом случае данный параметр можно опустить.

  • addr – это адрес I2C целевого устройства.

  • addrsize – это количество бит в адресе целевого устройства I2C. Допустимые значения – 7 и 10.

  • mem – это объект с буферным протоколом, доступный для записи. Если не указан, то резервная память отсутствует, и данные должны читаться/записываться с помощью методов I2CTarget.readinto() и I2CTarget.write().

  • mem_addrsize – это количество бит в адресе памяти. Допустимые значения – 0, 8, 16, 24 и 32.

  • scl – это объект вывода, указывающий вывод для использования в качестве SCL.

  • sda – это объект вывода, указывающий вывод для использования в качестве SDA.

Обратите внимание, что некоторые порты/платы имеют значения scl и sda по умолчанию, которые можно изменить в этом конструкторе. У других значения scl и sda фиксированы и не могут быть изменены.

Общие методы

deinit() None

Деинициализирует целевое устройство I2C. После вызова этого метода аппаратура перестанет отвечать на запросы на шине I2C, и никакие другие методы вызвать нельзя.

readinto(buf: bytearray) int

Читает в заданный буфер любые ожидающие байты, записанные контроллером I2C. Возвращает количество прочитанных байтов.

write(buf: bytes) int

Выводит байты из заданного буфера, чтобы передать их контроллеру I2C после того, как он отправит запрос на чтение. Возвращает количество записанных байтов. Большинство портов принимают этому методу только по одному байту за раз.

irq(handler: Callable[[I2CTarget], None] | None = None, trigger: int = IRQ_END_READ | IRQ_END_WRITE, hard: bool = False) None

Устанавливает обработчик прерывания handler, который вызывается при срабатывании одного из событий, выбранных параметром trigger. trigger – это битовая маска констант IRQ_*, объединённых через OR; по умолчанию срабатывает в конце каждого чтения или записи со стороны контроллера.

hard=True регистрирует обработчик аппаратного прерывания (без выделения памяти в куче внутри функции обратного вызова). По умолчанию используется запланированная функция обратного вызова. Передайте handler=None, чтобы отключить прерывание.

Примечание

IRQ_ADDR_MATCH_READ, IRQ_ADDR_MATCH_WRITE, IRQ_READ_REQ и IRQ_WRITE_REQ должны обрабатываться функцией обратного вызова аппаратного прерывания (hard=True), поскольку эти события необходимо подтверждать синхронно с аппаратурой. IRQ_END_READ и IRQ_END_WRITE могут обрабатываться как мягкими, так и аппаратными функциями обратного вызова; все события используют один общий обработчик, поэтому если хотя бы одному событию нужна аппаратная функция обратного вызова, то она нужна им всем.

Когда в конструктор передан буфер памяти, драйвер подавляет IRQ_END_WRITE для транзакции, которая лишь записывает адрес памяти. Это сохраняет осмысленность событий окончания транзакции даже тогда, когда планировщик мягких прерываний откладывает функцию обратного вызова.

memaddr

Целочисленное значение последнего адреса памяти, выбранного контроллером I2C (действительно только если в конструкторе был указан mem).

Константы

Каждая константа IRQ_* представляет собой флаговый бит. Объединяйте их через OR для построения маски trigger для irq(). Внутри обработчика набор сработавших событий можно восстановить через self.irq().flags(), применив AND с каждой константой.

IRQ_ADDR_MATCH_READ: int

Срабатывает, когда контроллер адресует это целевое устройство для транзакции чтения (байт адреса получен с битом чтения/записи, установленным в 1). Только аппаратное прерывание.

IRQ_ADDR_MATCH_WRITE: int

Срабатывает, когда контроллер адресует это целевое устройство для транзакции записи (байт адреса получен с битом чтения/записи, установленным в 0). Только аппаратное прерывание.

IRQ_READ_REQ: int

Срабатывает, когда контроллер запрашивает байт у целевого устройства. Обработчик должен вызвать write(), чтобы предоставить байт до завершения тактового цикла контроллера. Только аппаратное прерывание.

IRQ_WRITE_REQ: int

Срабатывает, когда контроллер передал байт в целевое устройство. Обработчик должен вызвать readinto(), чтобы получить байт до того, как контроллер отправит следующий. Только аппаратное прерывание.

IRQ_END_READ: int

Срабатывает, когда контроллер завершил транзакцию чтения (получен STOP / повторный START). Может обрабатываться как аппаратной, так и мягкой функцией обратного вызова прерывания.

IRQ_END_WRITE: int

Срабатывает, когда контроллер завершил транзакцию записи (получен STOP / повторный START). Может обрабатываться как аппаратной, так и мягкой функцией обратного вызова прерывания. Подавляется для транзакции, которая записывает адрес памяти, когда в конструктор был передан буфер mem.