CircuitPython, Adafruit Feather RP2040 e I2C

El RP2040 tiene dos controladores I2C - bueno, por ejemplo, cuando se desea ejecutar dos dispositivos I2C con la misma dirección I2C.

En mi configuración de prueba, tengo una placa de microcontrolador Adafruit Feather RP2040, y he conectado dos de nuestros Placas de conexión BME688 - uno utilizando los pines SCL + SDA y otro utilizando A1 (para SCL) + A0 (para SDA).

Estoy usando CircuitPython en la versión 7.0.0, que puede descargar desde aquí.

Además, he instalado todas las bibliotecas de Adafruit en el lib en la Feather RP2040. (El Feather RP2040 tiene suficiente espacio en su Flash para permitir esto)

Puede descargar estas bibliotecas en el Adafruit CircuitPython Bundle aquí. (He descargado adafruit-circuitpython-bundle-7.x-mpy-20211123.zip)

NotaPara instalar estas librerías, basta con copiarlas en la carpeta lib de la "unidad" CIRCUITPY que está montada en su ordenador. Por supuesto, tendrás que copiar sólo las librerías, no los ejemplos y otras cosas.

La gran ventaja de usar el material de Adafruit es que obtienes una tonelada de ejemplos que cubren muchos chips populares, y puedes empezar muy fácilmente con él. Hay cosas como la conducción de una tarjeta microSD utilizando SPI, la lectura de un RTC, y la lectura del sensor BME680.

Probando I2C en CircuitPython

Tengo la siguiente configuración, ya que quiero manejar dos dispositivos independientemente uno del otro (que casualmente tienen las mismas direcciones en este caso):

Feather RP2040 y dos Placas de conexión BME688

Ten en cuenta que nuestras placas breakout BME688 ya incluyen pullups para SDA y SCL. (Necesita pullups en SDA y SCL).

Nota 2: Nuestra placa breakout BME688 tiene la opción de cambiar la dirección, por lo que este escenario está pensado para fines de demostración.

Para conducir a través de ambos conjuntos de pines secuencialmente (para descubrir los dispositivos), estoy utilizando el siguiente código:

print("Escaneando SCL / SDA")
i2c = busio.I2C(board.SCL, board.SDA)
# un escaneo
i2c.try_lock()
print(i2c.scan())
i2c.unlock()
i2c.deinit()

print("Escaneando A0 / A1")
si2c = busio.I2C(board.A1, board.A0)
# un escaneo
si2c.try_lock()
print(si2c.scan())
si2c.unlock()

Nota: el i2c.deinit() ¡es la clave para que este ejemplo en particular funcione! (porque SCL / SDA y A0 / A1 tienen ambos el mismo periférico hardware I2C - ver más abajo).

Esto debería dar como resultado lo siguiente:

Escaneo SCL / SDA
[119]
Escaneo A0 / A1
[119]

Aquí, el 119 es decimal para el hexágono 0x77 - que es la dirección de nuestra placa breakout BME688 en el estado por defecto.

Ambos tableros se ven, secuencialmente en las exploraciones individuales.

El problema es que queremos utilizarlos simultáneamente.

Ejecutando dos buses I2C simultáneamente en el Adafruit Feather RP2040

CircuitPython es compatible con ambos controladores de hardware (SDA0/SCL0 y SDA1/SCL1). No necesitas establecer ninguna configuración (qué controlador quieres usar, o cómo muxar los pines) - de esto se encarga busio para ti.

Sin embargo, hay que prestar atención a las clavijas que se utilizan, ya que las clavijas sólo proporcionan un de estos buses en cada caso, y si por casualidad elige pines conflictivos, obtendrá ValueError: Periférico I2C en uso .

Pinout Adafruit Feather RP2040

Si quieres usar pines "conflictivos", por ejemplo SCL / SDA (que tienen SCL1 y SDA1) y A0 / A1 (que también tienen SCL1 y SDA1), tendrás que hacer un bitbang en uno de los puertos:

A continuación se explica cómo explorar esta configuración de pines sin llamar a deinit():

importar tablero
importar busio
importar bitbangio
# https://circuitpython.readthedocs.io/en/latest/shared-bindings/bitbangio/index.html

print("Escaneando SCL / SDA - I2C principal")
i2c = busio.I2C(board.SCL, board.SDA)
# un escaneo
i2c.try_lock()
print(i2c.scan())
i2c.unlock()
# ¡no es necesario llamar a deinit aquí!
#i2c.deinit()

print("Escaneando A0 / A1 - I2C secundario [bitbang!]")
si2c = bitbangio.I2C(board.A1, board.A0)
# un escaneo
si2c.try_lock()
print(si2c.scan())
si2c.unlock()

# tampoco necesitamos llamar a deinit aquí
#i2c.deinit()

Estamos utilizando bitbangio para manejar un I2C secundario. En mi caso el I2C secundario se utiliza para un propósito interno (para un expansor de puertos), y muy probablemente puede hacer con una velocidad de interfaz más baja.

Nota: no puedes elegir el periférico I2C que se enruta a los pines en el software - si necesitas un periférico diferente, tienes que usar pines diferentes.

Resolución de errores I2C

ValueError: Periférico I2C en uso

Si estás usando busio.I2C para ambos puertos: Compruebe si ya está utilizando el mismo periférico hardware I2C - y si necesita reasignar sus pines.

Por ejemplo, tanto SCL y SDA , como A0 y A1 comparten el mismo periférico I2C de hardware (SCL1 / SDA1 - ver la imagen del pinout del Adafruit Feather RP2040 en este artículo).

En caso de que quieras usar la misma configuración de pines, puedes usar bitbangio para "crear" un puerto I2C adicional controlado por software. La desventaja de esto es la menor velocidad de este puerto I2C por software, y una mayor carga de la CPU.

RuntimeError: No se ha encontrado pull up en SDA o SCL; compruebe su cableado

Si obtiene el siguiente error

RuntimeError: No se ha encontrado pull up en SDA o SCL; compruebe su cableado

entonces debe poner resistencias pullup entre 3V3 en la placa (el pin de 3.3V) y respectivamente sus pines SDA y SCL. Estos son necesarios para el funcionamiento normal de I2C (los dispositivos tiran de los pines I2C para comunicarse, el estado por defecto / inactivo en el bus es alto) - y no se incluyen en el Adafruit Feather RP2040. Están incluidos en muchos periféricos de Adafruit, y en periféricos de otras compañías (como, de nuevo, nuestro propio Placa de conexión BME688).

Si no sabes lo que es un pullup: se trata esencialmente de una resistencia entre el pin en cuestión (por ejemplo, SDA) y el pin de alimentación de 3,3 V. No es necesario que sea muy preciso. Deberías empezar con resistencias de 10 kOhm, si eso no funciona, posiblemente prueba con una resistencia de 1 kOhm para un pullup más "rígido".

TimeoutError: El tiempo de espera es demasiado largo

Comprueba si el chip con el que quieres hablar está bien alimentado.

Notas varias

Referencias / Recursos / Enlaces / Lecturas complementarias

Deja un comentario