En este tutorial, aprenderás todo sobre el protocolo de comunicación I2C, por qué querrías usarlo y cómo se implementa.

El protocolo I2C (Inter-Integrated Circuit) es un protocolo destinado a permitir que varios circuitos integrados digitales (“chips”) “periféricos” se comuniquen con uno o más chips “controladores”. Al igual que la Interfaz Periférica Serial (SPI), sólo está pensada para comunicaciones de corta distancia dentro de un único dispositivo. Al igual que las Interfaces Seriales Asíncronas (como RS-232 o UARTs), sólo requiere dos cables de señal para intercambiar información.
¿Por qué usar I2C?
Para saber por qué uno podría querer comunicarse a través de I2C, primero debes compararlo con las otras opciones disponibles para ver en qué se diferencia.
¿Qué hay de malo con los puertos seriales UART?

Dado que los puertos serie son asíncronos (no se transmiten datos de reloj), los dispositivos que los utilizan deben acordar de antemano una velocidad de transmisión de datos. Los dos dispositivos también deben tener relojes que se acerquen a la misma velocidad, y recordemos que diferencias excesivas entre las velocidades de reloj en ambos extremos causarán datos eróneos.
Los puertos serie asíncronos generan una sobrecarga de hardware en la UART en cualquiera de los extremos, lo cual es relativamente complejo y difícil de implementar con precisión en el software. Al menos un bit de inicio y otro de parada forman parte de cada trama de datos, lo que significa que se necesitan 10 bits de tiempo de transmisión por cada 8 bits de datos enviados, lo que afecta negativamente la velocidad de transmisión de datos.
Otro fallo fundamental de los puertos serie asíncronos es que son inherentemente adecuados para las comunicaciones entre dos, y sólo dos, dispositivos. Aunque es posible conectar varios dispositivos a un único puerto serie, la contención del bus (cuando dos dispositivos intentan utilizar la misma línea al mismo tiempo) es siempre un problema y debe ser tratado con cuidado para evitar daños en los dispositivos en cuestión, esto se hace normalmente usando de hardware externo.
Por último, la velocidad de transmisión de los datos es un problema. Aunque no existe un límite teórico para las comunicaciones seriales asíncronas, la mayoría de los dispositivos UART sólo soportan un cierto conjunto de velocidades de transmisión fijas, y la más alta de ellas suele ser de unos 230400 bits por segundo.
¿Qué hay de malo en SPI?

El inconveniente más evidente de SPI es el número de pines necesarios. La conexión de un solo controlador a un solo periférico con un bus SPI requiere cuatro líneas; cada dispositivo periférico adicional requiere un pin de E/S de selección de chip adicional en el controlador. La rápida proliferación de pines de conexion hace que no sea deseable en situaciones en las que hay que conectar muchos dispositivos a un controlador. Además, el gran número de conexiones para cada dispositivo puede dificultar el enrutamiento de las señales en situaciones de diseño de un PCB con dimensiones ajustadas.
SPI sólo permite un controlador en el bus, pero admite un número arbitrario de periféricos (sujeto únicamente a la capacidad de accionamiento de los dispositivos conectados al bus y al número de pines de selección de chip disponibles).
SPI es bueno para conexiones full-duplex (envío y recepción simultánea de datos) de alta velocidad, soportando velocidades de reloj de hasta 10MHz (por lo tanto, 10 millones de bits por segundo) para algunos dispositivos, y la velocidad se escala muy bien. El hardware en ambos extremos suele ser un registro de desplazamiento muy sencillo, lo que permite una fácil implementación en el software.
I2C es lo mejor de los dos mundos.

I2C requiere sólo dos hilos, como el serial asíncrono, pero esos dos hilos pueden soportar hasta 1008 dispositivos periféricos. Además, a diferencia de SPI, I2C puede soportar un sistema multicontrolador, permitiendo que más de un controlador se comunique con todos los dispositivos periféricos del bus (aunque los dispositivos controladores no pueden hablar entre sí a través del bus y deben turnarse para utilizar las líneas del bus).
La velocidad de transmisión de datos está entre la serie asíncrona y la SPI; la mayoría de los dispositivos I2C pueden comunicarse a 100kHz o 400kHz. El I2C tiene una cierta sobrecarga; por cada 8 bits de datos que se envían, hay que transmitir un bit extra de metadatos (el bit “ACK/NACK”, del que hablaremos más adelante).
El hardware necesario para implementar I2C es más complejo que SPI, pero menos que el serial asíncrono. Se puede implementar de forma bastante trivial en software.
Nota: Es posible que esté familiarizado con los términos “maestro” y “esclavo” para representar la relación entre dispositivos en un bus I2C. Estos términos se consideran obsoletos y ahora se sustituyen por los términos “controlador” y “periférico”, respectivamente.
Nombre Obsoleto | Nombre Sustituto |
Master | Controller |
Slave | Peripheral |
La convención de nomenclatura puede variar según el fabricante, el lenguaje de programación, las empresas o las organizaciones (por ejemplo, principal/secundario, iniciador-respuesta, fuente/réplica, etc.). Para más información puedes consultar Wikipedia: Terminology Concerns, OSHWA: A Resolution to Redefine SPI Signal Names
Breve historia de I2C
I2C fue desarrollado originalmente en 1982 por Philips para varios chips de la marca. La especificación original sólo permitía comunicaciones a 100kHz, y proveía únicamente direcciones de 7 bits, limitando el número de dispositivos en el bus a 112 (hay varias direcciones reservadas, que nunca se utilizarán para direcciones I2C válidas). En 1992 se publicó la primera especificación pública, que añadía un modo rápido de 400kHz, así como un espacio de direcciones ampliado de 10 bits. La mayoría de las veces (por ejemplo, en el dispositivo ATMega328 de muchas placas compatibles con Arduino), el soporte del dispositivo para I2C termina en este punto. Hay tres modos adicionales especificados:
- Modo rápido plus, a 1MHz
- Modo de alta velocidad, a 3,4MHz
- Modo ultrarrápido, a 5MHz
Además del I2C, Intel introdujo una variante en 1995 llamada “System Management Bus” (SMBus). SMBus es un formato más controlado, destinado a maximizar la previsibilidad de las comunicaciones entre los circuitos integrados de apoyo en las placas base de los PC. La diferencia más significativa de SMBus es que limita las velocidades de 10kHz a 100kHz, mientras que I2C puede soportar dispositivos de 0kHz a 5MHz. SMBus incluye un modo de tiempo de espera del reloj que hace que las operaciones de baja velocidad sean ilegales, aunque muchos dispositivos SMBus lo soportan de todos modos para maximizar la interoperabilidad con los sistemas I2C integrados.
I2C a nivel de hardware
Señales
Cada bus I2C consta de dos señales: SDA y SCL. SDA (Serial Data) es la señal de datos y SCL (Serial Clock) es la señal de reloj. La señal de reloj siempre es generada por el controlador del bus actual; algunos dispositivos periféricos pueden forzar el reloj a la baja en algunos momentos para retrasar el envío de más datos por parte del controlador (o para requerir más tiempo para preparar los datos antes de que el controlador intente enviarlos). Esto se llama “clock stretchingj” y se describe en la página del protocolo.
A diferencia de las conexiones UART o SPI, los controladores del bus I2C son de “drenaje abierto“, lo que significa que pueden tirar la línea de señal correspondiente a bajo, pero no pueden llevarla a alto. Por lo tanto, no puede haber contención de bus producto de que un dispositivo está tratando de conducir la línea a alto mientras que otro trata de tirarla a bajo, eliminando el potencial de daño o la disipación de energía excesiva en el sistema. Cada línea de señal tiene una resistencia de pull-up, para restaurar la señal a alto cuando ningún dispositivo la llevando a bajo.

La selección de la resistencia varía según los dispositivos del bus, pero una buena regla general es empezar con una resistencia de 4,7kΩ y ajustarla hacia abajo si es necesario. I2C es un protocolo bastante robusto, y puede ser utilizado con tramos cortos de cable (2-3m). Para tramos largos, o sistemas con muchos dispositivos, es mejor utilizar resistencias más pequeñas.

La mayoría de los dispositivos I2C disponibles en el mercado suelen incluir resistencias pull-up para los pines SCL y SDA. Si tienes muchos dispositivos I2C en el mismo bus, puede que tengas que ajustar el valor equivalente para las resistencias pull-up desconectando las resistencias pull-up en algunos de los dispositivos. Dependiendo de lo que estés conectado al bus y del diseño, puedes incluir unos 7 dispositivos I2C en el mismo bus.
Si tu diseño requiere tramos de cable más largos, puede utilizar un CI dedicado para extender la señal, como el PCA9615.

Niveles lógicos de las señales
Dado que los dispositivos en el bus no conducen realmente señales HIGH, I2C permite cierta flexibilidad en la conexión de dispositivos con diferentes voltajes de E/S. En general, en un sistema en el que un dispositivo está a un voltaje más alto que otro, puede ser posible conectar los dos dispositivos a través de I2C sin ningún circuito de cambio de nivel entre ellos. El truco consiste en conectar las resistencias de pull-up al menor de los dos voltajes. Esto sólo funciona en algunos casos, cuando el menor de los dos voltajes del sistema excede el voltaje de entrada de alto nivel del sistema de mayor voltaje – por ejemplo, un Arduino de 5V y un acelerómetro de 3.3V. Dependiendo del diseño del Arduino o del dispositivo I2C, se recomienda utilizar un convertidor de nivel lógico para ser consistente y evitar dañar cualquier dispositivo en el bus.
Si la diferencia de voltaje entre los dos sistemas es demasiado grande (por ejemplo, 5V y 2,5V), puedes usar una simple placa de cambio de nivel I2C – por ejemplo, el PCA9306 Level Translator Breakout. También hay convertidores de nivel lógico bidireccionales que se pueden utilizar.
Protocolo
La comunicación vía I2C es más compleja que con una solución UART o SPI. La señalización debe ajustarse a un determinado protocolo para que los dispositivos del bus la reconozcan como una comunicación I2C válida. Afortunadamente, la mayoría de los dispositivos se encargan de todos los detalles por ti, permitiéndote concentrarte en los datos que deseas intercambiar.
Conceptos básicos
Los mensajes se dividen en dos tipos de tramas: una trama de direcciones, en la que el controlador indica el periférico al que se envía el mensaje, y una o varias tramas de datos, que son mensajes de datos de 8 bits que pasan del controlador al periférico o viceversa. Los datos se colocan en la línea SDA después de que SCL pase a bajo, y se muestrean después de que la línea SCL pase a alto. El tiempo entre el flanco de reloj y la lectura/escritura de datos está definido por los dispositivos en el bus y variará de un chip a otro.

Condición de inicio
Para iniciar la trama de direcciones, el dispositivo controlador deja SCL alto y lleva SDA abajo. Esto pone a todos los dispositivos periféricos en aviso de que una transmisión está a punto de comenzar. Si dos controladores desean tomar la propiedad del bus a la vez, el dispositivo que primero ponga SDA en bajo gana la carrera y obtiene el control del bus. Es posible emitir arranques repetidos, iniciando una nueva secuencia de comunicación sin ceder el control del bus a otro(s) controlador(es); hablaremos de ello más adelante.
Marco de dirección
La trama de dirección es siempre la primera en cualquier secuencia de comunicación nueva. Para una dirección de 7 bits, la dirección se envía primero con el bit más significativo (MSB), seguido de un bit R/W que indica si se trata de una operación de lectura (1) o de escritura (0).
El 9º bit de la trama es el bit NACK/ACK. Este es el caso de todas las tramas (de datos o de direcciones). Una vez enviados los primeros 8 bits de la trama, el dispositivo receptor recibe el control sobre SDA. Si el dispositivo receptor no baja la línea SDA antes del noveno pulso de reloj, se puede deducir que el dispositivo receptor no ha recibido los datos o no ha sabido analizar el mensaje. En ese caso, el intercambio se detiene, y es el controlador del sistema quien debe decidir cómo proceder.
Tramas de datos
Una vez enviada la trama de direcciones, se pueden empezar a transmitir los datos. El controlador simplemente continuará generando pulsos de reloj a un intervalo regular, y los datos serán colocados en SDA por el controlador o el periférico, dependiendo de si el bit R/W indicó una operación de lectura o escritura. El número de tramas de datos es arbitrario, y la mayoría de los dispositivos periféricos autoincrementarán el registro interno, lo que significa que las lecturas o escrituras subsiguientes provendrán del siguiente registro en línea.
Condición de parada
Una vez que se han enviado todas las tramas de datos, el controlador generará una condición de parada. Las condiciones de parada se definen por una transición 0->1 (bajo a alto) en SDA después de una transición 0->1 en SCL, con SCL permaneciendo alto. Durante la operación normal de escritura de datos, el valor en SDA no debe cambiar cuando SCL está alto, para evitar falsas condiciones de parada.
Temas del Protocolo Avanzado
Direcciones de 10 bits
En un sistema de direccionamiento de 10 bits, se requieren dos tramas para transmitir la dirección del periférico. La primera trama consistirá en el código b11110xyz
, donde ‘x’ es el MSB de la dirección del periférico, y es el bit 8 de la dirección del periférico, y z es el bit de lectura/escritura como se ha descrito anteriormente. El bit ACK de la primera trama será afirmado por todos los periféricos que coincidan con los dos primeros bits de la dirección.

Al igual que con una transferencia normal de 7 bits, inmediatamente comienza otra transferencia que contiene los bits 7:0 de la dirección. En este punto, el periférico direccionado debe responder con un bit ACK. Si no lo hace, el modo de fallo es el mismo que en un sistema de 7 bits.
Ten en cuenta que los dispositivos con direcciones de 10 bits pueden coexistir con los de 7 bits, ya que la parte inicial “11110
” de la dirección no forma parte de ninguna dirección válida de 7 bits.
Condiciones de arranque repetido
A veces, es importante que un controlador pueda intercambiar varios mensajes de una sola vez, sin permitir que otros controladores en el bus interfieran. Por esta razón, se ha definido la condición de arranque repetido.

Para realizar un arranque repetido, se permite que SDA pase a alto mientras SCL está bajo, se permite que SCL pase a alto, y entonces SDA se pone bajo de nuevo mientras SCL está alto. Debido a que no hubo una condición de parada en el bus, la comunicación anterior no fue realmente completada y el controlador actual mantiene el control del bus.
En este punto, el siguiente mensaje puede comenzar la transmisión. La sintaxis de este nuevo mensaje es la misma que la de cualquier otro mensaje: una trama de dirección seguida de tramas de datos. Se permite cualquier número de inicios repetidos, y el controlador mantendrá el control del bus hasta que emita una condición de parada.
Estiramiento del reloj
A veces, la velocidad de datos del controlador superará la capacidad del periférico para proporcionar esos datos. Esto puede deberse a que los datos aún no están listos (por ejemplo, el periférico aún no ha completado una conversión analógico-digital) o a que una operación anterior aún no ha finalizado (por ejemplo, una EEPROM que aún no ha terminado de escribir en la memoria no volátil y necesita terminar eso antes de poder atender otras peticiones).

En este caso, algunos dispositivos periféricos ejecutarán lo que se conoce como “estiramiento del reloj”. Nominalmente, toda la sincronización es conducida por el controlador – los periféricos simplemente ponen datos en el bus o toman datos del bus en respuesta a los pulsos de reloj del controlador. En cualquier punto del proceso de transferencia de datos, un periférico direccionado puede mantener la línea SCL baja después de que el controlador la libere. El controlador debe abstenerse de dar más pulsos de reloj o de transferir datos hasta que el periférico libere la línea SCL.
Sfuptownmaker. I2C. Sparkfun.