← Índice del curso

Comunicación entre Dispositivos · Tema 16 · I²C

I²C: dos hilos y colector abierto

SPI resuelve la comunicación entre un maestro y muchos esclavos con una línea de selección por cada uno. I²C elige otro camino: dos hilos compartidos por todos y direcciones dentro del mensaje. Para que eso sea posible, las líneas no se manejan como las de SPI sino con salidas de colector abierto y una resistencia que las sube. Vamos a ver qué hace cada hilo, por qué existen las pull-ups, cómo se calculan a partir del tiempo de subida, qué velocidades admite el bus y cómo conectar dispositivos de distinta tensión.

01 · Otro enfoque

Dos hilos para todos

En el bloque de SPI vimos que agregar un esclavo cuesta un pin más, y que con ocho periféricos el maestro ya necesita once. I²C (Inter-Integrated Circuit, que se lee «I cuadrado C») nació en Philips, en los años ochenta, para conectar los circuitos integrados de un televisor sin llenar la placa de pistas. Hoy lo mantiene NXP y es el bus que usan la mayoría de los sensores de bajo costo: temperatura, presión, acelerómetros, relojes de tiempo real, pantallas pequeñas, expansores de pines y memorias EEPROM.

La idea tiene tres partes:

  • Dos hilos, sea cual sea el número de dispositivos. Una línea de reloj (SCL) y una línea de datos (SDA) recorren todo el bus, y cada dispositivo se conecta en paralelo a las dos.
  • Direcciones en lugar de líneas de selección. El mensaje empieza con la dirección del dispositivo al que va dirigido, y los demás lo ignoran. Cómo funciona exactamente lo vemos en el tema 17.
  • Líneas que se comparten sin pelearse. Para que muchos dispositivos manejen la misma línea de datos hace falta un tipo especial de salida, el colector abierto, que es el tema de este capítulo.
Comparación entre los tres enlaces que vimos hasta ahora.
UARTSPII²C
Líneas2 (TX y RX), sin reloj3 compartidas + 1 CS por esclavo2 (SDA y SCL), con reloj
Dispositivos2 (punto a punto)1 maestro, varios esclavosVarios maestros y varios esclavos
A quién se hablaNo hace faltaLínea CS físicaDirección dentro del mensaje
Sentido de los datosFull dúplexFull dúplexSemidúplex (una sola línea de datos)
ConfirmaciónNoNoSí: cada byte se confirma (ACK)
Tipo de salidaPush-pullPush-pullColector abierto
Velocidad típica9,6 a 115,2 kbit/s1 a 50 Mbit/s100 kbit/s a 1 Mbit/s

La comparación muestra el compromiso: I²C gasta menos pines y trae confirmación por byte, pero es más lento que SPI y más sensible al cableado. Si solo hace falta leer un sensor cada segundo, es casi siempre la mejor opción; si hay que llenar una pantalla o leer una memoria a velocidad, SPI.

02 · El cableado

SDA y SCL

Bus I²C con un maestro y tres esclavos Dos líneas, SDA y SCL, recorren el bus de izquierda a derecha y se derivan al maestro y a tres esclavos. Cada línea está unida a la alimentación a través de una resistencia de pull-up, situada en el extremo del bus. Maestromicrocontrolador Esclavo 1sensor Esclavo 2pantalla Esclavo 3memoria SDASCL VDD (3,3 V) RpRp Todos los dispositivos se conectan en paralelo a las dos líneas y comparten masa

Cada línea tiene un oficio:

  • SCL (Serial Clock) es la línea de reloj. La genera el maestro que está hablando en ese momento: cada pulso marca el instante en que se lee un bit de datos.
  • SDA (Serial Data) es la línea de datos y es bidireccional: el mismo hilo lleva los bits del maestro al esclavo y, cuando se lee, los del esclavo al maestro. Por eso el enlace es semidúplex y no hay una línea aparte para cada sentido como MOSI y MISO.
  • La masa es común a todos los dispositivos, como en cualquier enlace (tema 5). Sin ella las tensiones de SDA y SCL no tienen referencia.

La regla básica de sincronismo, que desarrollamos en el tema siguiente, es corta: SDA solo cambia mientras SCL está en bajo, y se lee mientras SCL está en alto. Las dos únicas excepciones son las marcas de comienzo y de fin de un mensaje, que son justamente cambios de SDA con SCL alto. Un receptor que mira SCL sabe, por lo tanto, cuándo puede confiar en SDA.

Como todos comparten dos líneas, en un momento dado solo uno habla. Hace falta entonces un modo de manejar una línea que permita que cualquiera la baje sin que dos dispositivos se estropeen entre sí. Eso nos lleva a la sección siguiente.

03 · La clave eléctrica

Colector abierto y Y cableado

En el tema 5 vimos las dos formas de construir una salida. En una salida push-pull dos transistores forman un par: uno conecta el pin a VDD (nivel alto) y el otro a masa (nivel bajo). Si dos salidas así se conectan a la misma línea y una intenta poner un 1 mientras la otra pone un 0, los transistores unen la alimentación con masa y circula una corriente de cortocircuito. Por eso en SPI cada esclavo desconecta MISO (alta impedancia) cuando no está seleccionado. I²C no tiene una línea de selección, así que necesita otra solución: que ninguna salida sea capaz de forzar un 1.

En una salida de colector abierto (o drenador abierto, en los transistores MOSFET), solo existe el transistor hacia masa. El dispositivo puede hacer dos cosas con la línea:

Bajar la línea

Enciende el transistor y la conecta a masa. La tensión cae a casi 0 V (como máximo 0,4 V en un dispositivo I²C estándar). Es lo que llamamos transmitir un 0.

Soltar la línea

Apaga el transistor y se desentiende: el pin queda en alta impedancia. La línea no está manejada por él; la sube la resistencia de pull-up hacia VDD. Es lo que llamamos transmitir un 1, aunque en rigor el dispositivo no hace nada.

Línea de colector abierto con tres dispositivos Una línea está unida a VDD mediante una resistencia de pull-up. Tres interruptores, uno por dispositivo, conectan la línea a masa. Si cualquiera de ellos se cierra, la línea queda en cero; si todos están abiertos, la resistencia la lleva a uno. Dispositivo ADispositivo BDispositivo C cada interruptor es el transistor de salida de un dispositivo VDDRp (pull-up) línea (SDA o SCL)masa

El resultado es un Y cableado (wired-AND): la línea vale 1 solo si todos los dispositivos la sueltan, y vale 0 apenas uno cualquiera la baje. Es exactamente la operación AND entre lo que cada uno intenta poner. Nadie puede dañar a nadie, porque lo peor que puede pasar es que dos dispositivos bajen la línea al mismo tiempo, y ambos lo hacen hacia el mismo lugar (masa).

Qué vale la línea según lo que hace cada uno de tres dispositivos (S = suelta, B = baja).
ABCLíneaQuién la determina
SSS1La pull-up (nadie conduce)
SBS0B
BBS0A y B, a la vez y sin conflicto

Esta propiedad hace posibles cuatro cosas que son parte del diseño de I²C:

  • Compartir una línea de datos entre todos los dispositivos, sin selección física: el que habla baja o suelta; los demás escuchan con la salida suelta.
  • Confirmaciones. Después de cada byte, el receptor baja SDA durante un pulso para decir «recibido»; si nadie la baja, la línea queda en 1 y el emisor sabe que nadie contestó (tema 17).
  • Arbitraje entre maestros. Si dos maestros empiezan a hablar al mismo tiempo, cada uno compara lo que quiso poner con lo que realmente lee en SDA; el que soltó un 1 y lee un 0 sabe que otro está hablando y se retira sin destruir el mensaje del otro.
  • Pausas del esclavo. Un esclavo lento puede mantener SCL en bajo para pedir más tiempo (clock stretching). Por eso SCL también es de colector abierto aunque casi siempre la maneje un solo maestro (tema 19).

El precio es la resistencia externa: sin ella, la línea nunca sube, y con ella los flancos de subida son lentos, como veremos a continuación. Los dispositivos I²C están diseñados para bajar la línea con una corriente limitada (3 mA en los modos estándar y rápido) y para tolerar que la lleven a masa otros.

04 · Una resistencia con consecuencias

La resistencia de pull-up

Cada línea tiene una resistencia desde VDD hasta la línea (Rp en el diagrama). Se llama pull-up y es la única responsable de las transiciones hacia el nivel alto. Hay una sola por línea: no una por dispositivo. Como cada dispositivo suma, además, una pequeña capacidad (la de su pin, la del cable, la de las pistas), lo que se carga a través de la resistencia es un condensador, y eso da una subida exponencial.

Flancos asimétricos de una línea I²C La tensión de la línea baja casi verticalmente cuando un dispositivo la conecta a masa, permanece en cero, y al soltarla sube con una curva exponencial lenta. Dos líneas punteadas marcan el 30 % y el 70 % de VDD, y el tiempo entre los cruces es el tiempo de subida. VDD0 V 70 % de VDD30 % de VDD flanco de bajada:rápido, lo fuerzael transistor flanco de subida:lento, lo da lapull-up y la capacidad tr = 0,8473 · R · C

La tensión de la línea sigue V(t) = VDD(1 − e−t/RC). La especificación mide el tiempo de subida entre el 30 % y el 70 % de VDD, que son los umbrales de bajo y alto. Resolviendo la exponencial para los dos puntos, la diferencia es siempre la misma constante por R·C:

tr = Rp · Cb · ln(0,7 / 0,3) ≈ 0,8473 · Rp · Cb

Aquí Cb es la capacidad total del bus. La subida tiene que ser más corta que el máximo de cada modo (1000 ns, 300 ns o 120 ns, según la tabla de la sección siguiente). Eso da un límite superior para la resistencia:

Rmáx = tr,máx / (0,8473 · Cb)

Pero no se puede usar una resistencia arbitrariamente chica para ir más rápido, porque cuando un dispositivo baja la línea tiene que absorber la corriente que fluye por la pull-up. Un dispositivo I²C garantiza bajar hasta VOL = 0,4 V con una corriente de IOL = 3 mA. Eso da un límite inferior:

Rmín = (VDD − VOL) / IOL

Ejemplo con VDD = 3,3 V, IOL = 3 mA, modo rápido (300 ns) y Cb = 100 pF:

  • Rmín = (3,3 − 0,4) / 0,003 ≈ 967 Ω.
  • Rmáx = 300 ns / (0,8473 · 100 pF) ≈ 3541 Ω.
  • Hay que elegir entre 967 Ω y 3541 Ω: 2,2 kΩ es un valor comercial en el medio, con tr ≈ 186 ns y 1,3 mA cuando la línea está baja.
  • Con los 4,7 kΩ que se suelen poner «por costumbre» el tiempo de subida sería de 398 ns: bien para el modo estándar (1000 ns), demasiado para el rápido (300 ns).

Dos observaciones. Primero, la capacidad pesa tanto como la resistencia: duplicar el cable duplica Cb y reduce a la mitad la resistencia máxima. Segundo, el cálculo supone que la subida es solo RC; los flancos reales dependen también de las entradas, y por eso se deja un margen y se confirma con un osciloscopio o un analizador lógico de buen ancho de banda.

05 · Cuánto se puede acelerar

Velocidades del bus

La especificación define varios modos. Lo que los distingue es la velocidad del reloj, el tiempo de subida que se tolera y, por eso mismo, cuánta capacidad admite el bus:

Modos de velocidad de I²C. Los bytes por segundo son un tope teórico: 9 pulsos de reloj por byte (8 bits y la confirmación), sin contar dirección ni marcas de inicio y fin.
ModoVelocidadtr máximoCb máximaPull-up típica (3,3 V)Bytes/s (tope)
Estándar (Sm)100 kbit/s1000 ns400 pF4,7 kΩ11 100
Rápido (Fm)400 kbit/s300 ns400 pF2,2 kΩ44 400
Rápido plus (Fm+)1 Mbit/s120 ns550 pF1 kΩ (los dispositivos deben bajar 20 mA)111 100
Alta velocidad (Hs)3,4 Mbit/sdecenas de ns100 a 400 pFfuente de corriente en el maestro≈ 378 000
Ultra rápido (UFm)5 Mbit/s——no usa pull-up: salidas push-pull, solo escritura≈ 625 000 (sin confirmación, 8 pulsos por byte)

Los tres primeros modos son los que se encuentran en la práctica. Hs y UFm son poco usados en proyectos de electrónica de consumo. Algunos puntos sobre la velocidad:

  • El bus corre a la velocidad del dispositivo más lento. Un sensor de 100 kHz en un bus con una memoria de 400 kHz obliga a todo el bus a usar 100 kHz mientras se le habla, o a cambiar el reloj en cada conversación. Mezclar modos obliga también a calcular la pull-up para el más exigente.
  • Frecuencia de reloj no es caudal de datos. Cada byte cuesta 9 pulsos, y cada mensaje agrega la dirección y las marcas de inicio y fin. Leer 6 bytes de un sensor son 7 bytes en el cable (dirección + datos): 63 pulsos, o 157,5 µs a 400 kHz. El mismo intercambio por SPI a 4 MHz son 56 pulsos y 14 µs: unas once veces más rápido.
  • En Arduino la velocidad por defecto es de 100 kHz. Se sube con Wire.setClock(400000) después de Wire.begin(), y eso solo debe hacerse después de comprobar que la pull-up da la subida necesaria.
  • El reloj real puede ser menor. Si un esclavo mantiene SCL en bajo (clock stretching) o si la subida lenta retrasa el flanco, la frecuencia efectiva cae por debajo del valor configurado.

La regla práctica: empezar a 100 kHz, comprobar que todo funciona y subir a 400 kHz solo si hace falta. Un bus en modo rápido con cables largos y resistencias de 10 kΩ es uno de los problemas más frecuentes de los proyectos con módulos baratos.

06 · Mezclar tensiones

Niveles de tensión distintos

En I²C los umbrales se definen en proporción a la alimentación de cada dispositivo: una entrada reconoce un nivel bajo por debajo del 30 % de su VDD y un nivel alto por encima del 70 %. La tensión en alto de la línea es la de la pull-up, y no necesariamente la de los dispositivos conectados. Esto es una ventaja frente a SPI: como nadie fuerza el 1, cada tramo del bus puede tener su propia tensión, con tal de separarlos con el circuito adecuado.

Sin ese circuito, con una sola pull-up para dos dispositivos de distinta alimentación, pasa una de dos cosas:

  • Si la pull-up va a la tensión mayor, el dispositivo de menor tensión recibe en sus pines más de lo que tolera. Es el caso de un Arduino Uno de 5 V con un sensor de 3,3 V: la línea sube a 5 V y el sensor puede dañarse (la mayoría de los pines de un CI de 3,3 V no toleran más de unos 3,6 V).
  • Si la pull-up va a la tensión menor, el dispositivo de mayor tensión no reconoce el nivel alto: un microcontrolador de 5 V necesita al menos 3,5 V (el 70 %), y con una línea de 3,3 V el 1 es ambiguo.

La solución estándar es un desplazador de nivel bidireccional con un transistor MOSFET de canal N (por ejemplo, el BSS138). Se usa uno por línea, con una pull-up de cada lado hacia la tensión de ese lado:

Desplazador de nivel bidireccional para una línea I²C Del lado izquierdo, una línea de 3,3 V con su pull-up, conectada a la fuente de un MOSFET de canal N cuya compuerta está a 3,3 V. Del lado derecho, una línea de 5 V con su pull-up, conectada al drenaje. El transistor une las dos líneas cuando cualquiera de ellas baja. MOSFETcanal N (BSS138) lado de 3,3 Vmaestro lado de 5 Vesclavo 3,3 V5 V RpRp G (compuerta) a 3,3 V S (fuente)D (drenaje) Un circuito idéntico para SDA y otro para SCL

Funciona porque la compuerta está fija en la tensión del lado bajo, y el transistor se comporta según el estado de las líneas:

  1. Nadie baja. Cada lado queda en su propia tensión (3,3 V y 5 V) por su pull-up. La tensión entre compuerta y fuente es cero y el transistor está apagado: los dos lados quedan separados.
  2. El lado de 3,3 V baja la línea. La fuente cae, la compuerta queda 3,3 V por encima y el transistor conduce: arrastra también el lado de 5 V a cero. El 0 pasa de un lado al otro.
  3. El lado de 5 V baja la línea. El diodo interno del transistor baja primero la fuente; apenas la tensión entre compuerta y fuente supera el umbral, el transistor conduce y el lado de 3,3 V también baja.

Existen también integrados dedicados para este trabajo (como el PCA9306 o el TXS0102) y módulos de cuatro o más canales que traen los MOSFET y las resistencias ya soldados. Tienen que ser bidireccionales con colector abierto: un desplazador unidireccional, como el que se usa para SPI, no sirve porque SDA cambia de sentido durante un mismo mensaje.

07 · Con el microcontrolador

Con el microcontrolador

Los dos programas siguientes son para un ESP32 con los pines por defecto (SDA en 21, SCL en 22; en un Uno son A4 y A5). El primero es una prueba del estado de reposo que conviene hacer antes de usar cualquier biblioteca: con los dispositivos conectados y sin tráfico, las dos líneas tienen que leerse en alto. Si no es así, ninguna biblioteca va a funcionar.

#include <Wire.h>

const byte PIN_SDA = 21;
const byte PIN_SCL = 22;

// Estado de una línea con los dispositivos conectados y el bus en reposo.
const char *diagnosticar(byte pin) {
    pinMode(pin, INPUT);                       // solo la pull-up externa puede subirla
    delayMicroseconds(100);
    if (digitalRead(pin)) return "alto: la pull-up externa funciona";
    pinMode(pin, INPUT_PULLUP);                // ¿mejora si ayuda la pull-up interna?
    delayMicroseconds(100);
    bool conInterna = digitalRead(pin);
    pinMode(pin, INPUT);
    return conInterna ? "bajo: falta la pull-up externa (flota)"
                      : "bajo: alguien la retiene a masa (dispositivo trabado o cortocircuito)";
}

void setup() {
    Serial.begin(115200);
    Serial.print("SDA: "); Serial.println(diagnosticar(PIN_SDA));
    Serial.print("SCL: "); Serial.println(diagnosticar(PIN_SCL));

    Wire.begin(PIN_SDA, PIN_SCL);
    Wire.setClock(100000);                     // empezar lento; subir a 400000 con la pull-up verificada
}

void loop() {}

La lógica del diagnóstico es la que se aplica con un multímetro: una línea que no sube es o bien una línea sin pull-up (flota y el pin la lee en bajo o de forma errática) o bien una línea retenida a masa. La diferencia se ve con la pull-up interna: si con ella sube, no había resistencia externa; si sigue en bajo, algo la está bajando (un dispositivo que quedó a mitad de una operación, un módulo en cortocircuito o un cable roto). El segundo programa maneja una línea a mano como colector abierto y estima el tiempo de subida que produce el conjunto de pull-up y capacidad:

// ESP32: medir cuánto tarda una línea en subir cuando se la suelta.
const byte PIN_LINEA = 21;                     // con el bus I²C sin inicializar (sin Wire.begin)

inline void bajar()  { pinMode(PIN_LINEA, OUTPUT); digitalWrite(PIN_LINEA, LOW); }
inline void soltar() { pinMode(PIN_LINEA, INPUT); }        // nunca digitalWrite(HIGH): eso es push-pull

// Nanosegundos desde que se suelta hasta que el pin lee 1, o 0xFFFFFFFF si no sube en 1 ms.
uint32_t medirSubidaNs() {
    const uint32_t mhz = getCpuFrequencyMhz();
    bajar();
    delayMicroseconds(50);                     // tiempo de sobra para descargar la capacidad
    noInterrupts();
    soltar();
    uint32_t t0 = ESP.getCycleCount();
    uint32_t ciclos;
    while (!digitalRead(PIN_LINEA)) {
        ciclos = ESP.getCycleCount() - t0;
        if (ciclos > mhz * 1000) { interrupts(); return 0xFFFFFFFF; }
    }
    ciclos = ESP.getCycleCount() - t0;
    interrupts();
    return ciclos * 1000UL / mhz;
}

void setup() {
    Serial.begin(115200);
}

void loop() {
    uint32_t ns = medirSubidaNs();
    if (ns == 0xFFFFFFFF) Serial.println("La línea no sube: falta la pull-up o está retenida");
    else {
        Serial.print("Subida hasta el umbral del pin: "); Serial.print(ns); Serial.println(" ns");
        // t = -R·C·ln(1 - 0,7) ≈ 1,2 · R · C  →  C ≈ t / (1,2 · R)
    }
    delay(1000);
}

El valor medido es el tiempo hasta que el pin lee un 1, que ocurre cerca del 60 al 70 % de VDD, así que equivale aproximadamente a 1,2 · R · C. Conocida la resistencia, se puede despejar la capacidad: con 4,7 kΩ y una lectura de 1000 ns, C ≈ 1000 / (1,2 · 4700) ≈ 177 pF. El resultado tiene una incertidumbre de unos cientos de nanosegundos por el tiempo que tarda cada digitalRead, de modo que sirve como orden de magnitud y para comparar un cableado con otro, no como instrumento de precisión. Para medidas finas está el analizador lógico o el osciloscopio.

Dos consejos para el uso normal de Wire. Primero, averiguar si la biblioteca activa las pull-ups internas: en las placas AVR (Uno, Nano) lo hace y empuja las líneas hacia la tensión del micro; en otras plataformas depende del núcleo. Segundo, medir la capacidad antes y después de agregar un módulo con el programa de medición, en lugar de descubrir el problema cuando el bus deja de responder.

08 · Analogía con programación

La línea y el dimensionado en Python

Antes de armar el circuito se puede capturar en un programa lo esencial de este tema: cómo se combinan las salidas en una línea de colector abierto, qué rango de pull-up admite cada modo y qué pasa con las resistencias en paralelo de varios módulos. El modelo siguiente usa las mismas fórmulas de la sección 04.

Python en tu navegador. Los bloques son editables: cambiá los valores y presioná «Ejecutar Python». La primera vez tarda unos segundos en cargar.

import math

K = math.log(0.7 / 0.3)          # tiempo de subida del 30 % al 70 % = K · R · C
VOL = 0.4                        # tensión máxima de un nivel bajo válido

MODOS = {                        # velocidad en kbit/s, subida máxima en ns, capacidad máxima en pF, corriente de bajada en mA
    "estándar": {"kbps": 100,  "tr_ns": 1000, "cb_pf": 400, "iol_ma": 3},
    "rápido":   {"kbps": 400,  "tr_ns": 300,  "cb_pf": 400, "iol_ma": 3},
    "rápido+":  {"kbps": 1000, "tr_ns": 120,  "cb_pf": 550, "iol_ma": 20},
}


def linea(salidas, tipo="colector abierto"):
    """Nivel de una línea compartida. Cada salida es 1 (suelta o fuerza un 1) o 0 (baja)."""
    if tipo == "colector abierto":
        return 0 if 0 in salidas else 1          # Y cableado: basta que uno baje
    if 0 in salidas and 1 in salidas:
        return "corto"                           # push-pull: alguien fuerza 1 y alguien fuerza 0
    return salidas[0]


def subida_ns(r, c_pf):
    return K * r * c_pf * 1e-3                   # ohmios · picofaradios → nanosegundos


def r_min(vdd, iol_ma):
    return (vdd - VOL) / (iol_ma * 1e-3)


def r_max(modo, c_pf):
    return MODOS[modo]["tr_ns"] / (K * c_pf * 1e-3)


def en_paralelo(*resistencias):
    return 1 / sum(1 / r for r in resistencias)


def revisar(modo, vdd, r, c_pf):
    m = MODOS[modo]
    tr = subida_ns(r, c_pf)
    avisos = []
    if c_pf > m["cb_pf"]:
        avisos.append(f"capacidad de {c_pf} pF, el modo admite {m['cb_pf']} pF")
    if r < r_min(vdd, m["iol_ma"]):
        avisos.append("R demasiado baja: el dispositivo no llega a bajar la línea a 0,4 V")
    if tr > m["tr_ns"]:
        avisos.append(f"subida de {tr:.0f} ns, el modo admite {m['tr_ns']} ns")
    return tr, avisos or ["correcto"]


print("Línea compartida (1 = suelta o fuerza un 1, 0 = baja):")
for salidas in ([1, 1, 1], [1, 0, 1], [0, 0, 1]):
    print(f"  salidas {salidas}: colector abierto -> {linea(salidas)}   push-pull -> {linea(salidas, 'push-pull')}")

print()
print("Resistencia de pull-up admisible con 3,3 V y 100 pF:")
for modo, m in MODOS.items():
    print(f"  modo {modo:9}: de {r_min(3.3, m['iol_ma']):5.0f} Ω a {r_max(modo, 100):5.0f} Ω")

print()
print("Revisión de combinaciones con 3,3 V:")
for modo, r, c in (("estándar", 4700, 100), ("rápido", 4700, 100), ("rápido", 2200, 100), ("rápido", 2200, 250), ("rápido", 470, 100)):
    tr, avisos = revisar(modo, 3.3, r, c)
    print(f"  {modo:9} R={r:5} Ω C={c:3} pF -> tr={tr:4.0f} ns: {'; '.join(avisos)}")

print()
r = en_paralelo(4700, 10000, 10000, 10000)
tr, avisos = revisar("rápido", 3.3, r, 100)
print(f"Una pull-up de 4,7 kΩ y tres módulos con 10 kΩ en paralelo: {r:.0f} Ω, tr={tr:.0f} ns, {(3.3 - VOL) / r * 1000:.2f} mA al bajar -> {avisos[0]}")

print()
print("Tiempo de «dirección + 6 bytes» (7 bytes × 9 pulsos = 63 pulsos):")
for modo, m in MODOS.items():
    print(f"  {modo:9}: {63 / (m['kbps'] * 1e3) * 1e6:6.1f} µs")
print(f"  por SPI a 4 MHz (7 bytes × 8 pulsos = 56): {56 / 4e6 * 1e6:.1f} µs")

Resultado: con tres salidas en [1, 1, 1] la línea vale 1 en ambos tipos; con [1, 0, 1] y [0, 0, 1] el colector abierto da 0 (Y cableado), y el push-pull da corto: dos salidas se oponen. Los rangos de pull-up con 3,3 V y 100 pF son 967 Ω a 11 802 Ω (estándar), 967 Ω a 3541 Ω (rápido) y 145 Ω a 1416 Ω (rápido plus, que baja 20 mA). La revisión da: 4,7 kΩ con 100 pF cumple en modo estándar (398 ns), pero en modo rápido falla (398 ns contra 300); con 2,2 kΩ cumple (186 ns); con 2,2 kΩ y 250 pF vuelve a fallar (466 ns); y con 470 Ω la subida es excelente (40 ns) pero la resistencia es demasiado baja para los 3 mA del dispositivo. Las resistencias de 4,7 kΩ y tres de 10 kΩ en paralelo valen 1950 Ω: la subida es de 165 ns y la corriente al bajar, 1,49 mA, de modo que el bus sigue sirviendo para el modo rápido. En el tiempo de transferencia, 63 pulsos son 630 µs a 100 kHz, 157,5 µs a 400 kHz y 63 µs a 1 MHz; por SPI a 4 MHz el mismo intercambio tarda 14 µs.

Observá el caso de las resistencias en paralelo: las pull-ups de varios módulos se suman sin que nadie lo haya decidido. Cada módulo de bajo costo trae las suyas en la placa, y el conjunto puede quedar por debajo del mínimo, sobre todo a 5 V y con muchos módulos.

09 · Exploración interactiva

Laboratorio: línea, pull-up y niveles

El laboratorio tiene tres herramientas. La primera es una línea compartida por tres dispositivos, con salidas de colector abierto o push-pull: elegís qué hace cada uno y ves el nivel de la línea y la corriente. La segunda es un calculador de pull-up: elegís el modo, la tensión, la resistencia y la capacidad, y ves el tiempo de subida sobre una curva, el rango admisible y el veredicto. La tercera es un conversor de niveles: elegís las tensiones del maestro y del sensor y la forma de conectarlos.

1. Una línea, tres dispositivos

Nivel de la línea—
Tensión—
Corriente—
Veredicto—

Elegí qué hace cada dispositivo con la línea.

2. Pull-up, capacidad y tiempo de subida

70 %30 %0VDD 01000 ns2000 ns línea naranja: límite del modo
Tiempo de subida (30 % a 70 %)—
Máximo permitido—
Pull-up admisible—
Corriente con la línea baja—
Caudal teórico del modo—
Veredicto—

Elegí el modo, la resistencia y la capacidad.

3. Tensiones distintas en el mismo bus

Nivel alto de la línea—
El maestro recibe—
El sensor recibe—
Veredicto—

Elegí las tensiones y la forma de conexión.

En la herramienta 1 el cálculo de corriente usa la resistencia elegida y 0,4 V de bajada; con push-pull el cortocircuito no se calcula porque depende de los transistores de cada pin. La herramienta 2 usa los límites de la especificación (tabla de la sección 05) y supone una sola resistencia equivalente para toda la línea. En la 3 se supone que los pines toleran lo que su alimentación más 0,3 V; la hoja de datos de cada dispositivo manda.

Recorrido guiado

  1. Con los valores iniciales (colector abierto, los tres dispositivos sueltan), la línea vale 1 a 3,3 V. La corriente es cero: nadie conduce, y la pull-up la mantiene arriba.
  2. Hacé que el dispositivo B baje: la línea vale 0 y la corriente por la pull-up es de 0,62 mA (2,9 V / 4,7 kΩ). Hacé que A y B bajen a la vez: sigue en 0 sin conflicto. Es el Y cableado.
  3. Cambiá a push-pull con el dispositivo A en «Fuerza un 1» y el B en «Fuerza un 0»: «Cortocircuito». La misma situación que en colector abierto era normal, aquí es un defecto del circuito.
  4. En la herramienta 2, con los valores iniciales (modo estándar, 3,3 V, 4,7 kΩ y 100 pF), el tiempo de subida es de 398 ns, dentro de los 1000 ns del modo: «Cumple». El rango admisible va de 967 Ω a 11 802 Ω.
  5. Pasá al modo rápido: el máximo baja a 300 ns y el veredicto cambia a «No cumple». El rango admisible es ahora de 967 Ω a 3541 Ω. Elegí 2,2 kΩ: 186 ns y 1,32 mA; vuelve a cumplir.
  6. Con 2,2 kΩ y modo rápido, subí la capacidad a 250 pF: la subida es de 466 ns y falla; el rango se reduce a 967 Ω a 1416 Ω. Bajá la resistencia a 1 kΩ: 212 ns y 2,90 mA, justo por debajo de los 3 mA. Con 470 Ω la subida es muy buena, pero la corriente (6,17 mA) supera lo que el dispositivo puede absorber.
  7. Subí la capacidad a 450 pF en modo rápido: se supera el máximo de 400 pF y el rango admisible es «ninguna» (la resistencia máxima de 787 Ω quedaría por debajo de la mínima de 967 Ω). No hay resistencia que lo arregle: hay que reducir la capacidad.
  8. Elegí 30 kΩ (la pull-up interna de un micro) en modo estándar con 100 pF: la subida es de 2542 ns, más del doble de lo permitido.
  9. Cambiá a 5 V con 4,7 kΩ y modo estándar: la corriente con la línea baja sube a 0,98 mA. Una tensión mayor da más corriente por la misma resistencia.
  10. En la herramienta 3, con maestro de 5 V y sensor de 3,3 V con la pull-up del maestro: el sensor recibe 5,0 V y se marca «sobretensión».
  11. Pasá la pull-up al sensor (3,3 V): ahora el sobrevoltaje desaparece, pero el maestro de 5 V necesita 3,50 V para reconocer un 1 y no los tiene. La tercera opción, el desplazador bidireccional, es la que cumple con ambos.
Desafío: cuántos módulos entran en un bus rápido

Cada módulo de bajo costo trae dos pull-ups de 10 kΩ (una en SDA y otra en SCL). Con 3,3 V y 100 pF de capacidad, ¿cuántos módulos iguales pueden conectarse en paralelo antes de que la resistencia total baje de los 967 Ω? Con n módulos la pull-up equivalente es 10 000 / n: para que no baje de 967 Ω, n debe ser menor o igual a 10 000 / 967 ≈ 10. Pero el límite práctico se alcanza antes, por la capacidad (cada módulo agrega la suya) y porque 967 Ω es el límite del dispositivo. Con 4 o 5 módulos, el conjunto queda en 2 a 2,5 kΩ y sirve para el modo rápido.

10 · Un procedimiento

Cómo dimensionar un bus I²C

El cálculo de la pull-up es la parte del trabajo que más se omite y la que más problemas da. Un procedimiento simple, de seis pasos, evita casi todos:

  1. Listar los dispositivos y sus tensiones. Si hay más de una tensión, se necesita un desplazador de nivel entre los grupos (sección 06).
  2. Elegir el modo de velocidad por el dispositivo más lento o más exigente, y empezar siempre por el estándar.
  3. Estimar la capacidad. Un pin de dispositivo suma del orden de 5 a 10 pF, el cable unos 50 a 100 pF por metro, y las pistas y los conectores algunos picofaradios. Cinco dispositivos y medio metro de cable pueden sumar unos 90 a 100 pF. Por encima de 400 pF el bus no cumple la especificación.
  4. Calcular el rango de la pull-up con Rmín = (VDD − 0,4) / 3 mA y Rmáx = tr,máx / (0,8473 · Cb). Si Rmín > Rmáx, no hay solución y hay que acortar el bus, reducir dispositivos o bajar el modo.
  5. Contar las pull-ups que ya hay: las de cada módulo están en paralelo. Si el conjunto cae en el rango, no se agrega nada; si queda debajo del mínimo, se retira o se cortan las de algún módulo; si queda por encima del máximo, se agrega una resistencia en paralelo.
  6. Medir. Con un analizador lógico o un osciloscopio se verifica que la subida cumpla y que el nivel bajo no pase de 0,4 V. Con el analizador solo se ve un nivel lógico, pero basta para comprobar que los bits se leen donde corresponde.
Síntomas más frecuentes y su causa probable.
SíntomaCausa probableQué hacer
Ninguno de los dispositivos responde, SDA o SCL leen 0 en reposoUn dispositivo reteniendo la línea, cortocircuito o pull-up a la tensión equivocadaDesconectar los dispositivos de a uno hasta que la línea suba; revisar el cableado
Las líneas flotan y el comportamiento es erráticoNo hay ninguna pull-upAgregar resistencias externas (o usar un módulo que las traiga)
Funciona a 100 kHz y falla a 400 kHzSubida demasiado lenta: resistencia alta o cable largoBajar la pull-up dentro del rango, acortar el cable
Funciona solo con pocos dispositivos y falla al agregar otroLa capacidad total pasó del límiteMedir la capacidad, acortar cables, bajar el modo
El nivel bajo no baja de 0,6 o 0,8 VPull-up muy baja (el dispositivo no puede absorber la corriente) o conexión de masa deficienteSubir la resistencia y revisar la masa común
Un sensor de 3,3 V se calienta o muere en un Arduino de 5 VPull-ups a 5 V sobre un dispositivo de 3,3 VUsar un desplazador de nivel bidireccional

El tema 19 vuelve sobre varias de estas situaciones (capacidad, bus bloqueado, clock stretching) con ejemplos de captura.

11 · Comprensión

Confusiones frecuentes

«I²C usa dos hilos, así que es como una UART»

No. Una UART no tiene reloj: cada lado mide el tiempo por su cuenta. I²C tiene una línea de reloj que genera el maestro, direcciones para elegir el destino y una confirmación por cada byte. Además, la línea de datos es única y compartida por todos.

«Un dispositivo I²C envía un 1 poniendo la línea en alto»

Nadie fuerza el 1. El dispositivo suelta la línea y la sube la pull-up. Un pin configurado como salida en alto es un error: se pelea con los demás.

«Con cada módulo que agrego, agrego su resistencia y todo va mejor»

Las pull-ups de los módulos se suman en paralelo y la resistencia total baja. Con demasiados módulos, el conjunto queda por debajo del mínimo y los dispositivos no pueden bajar la línea hasta 0,4 V. Hay una sola pull-up efectiva por línea, no una por dispositivo.

«Cuanto menor la resistencia, mejor, porque la señal sube más rápido»

Hasta un punto: la resistencia mínima la fija la corriente que puede absorber el dispositivo (3 mA). Por debajo, el nivel bajo no llega a 0,4 V y el bus pierde confiabilidad, además de consumir más.

«Las pull-ups internas del micro son suficientes»

Valen de 20 a 50 kΩ y con una capacidad típica dan subidas de varios microsegundos, mucho más que los 1000 ns del modo más lento. Pueden funcionar en pruebas de banco a velocidades muy bajas, pero no en un diseño serio.

«El bus anda a 400 kHz porque lo configuré a 400 kHz»

El reloj configurado es un máximo. Si la subida es demasiado lenta, los bits no son válidos a esa frecuencia; si un esclavo estira el reloj, la frecuencia efectiva es menor. Hay que verificar con la captura.

«Puedo conectar un sensor de 3,3 V a un Arduino de 5 V y usar los pines SDA y SCL directamente»

Solo si el sensor tolera 5 V en esos pines (algunos módulos con regulador y adaptador integrados sí). Un CI de 3,3 V suelto no. En ese caso hace falta un desplazador de nivel bidireccional con colector abierto.

«I²C es lento, entonces siempre conviene SPI»

Depende de qué se lea. Con un sensor que da una muestra por segundo, la diferencia de velocidad no se nota y I²C ahorra pines y cableado. SPI conviene para pantallas, memorias y conversores rápidos.

12 · Práctica guiada

Predecí antes de comprobar

1. Rango de la pull-up

Un bus en modo rápido, a 3,3 V, tiene una capacidad estimada de 150 pF. ¿Entre qué valores tiene que estar la pull-up? ¿Qué valor comercial elegirías?

Ver solución

Rmín = (3,3 − 0,4) / 0,003 ≈ 967 Ω. Rmáx = 300 ns / (0,8473 · 150 pF) ≈ 2360 Ω. Los valores comerciales dentro del rango son 1,0; 1,2; 1,5; 1,8 y 2,2 kΩ. Los del medio (1,5 kΩ o 1,8 kΩ) dan margen para las tolerancias; 2,2 kΩ está dentro pero muy cerca del límite superior.

2. Pull-ups que se suman

Una placa tiene una pull-up de 4,7 kΩ en SDA, y se le conectan tres módulos que traen 10 kΩ cada uno. ¿Cuánto vale la resistencia equivalente y sirve para el modo rápido con 100 pF?

Ver solución

1 / (1/4700 + 3/10 000) = 1950 Ω. Está por encima del mínimo (967 Ω) y el tiempo de subida es 0,8473 · 1950 · 100 pF ≈ 165 ns, menor que 300 ns. Sirve. La corriente al bajar es (3,3 − 0,4) / 1950 ≈ 1,49 mA.

3. Cuánta capacidad admite una resistencia

Con una pull-up de 4,7 kΩ y modo rápido, ¿cuál es la capacidad máxima del bus? ¿Y si se reemplaza por una de 2,2 kΩ?

Ver solución

Cmáx = tr,máx / (0,8473 · R). Con 4,7 kΩ: 300 ns / (0,8473 · 4700) ≈ 75 pF, que ya es poco para algunos dispositivos y un cable. Con 2,2 kΩ: 161 pF. Bajar la resistencia a la mitad duplica la capacidad admisible, hasta el límite de la corriente.

4. Un Arduino Uno y un sensor de 3,3 V

Conectás un sensor de 3,3 V directamente a los pines A4 y A5 de un Uno (5 V) que usa Wire. ¿Qué tensión ve el sensor en reposo y qué se debe hacer?

Ver solución

Wire activa las pull-ups internas de SDA y SCL, que suben las líneas hacia 5 V; el sensor ve esa tensión en sus pines, por encima de los 3,6 V que suele tolerar. Hay que usar un desplazador de nivel bidireccional (con MOSFET o un integrado como el PCA9306), con la pull-up del lado de 3,3 V a 3,3 V y la del lado de 5 V a 5 V; o bien cambiar a una placa de 3,3 V.

5. Tiempo de una lectura

Leés 6 bytes de datos de un sensor. Contando la dirección, son 7 bytes y 9 pulsos por byte. ¿Cuánto tarda a 100 kHz y a 400 kHz? ¿Y con SPI a 4 MHz, con 1 byte de comando y 6 de datos?

Ver solución

I²C: 7 × 9 = 63 pulsos: 630 µs a 100 kHz y 157,5 µs a 400 kHz. SPI: 7 × 8 = 56 pulsos a 4 MHz: 14 µs, unas once veces más rápido que I²C a 400 kHz. (Se ignoran el tiempo entre transacciones y las marcas de inicio y fin.)

6. Corriente en el nivel bajo

¿Qué corriente circula por una pull-up de 4,7 kΩ cuando la línea está baja, a 3,3 V y a 5 V? ¿Y si la pull-up fuera de 470 Ω a 3,3 V?

Ver solución

(VDD − 0,4) / R: a 3,3 V, 2,9 / 4700 ≈ 0,62 mA; a 5 V, 4,6 / 4700 ≈ 0,98 mA. Con 470 Ω a 3,3 V: 6,17 mA, más del doble de los 3 mA que garantiza un dispositivo estándar: la línea no bajaría de 0,4 V.

7. Diagnóstico de reposo

Con el bus en reposo, el programa de la sección 07 informa: (a) «SDA bajo: falta la pull-up externa»; (b) «SCL bajo: alguien la retiene a masa». ¿Qué revisás en cada caso?

Ver solución

(a) La línea flota y solo sube con la pull-up interna: no hay resistencia externa (o está mal soldada o conectada a una tensión que no existe). Se agrega o se revisa. (b) Ni con la ayuda de la pull-up interna sube: algo la mantiene a masa. Se desconectan los dispositivos de a uno, se revisa un cortocircuito entre pistas o cables y se busca un esclavo que haya quedado trabado.

13 · Síntesis

Ideas para recordar

  • I²C usa dos hilos para cualquier cantidad de dispositivos: SCL (reloj, lo genera el maestro) y SDA (datos, bidireccional), además de la masa común. El destinatario se elige con una dirección y no con una línea de selección.
  • Las salidas son de colector abierto: un dispositivo solo puede bajar la línea o soltarla; el nivel alto lo pone la resistencia de pull-up. Nadie envía un 1.
  • La línea resulta un Y cableado: vale 1 solo si todos la sueltan y 0 si cualquiera la baja. Eso permite compartir la línea sin cortocircuitos, confirmar los bytes, arbitrar entre maestros y estirar el reloj.
  • Hay una sola pull-up efectiva por línea. Las de los módulos quedan en paralelo y su valor combinado es el que cuenta.
  • El tiempo de subida del 30 % al 70 % es tr ≈ 0,8473 · R · C. De ahí sale la resistencia máxima, y la mínima sale de la corriente de bajada: Rmín = (VDD − 0,4) / 3 mA.
  • Los modos habituales son: estándar (100 kbit/s, subida de 1000 ns), rápido (400 kbit/s, 300 ns) y rápido plus (1 Mbit/s, 120 ns). La capacidad máxima es de 400 pF (550 pF en rápido plus). El bus corre a la velocidad del dispositivo más lento.
  • Cada byte cuesta 9 pulsos de reloj: la velocidad real es menor que la nominal y claramente menor que la de SPI, pero alcanza para sensores y configuraciones.
  • Los umbrales son del 30 % y el 70 % de la alimentación de cada dispositivo. Para mezclar tensiones se usa un desplazador de nivel bidireccional con colector abierto (MOSFET como el BSS138 o un integrado como el PCA9306), con una pull-up de cada lado.
  • Un bus nuevo se prueba mirando primero el reposo: SDA y SCL deben leerse en alto. Si no, o falta la pull-up o alguien retiene la línea.

¿Listo para el siguiente tema?

Antes de avanzar, calculá el rango de la pull-up para un bus de 5 V en modo estándar con 200 pF; explicá por qué un dispositivo que quiere transmitir un 1 no hace nada; y decidí qué conectarías entre un maestro de 3,3 V y un sensor de 1,8 V. Si podés justificar las tres respuestas, tenés la base eléctrica de I²C. (Para la primera: Rmín = 4,6 / 3 mA ≈ 1533 Ω y Rmáx = 1000 ns / (0,8473 · 200 pF) ≈ 5901 Ω.)

En el próximo tema vemos qué viaja por esas dos líneas: las condiciones de inicio y fin, las direcciones de 7 bits, el bit de lectura o escritura y las confirmaciones ACK y NACK.