como-usar-extensor-i2c-tca9548a-y-arduino

Cómo usar un extensor de bus I2C TCA9548A y Arduino

¿Qué es un TCA9548A?

El TCA9548A es un extensor I2C de 8 canales, que podemos usar con un microprocesador como Arduino.

La función de un extensor I2C es conectar varios buses a un único bus. Podría entenderse como un tipo particular de multiplexor, pero especialmente diseñado para comunicación I2C.

De esta forma, el TCA9548A tiene una entrada de bus I2C, con dos líneas (SDA y SCL). Por otro lado, tiene 8 salidas de bus I2C, cada una con sus correspondientes dos líneas (SDA y SCL).

arduino-tca9548a-explicacion

Durante su funcionamiento, el extensor I2C conecta el bus de entrada a una (o ninguna) de las salidas, lo que permite al procesador comunicarse con varios buses.

Probablemente el uso más frecuente que podemos hacer de un extensor I2C es permitir conectarnos varios dispositivos con la misma dirección, y que no permiten cambiarla.

También puede ser útiles para comunicar buses I2C con tensiones diferentes, sin necesidad de emplear un adaptador de nivel lógico. Así es posible comunicar buses a tensiones de 1.8V, 2.5V, 3.3V y 5V.

La comunicación con el propio TCA9548A se realiza por el bus de entrada, por lo que es muy sencillo controlarlo desde un procesador.

El voltaje del funcionamiento del TCA9548A es 1.65V a 5.5V, y funciona con buses I2C de frecuencia 0 hasta 400KHz.

Precio

Los TCA9548A son dispositivos muy baratos. Podemos encontrarlos por unos 0,45€ en vendedores internacionales de eBay y AliExpress.

arduino-tca9548a-componente

¿Cómo funciona un TCA9548A?

De forma resumida, internamente el TCA9548A puede ser considerado como una matriz de 16 interruptores, que conectan la línea SDA y SCL del bus de entrada, con las líneas SDA y SCL de las 8 salidas.

arduino-tca9548a-funcionamiento

La electrónica del TCA9548A recibe la señal del bus I2C de entrada, y configura la matriz de interruptores. De esta forma conecta el bus I2C de entrada a una de las salidas.

La dirección por defecto del TCA9548A es 0x70, pero se puede variar de 0x70 a 0x77 mediante los pines A0, A1 y A2, según la siguiente tabla.

A2A1A0Adreess
LLL0x70
LLH0x71
LHL0x72
LHH0x73
HLL0x74
HLH0x75
HHL0x76
HHH0x77

Esquema de montaje

La conexión de TCA9548A es bastante sencilla. Por un lado, alimentamos el módulo a la tensión del bus de entrada (en el ejemplo, GND y 5V), y las SDA y SCL del bus I2C de entrada.

arduino-tca9548a-esquema

Por otro lado, conectamos las salidas que necesitemos, hasta un máximo de 8, cada uno con sus líneas SDA y SCL.

La conexión, vista desde Arduino sería la siguiente.

arduino-tca9548a-conexion

La dirección del propio TCA9548A puede configurarse entre 0x70 y 0x77 con los pines A0, A1 y A2, según la tabla que hemos visto antes.

El TCA9548A puede reiniciarse poniendo RST a LOW. Por defecto está pull-up, así que podéis dejarlo sin conectar si no lo necesitáis en el proyecto.

Finalmente, tened en cuenta que, en función de cómo sean los dispositivos que conectéis y la longitud de los cables, podéis necesitar añadir resistencias de Pull-UP para los buses de I2C de entrada o salida.

Ejemplos de código

Escaner I2C

Lo primero que vamos a hacer es detectar el propio TCA9548A, para lo cual vamos a ejecutar un I2CScanner.

Como aún no hemos realizado ninguna acción sobre el TCA9548A, la entrada y las salidas están desconectadas, por lo que la única dirección que deberíamos detectar es la del propio TCA9548A, en la dirección que hemos configurado (0x70-0x77)

#include "Wire.h"

void scanI2CBus(byte from_addr, byte to_addr, void(*callback)(byte address, byte result) ) 
{
  byte rc;
  byte data = 0;
  for( byte addr = from_addr; addr <= to_addr; addr++ ) {
    rc = twi_writeTo(addr, &data, 0, 1, 0);
    callback( addr, rc );
  }
}

void scanFunc( byte addr, byte result ) {
  Serial.print("addr: ");
  Serial.print(addr,DEC);
  Serial.print( (result==0) ? " Encontrado!":"       ");
  Serial.print( (addr%4) ? "\t":"\n");
}

const byte start_address = 8;
const byte end_address = 119;

void setup()
{
    Wire.begin();

    Serial.begin(9600);
    Serial.print("Escaneando bus I2C...");
    scanI2CBus( start_address, end_address, scanFunc );
    Serial.println("\nTerminado");
}

void loop() 
{
    delay(1000);
}

Escaner I2C para TCA9548A

Una vez comprobado que el extensor es detectado correctamente, podemos actuar para detectar los dispositivos conectados en los buses de salida.

Existen librerías para manipular el TCA9548A, pero seleccionar un canal es muy sencillo, únicamente tenemos que escribir un byte con el canal con el que queremos conectar.

Por tanto, normalmente evitaremos usar una librería, y simplemente tendremos una función como la siguiente void tcaselect(uint8_t i), para manejar el TCA9548A.

De esta forma, podemos modificar el I2C escáner normal para que detecte los dispositivos en las distintas salidas.

/**
 * TCA9548 I2CScanner.ino -- I2C bus scanner for Arduino
 *
 * Based on https://playground.arduino.cc/Main/I2cScanner/
 *
 */

#include "Wire.h"


#define TCAADDR 0x70

void tcaselect(uint8_t i) {
  if (i > 7) return;
 
  Wire.beginTransmission(TCAADDR);
  Wire.write(1 << i);
  Wire.endTransmission();  
}

void setup()
{
    while (!Serial);
    delay(1000);

    Wire.begin();
    
    Serial.begin(115200);
    Serial.println("\nTCA escaner listo");
    
    for (uint8_t t=0; t<8; t++) {
      tcaselect(t);
      Serial.print("  Escaneando salida "); Serial.println(t);

      for (uint8_t addr = 0; addr<=127; addr++) {
        if (addr == TCAADDR) continue;

        Wire.beginTransmission(addr);
        if (!Wire.endTransmission()) {
          Serial.print("  - Encontrado I2C 0x");  Serial.println(addr,HEX);
        }
      }
    }
    Serial.println("Finalizado");
}

void loop() 
{
}

Descarga el código

Todo el código de esta entrada está disponible para su descarga en Github. github-full