clase I2CTarget – un dispositivo target de I2C

Un target de I2C es un dispositivo que se conecta a un bus I2C y es controlado por un controlador I2C. Los targets de I2C pueden adoptar muchas formas. La clase machine.I2CTarget implementa un target de I2C que puede configurarse como un dispositivo de memoria/registros, o como un dispositivo I2C arbitrario mediante funciones de retorno (callbacks) (si el puerto lo admite).

Disponible en la OpenMV Cam M4 / M7 / H7 / H7 Plus / Pure Thermal / RT1062 / AE3.

Ejemplo de uso para el caso de un dispositivo de memoria:

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

Tenga en cuenta que algunos puertos requieren que se pase un id, y quizás pines scl y sda, al constructor de I2CTarget, para seleccionar la instancia I2C de hardware y los pines a los que se conecta.

Cuando se configura como dispositivo de memoria, también es posible registrarse para recibir eventos. Por ejemplo, para ser notificado cuando se lee/escribe la memoria:

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)

Pueden implementarse dispositivos I2C más complejos usando el conjunto completo de eventos. Por ejemplo, para ver los eventos en bruto a medida que se disparan:

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)

Constructores

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)

Construye y devuelve un nuevo objeto I2CTarget usando los siguientes parámetros:

  • id identifica un periférico I2C en particular. Los valores permitidos dependen del puerto/placa concreto. Algunos puertos tienen un valor predeterminado, en cuyo caso este parámetro puede omitirse.

  • addr es la dirección I2C del target.

  • addrsize es el número de bits en la dirección del target I2C. Los valores válidos son 7 y 10.

  • mem es un objeto con el protocolo de búfer que es escribible. Si no se especifica, no hay memoria de respaldo y los datos deben leerse/escribirse usando los métodos I2CTarget.readinto() e I2CTarget.write().

  • mem_addrsize es el número de bits en la dirección de memoria. Los valores válidos son 0, 8, 16, 24 y 32.

  • scl es un objeto pin que especifica el pin a usar para SCL.

  • sda es un objeto pin que especifica el pin a usar para SDA.

Tenga en cuenta que algunos puertos/placas tendrán valores predeterminados de scl y sda que pueden cambiarse en este constructor. Otros tendrán valores fijos de scl y sda que no pueden cambiarse.

Métodos generales

deinit() None

Desinicializa el target de I2C. Después de llamar a este método, el hardware dejará de responder a las solicitudes en el bus I2C, y no se podrá llamar a ningún otro método.

readinto(buf: bytearray) int

Lee en el búfer dado los bytes pendientes escritos por el controlador I2C. Devuelve el número de bytes leídos.

write(buf: bytes) int

Escribe los bytes del búfer dado, para pasarlos al controlador I2C después de que este envíe una solicitud de lectura. Devuelve el número de bytes escritos. La mayoría de los puertos solo aceptan un byte a la vez en este método.

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

Instala un manejador de IRQ handler que se invoca cuando se dispara uno de los eventos seleccionados por trigger. trigger es una máscara de bits de constantes IRQ_* combinadas con OR; el valor predeterminado se dispara al final de cada lectura o escritura del lado del controlador.

hard=True registra un manejador de interrupción dura (sin asignación de heap en la función de retorno). El valor predeterminado es una función de retorno programada. Pase handler=None para deshabilitar la interrupción.

Nota

IRQ_ADDR_MATCH_READ, IRQ_ADDR_MATCH_WRITE, IRQ_READ_REQ e IRQ_WRITE_REQ deben manejarse mediante una función de retorno de IRQ dura (hard=True) porque los eventos tienen que confirmarse de forma síncrona con el hardware. IRQ_END_READ e IRQ_END_WRITE pueden manejarse mediante funciones de retorno blandas o duras; todos los eventos comparten un único manejador, así que si algún evento necesita una función de retorno dura, todos la necesitan.

Cuando se suministra un búfer de memoria al constructor, el controlador suprime IRQ_END_WRITE para la transacción que solo escribe la dirección de memoria. Esto mantiene significativos los eventos de fin de transacción incluso cuando el planificador de IRQ blandas difiere la función de retorno.

memaddr

El valor entero de la dirección de memoria más reciente que fue seleccionada por el controlador I2C (solo válido si se especificó mem en el constructor).

Constantes

Cada constante IRQ_* es un bit de bandera. Combínelas con OR para construir una máscara trigger para irq(). Dentro del manejador, el conjunto de eventos disparados puede recuperarse mediante self.irq().flags() combinado con AND con cada constante.

IRQ_ADDR_MATCH_READ: int

Se dispara cuando un controlador direcciona este target para una transacción de lectura (el byte de dirección se ha recibido con el bit de lectura/escritura puesto a 1). Solo IRQ dura.

IRQ_ADDR_MATCH_WRITE: int

Se dispara cuando un controlador direcciona este target para una transacción de escritura (el byte de dirección se ha recibido con el bit de lectura/escritura puesto a 0). Solo IRQ dura.

IRQ_READ_REQ: int

Se dispara cuando el controlador está solicitando un byte del target. El manejador debe llamar a write() para suministrar el byte antes de que se complete el ciclo de reloj del controlador. Solo IRQ dura.

IRQ_WRITE_REQ: int

Se dispara cuando el controlador ha introducido un byte en el target mediante el reloj. El manejador debe llamar a readinto() para recuperar el byte antes de que el controlador envíe el siguiente. Solo IRQ dura.

IRQ_END_READ: int

Se dispara cuando el controlador ha terminado una transacción de lectura (ha recibido STOP / START repetido). Puede manejarse mediante una función de retorno de IRQ dura o blanda.

IRQ_END_WRITE: int

Se dispara cuando el controlador ha terminado una transacción de escritura (ha recibido STOP / START repetido). Puede manejarse mediante una función de retorno de IRQ dura o blanda. Se suprime para la transacción que escribe la dirección de memoria cuando se suministró un búfer mem al constructor.