Protocolo I2C (1ra Parte)

Standard

Hoy trataremos sobre un protocolo ampliamente difundido y utilizado en el mundo de los micros y su comunicación con los periféricos, o esclavos, y estamos hablando del protocolo I2C:

I²C es un bus de comunicaciones en serie. Su nombre viene de Inter-Integrated Circuit (Inter-Circuitos Integrados). La versión 1.0 data del año 1992 y la versión 2.1 del año 2000, su diseñador es Philips. La velocidad es de 100 kbit/s en el modo estándar, aunque también permite velocidades de 3.4 Mbit/s.

 

¿Qué es?

La principal característica de I²C es que utiliza dos líneas para transmitir la información: una para los datos y otra para la señal de reloj. También es necesaria una tercera línea, pero esta sólo es la referencia (masa). Como suelen comunicarse circuitos en una misma placa que comparten una misma masa esta tercera línea no suele ser necesaria.

Las líneas se llaman:

  • SDA(Serial Data): corresponde a la línea de datos, es una línea semibidireccional y se trata de una señal en colector abierto. Es gobernada por un emisor, que puede ser un maestro o esclavo.
  • SCL: SCL(Serial Clock): corresponde a la línea de sincronización o de reloj. Se trata también de una señal a colector abierto. Esta señal es gobernada por el maestro y corresponde a una de sus salidas, en cambio en el esclavo corresponde a la entrada y solo puede retenerla  Una de sus misiones es establecer la sincronización entre Maestro-Esclavo.
  • GND: tierra de referencia

Funcionamiento

En el protocolo I2C cada dispositivo es reconocido por una dirección única de 7bits + un bit de escritura/lectura el protocolo I2C normalmente puede soportar 128 dispositivos aunque también existe configuración de 10 bits. Los fabricantes de dispositivos suelen asignar más de una dirección I2C al dispositivo y  activada al energizar/ des-energizar algún pin especifico. Como precaución a dispositivos con direcciones parecidas.

Dirección de dispositivo: esta dirección normalmente, está compuesta por 7 bits más 1 de lectura/ escritura como se muestra en la imagen siguiente:

1

Modo de comunicación:

Condiciones de START y STOP: Antes de que se establezca un intercambio de datos entre el circuito Master y los Esclavos, el Master debe informar el comienzo de la comunicación

(condición de Start): la línea SDA cae a cero mientras SCL permanece en nivel alto. A partir de este momento comienza la transferencia de datos. Una vez finalizada la comunicación se debe informar de esta situación (condición de Stop). La línea SDA pasa a nivel alto mientras SCL permanece en estado alto.

Transferencia de datos: El Maestro genera la condición de Start. Cada palabra puesta en el bus SDA debe tener 8 bits, la primera palabra transferida contiene  la dirección del Esclavo seleccionado. Luego el Master lee el estado de la línea SDA, si vale 0 (impuesto por el esclavo), el proceso de transferencia continúa. Si vale 1, indica que el circuito direccionado no valida la comunicación, entonces, el Maestro genera un bit de stop para liberar el bus I2C. Este acuse de recibo se denomina ACK (acknowledge) y es una parte importante del protocolo I2C. Al final de la transmisión, el Maestro genera la condición de Stop y libera el bus I2C, las líneas SDA y SCL pasan a estado alto.
El Slave (esclavo) es el dispositivo direccionado. Las líneas SDA (serial Data) y SCL (serial Clock) son bidireccionales, conectadas al positivo de la alimentación a través de las resistencias de pull-up. Cuando el bus está libre, ambas líneas están en nivel alto. La transmisión bidireccional serie (8-bits) de datos puede realizarse a 100Kbits/s  en el modo standard o 400 Kbits/s en el modo rápido.

Bus libre: en este estado las líneas SDA y SCL se mantienen a 1, sin que se produzca ninguna transferencia.
2

Condición de inicio: en el momento que el maestro inicia una transmisión de datos se produce la condición de inicio. Se corresponde a un cambio de alta a baja en la línea SDA, mientras que SCL se mantiene alta. En este momento el Bus está ocupado.
3

Condición de cambio: Este estado se produce en el momento que estando la línea SCL en baja, la línea SDA puede cambiar de estados. En este instante es cuando se produce la transmisión de los bits por parte del emisor, ya sea maestro o esclavo.
4

Dato válido: Una vez que se ha iniciado la transacción de datos, se define que el dato ha sido válido en el momento que pasa a la fase alta SCl. Es decir en este estado se considera que el dato emitido ha sido válido.

Parada: La parada se produce cuando la línea SCL se encuentra en alta, y se produce un cambio de baja a alta en la línea SDA. En este estado se indica el fin de la transferencia. Posteriormente a este estado, se pasa al estado de bus libre de nuevo
5

Ejemplo de mensaje de escritura:
6

Ejemplo de mensaje de lectura:
7

Limitación de dispositivos: Ya que el Bus I2C tuvo mucho éxito, se fueron agotando las direcciones disponibles de bus I2c, y no se podían ofrecer nuevos circuitos I2c. Para ello se crearon direcciones que comenzaban por 1111, por ello ahora existen dos tipos de direcciones, las normales de 7 bits y las ampliadas de 10 bits. En el caso de 10 bits, el direccionamiento del esclavo está compuesto por la transferencia de dos caracteres, el primero comenzará por 11110XX(XX: los bits de mayor peso de la dirección de 10 bits), y el segundo carácter corresponde a los 8 bits inferiores de la dirección del esclavo.

Hasta este punto observamos y comprendemos más que es el conocido  I2C

Ahora comenzaremos con algo un poco más didáctico trabajaremos con un arduino  debido a que es la placa de prototipo más común en la actualidad, para comprender un poco mejor  el cómo  y para que se puede utilizar este protocolo.

Recomendaciones:

  1. Tener 2 arduino uno
  2. Puentes o cables para conectar

En primer lugar hay que tener en cuenta, que  gracias a la plataforma de arduino esta tan difundida no entrega casi todo a la mano  por eso tenemos la  biblioteca “wire.h” (para más información sobre ella: https://www.arduino.cc/en/reference/wire )  la cual está encargada de manejar todos los mensajes I2C por lo que nosotros solo tendremos que preocuparnos por 3 cosas principalmente:

  1. ID del dispositivo que enviaremos.
  2. Registro al que queremos acceder y si queremos leerlo o escribirlo (con write.wire/ read.wire nos ahorramos hacer otra cosa)
  3. Información que enviamos o recibimos recordar que estamos manejando mensajes de 8 bits.

Ejemplo de comunicación de 2 arduinos:

#include <Wire.h>    // Incluimos la librería de comunicación I2C

void setup()              // Secuencia de configuración, solo se ejecuta una vez

Wire.begin();            // Iniciamos la comunicación I2C,

Serial.begin(9600);       // Iniciamos la comunicación por el puerto serie los datos

void loop()              // Secuencia en bucle, se repite  indefinidamente

Wire.requestFrom(1, 12);  // Manda una petición al esclavo numero 1 de 12 bytes

while(Wire.available())  // Mientras tengamos datos en el buffer seguimos leyendo

char Datos = Wire.read(); // Leemos un byte y lo pasamos a una variable de tipo char

Serial.print(Datos);     // Lo mostramos en el puerto serie (esto es un bucle donde van llegando uno por uno cada carácter y se van imprimiendo por el serial)

<delay(1500);        // Esperamos 1,5 segundos para que sea posible ver las respuestas

Serial.println();  // Imprimimos una nueva linea, sino la respuestas van a ir pegadas


El programa que hay que cargar en el Esclavo (en este caso el Uno) es el siguiente:

#include <Wire.h>
void setup()

Wire.begin(0x01);                     // Nos añadimos al bus como esclavo, con la dirección 1

Wire.onRequest(requestEvent); // Registro de eventos

void loop()

delay(100);                    // retraso de 100 mili-segundos

void requestEvent()      // Función que se ejecuta cuando recibe una petición desde el maestro

Wire.write(“Hola maestro”);   // Responde a la petición del maestro de enviarle 12 bytes


El anterior fue un ejemplo básico del uso del I2C ahora explicare un poco más a detalle que acaba de pasar:

La primero que nos encontramos después de llamar la biblioteca es “Wire.begin();” este comando es encargado de habilitar la comunicación por I2C en nuestro arduino,  y de ser necesario se le puede asignar una dirección preferiblemente hexadecimal a nuestro arduino, lo cual  será necesario si pensamos trabajarlo como esclavo en algún momento, de lo contrario se puede dejar vacío, si nos damos cuenta en el programa del esclavo tenemos asignado el numero “0x01” dándole un ID de dispositivo  al arduino con el cual cualquiera que esté en la red podrá comunicarse con él .

El siguiente comando que nos encontramos es “Wire.requestFrom( ,  );” este comando simplemente es una petición del maestro al esclavo,  pero consiste de 2 valores, el primero es la dirección I2C o registro (cuando los utilicemos) del cual deseamos recibir la información, y el segundo es la cantidad de bytes que vamos a recibir o esperamos recibir.

Con el arreglo “while(Wire.available())” nos cercioramos  que tengamos datos en el buffer y los estaremos leyendo mientras tengamos datos en el.

Y por último en el código del maestro tendremos “Wire.read();“ este comando es el que nos permite leer lo que nos esté llegando por nuestro protocolo i2c de forma correcta

Un comando que tenemos muy útil es “Wire.onRequest();” con el cual nuestro arduino esclavo está a la espera del llamado de algún maestro para iniciar la comunicación

Con el comando “Wire.write();” nuestro esclavo en este caso comienza a enviar los bits que contiene el mensaje, aunque también en otros caso se puede utilizar del maestro a algún periférico para escribir un registro que se necesite.

Por el momento este tutorial lo dejaremos hasta la próxima oportunidad donde ya se trataran periféricos con registros y  algunas opciones más tanto en arduino como en el protocolo i2c en general.

Saludos y éxito.

Leave a Reply

Your email address will not be published. Required fields are marked *