I2C y SPI: los dos buses seriales del mundo embebido
Por qué los periféricos lentos —sensores, EEPROM, pantallas— no cuelgan de un bus paralelo sino de dos hilos (I2C) o cuatro (SPI). Direccionamiento lógico por número frente a selección física por línea, half-duplex frente a full-duplex, y el compromiso entre pines y velocidad que decide cuál usar.
No todo periférico merece un bus paralelo de treinta pines. Un sensor de temperatura que entrega dos bytes por segundo, una EEPROM que guarda la calibración de fábrica, una pequeña pantalla OLED que refresca unos kilobytes: son dispositivos lentos e íntimos que solo necesitan intercambiar puñados de bytes con el procesador. Para ellos, la industria embebida consagró dos buses seriales que reducen el conexionado al hueso. I2C viaja por dos hilos y distingue a sus dispositivos por un número de dirección; SPI usa cuatro y los elige activando una línea física. Escoger entre ambos es situarse en un único eje de tensión: pines contra velocidad.
- Entender por qué un periférico lento cuelga de un bus serial y no de uno paralelo.
- Dominar la topología de I2C: dos hilos, direcciones de 7 bits, open-drain y multi-maestro.
- Dominar la topología de SPI: full-duplex, chip select y ausencia de direcciones.
- Saber decidir entre I2C y SPI según pines, frecuencia y número de dispositivos.
El coste de un pin
En un SoC, el recurso más escaso no es la frecuencia ni la memoria: son los pines. Cada patilla que sale del encapsulado cuesta área de silicio, encarece el empaquetado y complica el enrutado de la placa. Un bus paralelo de ocho o dieciséis líneas de datos más su control devora decenas de pines por dispositivo, un lujo impensable para colgar cinco sensores de un microcontrolador. Los buses seriales hacen el canje evidente: sacrifican anchura por tiempo. En lugar de presentar ocho bits a la vez sobre ocho hilos, envían los bits uno tras otro por uno o dos. Para un periférico lento —donde una latencia de microsegundos es irrelevante— el canje sale gratis. Linux enumera cada bus descubierto y cuelga de él sus dispositivos, visibles en sysfs:
# buses y dispositivos que el kernel ha enumerado
ls /sys/bus/i2c/devices/ # i2c-0 i2c-1 1-0048 ...
ls /sys/bus/spi/devices/ # spi0.0 spi0.1 ...
# mapa de direcciones ocupadas del bus I2C numero 1
i2cdetect -y 1
El nombre 1-0048 no es arbitrario: codifica el bus (1) y la dirección del dispositivo (0x48). Esa nomenclatura ya delata la diferencia esencial entre los dos buses, que es cómo nombran a quién habla.
I2C: dos hilos y un mapa de direcciones
I2C (Inter-Integrated Circuit) reduce el bus a dos hilos compartidos por todos: SDA para los datos y SCL para el reloj. Ambos son de colector abierto (open-drain) con resistencias de pull-up: nadie fuerza un uno activo, solo se tira a cero o se suelta la línea, que el pull-up devuelve a uno. Esta lógica de Y-cableada (wired-AND) es la clave de toda la elegancia del bus. El maestro genera el reloj e inicia cada transacción; los esclavos responden. Cada dispositivo tiene una dirección de 7 bits, así que en un bus caben hasta unos 112 dispositivos —algunas direcciones están reservadas—, y el maestro elige con quién habla emitiéndola al principio de la trama.
Una transferencia se enmarca entre una condición de arranque (start) y una de parada (stop), y cada byte va seguido de un bit de reconocimiento (ACK) que el receptor genera tirando SDA a cero. Las velocidades estandarizadas van del modo normal a 100 kbit/s, pasando por el rápido a 400 kbit/s y el rápido-plus a 1 Mbit/s, hasta el de alta velocidad a 3,4 Mbit/s. Y como la línea es de Y-cableada, I2C admite varios maestros: si dos arrancan a la vez, el que pretenda emitir un uno mientras lee un cero en SDA reconoce que ha perdido el arbitraje y se retira sin corromper la trama del ganador. En el device tree, un dispositivo I2C se declara como hijo del controlador, y su propiedad reg es literalmente su dirección de 7 bits:
&i2c1 {
clock-frequency = <400000>; /* 400 kHz, modo rapido */
sensor@48 {
compatible = "ti,tmp117"; /* casa con el driver */
reg = <0x48>; /* la direccion I2C de 7 bits */
};
};
SMBus (System Management Bus) es un subconjunto de I2C con reglas más estrictas: define tipos de transacción fijos —leer o escribir un byte o una palabra en un registro—, impone tiempos de espera (timeouts) y añade una suma de comprobación opcional (PEC). La mayoría de los sensores hablan este dialecto, y por eso el kernel ofrece una familia i2c_smbus_* que, si el controlador no implementa SMBus en hardware, emula sobre transferencias I2C crudas. Programar contra SMBus es más portable y conciso que armar tramas a mano.
SPI: full-duplex y selección física
SPI (Serial Peripheral Interface) toma el camino opuesto. Usa cuatro líneas: SCLK (reloj), MOSI (datos del controlador al periférico, hoy también llamada COPI), MISO (del periférico al controlador, o CIPO) y CS (chip select, casi siempre activa a cero). No hay direcciones: cada periférico tiene su propia línea CS, y el controlador elige con quién habla bajándola. N periféricos exigen N líneas de selección, aunque comparten SCLK, MOSI y MISO.
Su rasgo definitorio es el full-duplex. Controlador y periférico forman un anillo de dos registros de desplazamiento: en cada pulso de reloj sale un bit por MOSI y entra otro por MISO, simultáneamente. No existe, a nivel físico, una operación de solo lectura o solo escritura; existe el intercambio. SPI no tiene ACK, ni arbitraje, ni tramas definidas: el controlador manda el reloj y ambos extremos confían en que el otro conoce el protocolo del chip. A cambio de esa desnudez, es mucho más rápido: decenas de megahercios son rutina, y las flash SPI superan los 100 MHz. En el device tree, reg ya no es una dirección sino el índice del chip select:
&spi0 {
adc@0 {
compatible = "adi,ad7292";
reg = <0>; /* el numero de chip select, no una direccion */
spi-max-frequency = <20000000>;
spi-cpha; /* fase de reloj: esto sera el modo 1 */
};
};
flowchart TB subgraph SG_I2C [I2C dos hilos para todos distingue por direccion] M[Maestro] --- SDA_SCL[SDA y SCL compartidos] SDA_SCL --- A[Esclavo 0x48] SDA_SCL --- B[Esclavo 0x68] SDA_SCL --- D[Esclavo 0x1d] end subgraph SG_SPI [SPI reloj y datos comunes una linea CS por dispositivo] C[Controlador] -->|SCLK MOSI MISO| P0[Periferico 0] C -->|CS0| P0 C -->|CS1| P1[Periferico 1] C -->|CS2| P2[Periferico 2] end
I2C: pocos hilos, muchos nodos
Dos pines para todo el bus y direccionamiento lógico: ideal para colgar muchos dispositivos lentos —sensores, EEPROM, RTC, controladores de energía—. El precio es la velocidad, el ACK por byte y la fragilidad de los pull-ups.
SPI: rápido y full-duplex
Intercambio simultáneo en ambos sentidos a decenas de MHz: la elección para flash, pantallas, ADC de alta tasa y radios. El precio es un pin CS por dispositivo y la ausencia de todo protocolo estándar.
En 2026 asoma I3C (MIPI), pensado para heredar los dos hilos de I2C pero con velocidades cercanas a SPI, interrupciones en banda (in-band) y descubrimiento dinámico de dispositivos. Linux ya tiene subsistema propio en drivers/i3c/ y compatibilidad hacia atrás con dispositivos I2C legados en el mismo bus. No sustituye aún a I2C ni a SPI en el grueso del hardware desplegado, pero conviene saber que la dicotomía de este nivel tiende, a largo plazo, a difuminarse.
Detente en la diferencia más honda entre estos dos buses, porque no es un detalle eléctrico sino una de las dicotomías fundamentales de toda la ingeniería de sistemas. I2C multiplexa por nombre: un solo par de hilos transporta a todos, y quién habla se decide con una dirección que viaja en banda, dentro del propio flujo de datos. SPI multiplexa por cable: cada dispositivo tiene su línea de selección, y quién habla se decide fuera de banda, activando un pin físico. Esa misma elección —¿distingo a mis interlocutores por una etiqueta lógica que viaja con los datos, o por el canal físico por el que llegan?— reaparece en cada capa del ordenador: es la diferencia entre un puerto TCP y una tarjeta de red distinta, entre un número de proceso y una CPU dedicada, entre una VLAN y un cable separado, entre un descriptor de fichero y un disco físico. Multiplexar por nombre escala en número —una dirección de 7 bits admite ciento y pico nodos con dos hilos— a costa de gastar ancho de banda en las etiquetas y de arbitrar el acceso compartido. Seleccionar por cable escala en velocidad —el canal es tuyo, sin etiquetas ni arbitraje— a costa de gastar un recurso físico por cada participante. No hay bus superior; hay dos respuestas a la pregunta de cómo compartir un medio, y cada una domina donde su moneda de canje es la barata. Cuando internalizas que I2C y SPI son esa dualidad hecha silicio, dejas de memorizar cuál es más rápido y empiezas a leer cualquier sistema nuevo preguntando lo único que importa: ¿este diseño distingue por nombre o por cable, y qué recurso está eligiendo pagar?
- Ejecuta
i2cdetect -lyls /sys/bus/spi/devices/y enumera cuántos buses de cada tipo expone tu sistema. - Para un dispositivo I2C que encuentres en
/sys/bus/i2c/devices/, extrae su dirección del nombrebus-XXXXy explica por qué ese número cae entre0x08y0x77. - Argumenta por qué un fabricante pondría un acelerómetro de baja tasa en I2C pero la flash de arranque en SPI.
- Un bus I2C con 112 dispositivos frente a un bus SPI con 112 periféricos: compara cuántos pines gasta cada topología y dónde está el cuello de botella de cada una.