INTRODUCCION
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. Es un bus muy usado en la
industria, principalmente para comunicar microcontroladores y sus periféricos en sistemas integrados (Embedded Systems) y
generalizando más para comunicar circuitos integrados entre sí que normalmente
residen en un mismo circuito impreso.
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: datos
·
SCL: reloj
·
GND: tierra
Las
dos primeras líneas son drenador abierto,
por lo que necesitan resistencias de pull-up.
Los
dispositivos conectados al bus I²C tienen una dirección única para cada
uno. También pueden ser maestros o esclavos.
El dispositivo maestro inicia la transferencia de datos y
además genera la señal de reloj, pero no es necesario que el maestro sea siempre el mismo dispositivo, esta
característica se la pueden ir pasando los dispositivos que tengan esa capacidad.
Esta característica hace que al bus I²C se le denomine bus multimaestro.
Las
transacciones en el bus I2C tienen este formato:
|
start | A7 A6 A5 A4 A3 A2 A1 R/W | ACK | ... DATA ... | ACK | stop | idle |
·
El bus esta libre cuando SDA y SCL están en
estado lógico alto.
·
En estado bus libre, cualquier dispositivo
puede ocupar el bus I²C como maestro.
·
El maestro comienza la comunicación enviando
un patrón llamado "start condition". Esto alerta a los dispositivos
esclavos, poniéndolos a la espera de una transacción.
·
El maestro se dirige al dispositivo con el
que quiere hablar, enviando un byte que contiene los siete bits (A7-A1) que
componen la dirección del dispositivo esclavo con el que se quiere comunicar, y
el octavo bit (A0) de menor peso se corresponde con la operación deseada (L/E),
lectura=1 (recibir del esclavo) y escritura=0 (enviar al esclavo).
·
La dirección enviada es comparada por cada
esclavo del bus con su propia dirección, si ambas coinciden, el esclavo se
considera direccionado como esclavo-transmisor o esclavo-receptor dependiendo
del bit R/W.
·
El esclavo responde enviando un bit de ACK
que le indica al dispositivo maestro que el esclavo reconoce la solicitud y
está en condiciones de comunicarse.
·
Seguidamente comienza el intercambio de
información entre los dispositivos.
·
El maestro envía la dirección del registro
interno del dispositivo que se desea leer o escribir.
·
El esclavo responde con otro bit de ACK
·
Ahora el maestro puede empezar a leer o escribir
bytes de datos. Todos los bytes de datos deben constar de 8 bits, el número
máximo de bytes que pueden ser enviados en una transmisión no está restringido,
siendo el esclavo quien fija esta cantidad de acuerdo a sus características.
·
Cada byte leído/escrito por el maestro debe
ser obligatoriamente reconocido por un bit de ACK por el dispositivo
maestro/esclavo.
·
Se repiten los 2 pasos anteriores hasta
finalizar la comunicación entre maestro y esclavo.
·
Aun cuando el maestro siempre controla el
estado de la línea del reloj, un esclavo de baja velocidad o que deba detener
la transferencia de datos mientras efectúa otra función, puede forzar la línea
SCL a nivel bajo. Esto hace que el maestro entre en un estado de espera,
durante el cual, no transmite información esperando a que el esclavo esté listo
para continuar la transferencia en el punto donde había sido detenida.
·
Cuando la comunicación finaliza, el maestro
transmite una "stop condition" para dejar libre el bus.
·
Después de la "stop condition", es
obligatorio para el bus estar idle durante unos microsegundos.
- Ejemplo de frame de datos:
- OBJETIVO.
Para
iniciar la comunicación I2C con la tarjeta Zedboard debemos tener previamente
un esclavo y un maestro que valide el sistema de comunicación. Para ello se
propone un esquema de microcontroladores como el de la siguiente imagen:
El esquemático
está compuesto por dos microcontroladores PIC18F2550 configurados con oscilador
interno a 8 Mhz, velocidad de 100 Khz en I2C y un led de estatus en el PIN_B7.
La
dirección del esclavo es 0x38.
En
la siguiente figura se muestran armados en un protoboard:
La idea es transferir 64 bytes del maestro al
esclavo y este a su vez los retransmite nuevamente al maestro.
Maestro [0, 1, 2, … 63] à Esclavo [0, 1, 2, … 63] à Maestro [0, 1, 2, … 63]
En la siguiente figura se muestra las transmisiones
recibidas entre ambos:
- Los códigos hexadecimales los puedes bajar de aquí:
ESCLAVO:
MAESTRO:
- Ahora desarrollaremos la etapa del I2C Maestro con la Zedboard. Iniciando con la construcción de bloques en vivado de la siguiente manera:
- La configuración en Zynq del I2C se muestra a continuación:
- El código en SDK de eclipse es:
/*****************************
Include Files **********************************/
#include "xparameters.h"
#include "xiicps.h"
#include "xil_printf.h"
#include "xgpio.h"
/**************************
Constant Definitions ******************************/
/*
* The following constants map to the XPAR
parameters created in the
* xparameters.h file. They are defined here
such that a user can easily
* change all the needed parameters in one
place.
*/
#define IIC_DEVICE_ID XPAR_XIICPS_0_DEVICE_ID
#define
GPIO_EXAMPLE_DEVICE_ID
XPAR_AXI_GPIO_0_DEVICE_ID
#define LED_CHANNEL 1
/*
* The slave address to send to and receive
from.
*/
#define IIC_SLAVE_ADDR 0x38
#define IIC_SCLK_RATE 100000
/*
* The following constant controls the length
of the buffers to be sent
* and received with the IIC.
*/
#define TEST_BUFFER_SIZE 64
/****************************
Type Definitions ********************************/
/**************************
Function Prototypes *******************************/
int IicPsMasterPolledExample(u16 DeviceId);
/**************************
Variable Definitions ******************************/
XIicPs
Iic; /**< Instance of the IIC Device */
XGpio
Gpio; // The Instance of the GPIO Driver
/*
* The following buffers are used in this
example to send and receive data
* with the IIC.
*/
u8
SendBuffer[TEST_BUFFER_SIZE]; /**< Buffer for Transmitting Data */
u8
RecvBuffer[TEST_BUFFER_SIZE]; /**< Buffer for Receiving Data */
/******************************************************************************/
/**
*
* Main
function to call the polled master example.
*
* @param None.
*
* @return XST_SUCCESS if successful, XST_FAILURE if
unsuccessful.
*
* @note None.
*
*******************************************************************************/
int main(void)
{
int
Status;
// Initialize the
GPIO driver
Status = XGpio_Initialize(&Gpio,
GPIO_EXAMPLE_DEVICE_ID);
if
(Status != XST_SUCCESS) {
return XST_FAILURE;
}
// Clear the LEDs
XGpio_DiscreteWrite(&Gpio,
LED_CHANNEL, 0);
xil_printf(" Microcarsil,
2014\n");
xil_printf("IIC Master Polled Example Test \r\n");
/*
* Run the Iic polled example in master
mode, specify the Device
* ID that is specified in xparameters.h.
*/
Status =
IicPsMasterPolledExample(IIC_DEVICE_ID);
if
(Status != XST_SUCCESS) {
xil_printf("IIC Master Polled Example Test Failed\r\n");
return XST_FAILURE;
}
xil_printf("Successfully ran IIC Master Polled Example Test\r\n");
return
XST_SUCCESS;
}
/*****************************************************************************/
/**
*
* This
function sends data and expects to receive data from slave as modular
* of 64.
*
* This
function uses interrupt-driven mode of the device.
*
* @param DeviceId is the Device ID of the IicPs
Device and is the
* XPAR_<IICPS_instance>_DEVICE_ID
value from xparameters.h
*
* @return XST_SUCCESS if successful, otherwise
XST_FAILURE.
*
* @note None.
*
*******************************************************************************/
int IicPsMasterPolledExample(u16 DeviceId)
{
int
Status;
XIicPs_Config
*Config;
int
Index;
unsigned
char i=1;
/*
* Initialize the IIC driver so that it's ready
to use
* Look up the configuration in the config
table,
* then initialize it.
*/
Config =
XIicPs_LookupConfig(DeviceId);
if
(NULL == Config) {
return XST_FAILURE;
}
Status =
XIicPs_CfgInitialize(&Iic, Config, Config->BaseAddress);
if
(Status != XST_SUCCESS) {
return XST_FAILURE;
}
/*
* Perform a self-test to ensure that the
hardware was built correctly.
*/
Status = XIicPs_SelfTest(&Iic);
if
(Status != XST_SUCCESS) {
return XST_FAILURE;
}
/*
* Set the IIC serial clock rate.
*/
XIicPs_SetSClk(&Iic,
IIC_SCLK_RATE);
/*
* Initialize the send buffer bytes with a
pattern to send and the
* the receive buffer bytes to zero to allow
the receive data to be
* verified.
*/
for
(Index = 0; Index < TEST_BUFFER_SIZE; Index++)
{
SendBuffer[Index] =
Index;
RecvBuffer[Index] = 0;
}
while(1)
{
/*
* Send the buffer using the IIC and ignore the
number of bytes sent
* as the return value since we are using it in
interrupt mode.
*/
XGpio_DiscreteWrite(&Gpio, LED_CHANNEL,
i++);
/*
* Wait until
bus is idle to start another transfer.
*/
while (XIicPs_BusIsBusy(&Iic)) { /* NOP */ }
Status = XIicPs_MasterSendPolled(&Iic,
SendBuffer, TEST_BUFFER_SIZE, IIC_SLAVE_ADDR);
if (Status != XST_SUCCESS)
{
xil_printf(" FALLA WRITE!\n");
}
else
{
xil_printf(" OK!\n");
}
usleep(10000);
Status =
XIicPs_MasterRecvPolled(&Iic, RecvBuffer,
TEST_BUFFER_SIZE, IIC_SLAVE_ADDR );
if (Status != XST_SUCCESS)
{
xil_printf(" FALLA READ!\n");
}
else
{
for(Index = 0; Index < TEST_BUFFER_SIZE;
Index ++)
{
xil_printf(" MASTER[%d] = %d\n",Index,RecvBuffer[Index]);
}
}
usleep(2000000);
}
return
XST_SUCCESS;
}
- Sustituimos el microcontrolador maestro pic18f2550 por la zedboard. Y verificamos la respuesta por medio de debug.
- Funcionando correctamente en debug SDK:
Hola, que buen contenido, ando en un proyecto similar para ingeniería electrónica, me preguntaba si aún tienes los códigos ya que los links están caídos ( ESCLAVO: https://mega.co.nz/#!0ptmDToT!W5s7HUwqK4eiqv8_0RzpiRxfdP1fWzDxiTboM9ItA9E
ResponderBorrarMAESTRO:
https://mega.co.nz/#!M0Ug2ahD!Z8VNIItNXI1AhZfonenHZ06DqamTvY5tp8gxfXsp2jA) Muchas gracias, saludos!
Hola gracias por revisar el blog. Ya actualice los links caídos. Saludos
ResponderBorrar