Hola, tuve que implementar una comunicacion I2C entre una Raspberry Pi 3 y un dsPIC. Luego de buscar bastante lo he logrado, aca dejo un resumen:
Se definen 5 estados para la comunicación I2C, pero para la comunicación con la raspberry solo se usan los primeros 3.
La raspberry actuara como maestro y el dsPIC como esclavo a través de la interrupción del I2C como slave.
Del lado de la raspberry (yo utilizo QT que usa C++) para iniciar la comunicación I2C:
#include "wiringPi.h"
#include "wiringPiI2C.h"
.
.
.
wiringPiSetup();
Int fd=wiringPiI2CSetup (0x20);
0x20 es la dirección que le asigno al dsPIC.
Escritura:
Cuando se desea escribir un comando desde la raspberry se usa la función:
int wiringPiI2CWriteReg8 (int fd, int reg, int data);
reg puede ser el parámetro que deseo escribir (Ej una temperatura de seteo) y data es el valor.
Del lado del dsPIC entrara primero en el estado1 y leera la dirección, luego entrara en el estado2 y leera reg y luego volverá a entrar en el estado2 y leera data.
Lectura:
Cuando se desea leer un valor desde el dsPIC a la raspberry se usa la función:
int wiringPiI2CReadReg8 (int fd, int reg);
reg puede ser el parámetro que deseo leer y el retorno de la función el valor leido.
Codigo dsPIC
void I2C_Init(void)
{
unsigned int config1 = 0;
unsigned int config2 = 0;
config1 = (I2C1_ON & I2C1_7BIT_ADD & I2C1_CLK_REL & I2C1_STR_EN & I2C1_GCALL_DIS & I2C1_IPMI_DIS);
config2 = 0; //La frecuancia la impone el maestro
ConfigIntI2C1(SI2C1_INT_ON & SI2C1_INT_PRI_7 & MI2C1_INT_OFF);
OpenI2C1(config1,config2);
I2C1ADD = 0x0020;
}
void __attribute__ ((interrupt, no_auto_psv)) _SI2C1Interrupt(void)
{
static unsigned char state=0xFF;
static unsigned char addr=0;
static unsigned char reg=0;
static unsigned char read=0;
static unsigned char write;
static unsigned char aux;
//wiringPiI2CWriteReg8 state1(addr) "read" -> stete2(reg) "read" -> stete2(data) "read")
//wiringPiI2CReadReg8 state1(addr) "read" -> stete2(reg) "read" -> stete3(data) "write")
//State 1: I2C write operation, last byte was an address byte.
//I2CSTAT bits: S = 1, D_A = 0, R_W = 0, BF = 1
if(I2C1STATbits.S && !I2C1STATbits.D_A && !I2C1STATbits.R_W && I2C1STATbits.RBF )
{
addr = SlaveReadI2C1();
I2C1CONbits.STREN = 0;
state=0;
}
//State 2: I2C write operation, last byte was a data byte.
//I2CSTAT bits: S = 1, D_A = 1, R_W = 0, BF = 1
else if(I2C1STATbits.S && I2C1STATbits.D_A && !I2C1STATbits.R_W && I2C1STATbits.RBF )
{
aux = SlaveReadI2C1();
if(state==0)
{
reg=aux;
state=1;
}
else if(state==1)
{
read=aux;
state=0xFF;
}
I2C1CONbits.STREN = 0;
}
//State 3: I2C read operation, last byte was an address byte.
//I2CSTAT bits: S = 1, D_A = 0, R_W = 1, BF = 0
else if(I2C1STATbits.S && !I2C1STATbits.D_A && I2C1STATbits.R_W && !I2C1STATbits.TBF )
{
while(I2C1STATbits.TBF);
do
{
I2C1STATbits.IWCOL = 0;
if(state==1)
{
write=GetDato(reg);
SlaveWriteI2C1(write);
state=0xFF;
}
}
while(I2C1STATbits.IWCOL);
I2C1CONbits.SCLREL = 1;
}
//State 4: I2C read operation, last byte was a data byte.
//I2CSTAT bits: S = 1, D_A = 1, R_W = 1, BF = 0
else if(I2C1STATbits.S && I2C1STATbits.D_A && I2C1STATbits.R_W && !I2C1STATbits.TBF )
{
while(I2C1STATbits.TBF);
do
{
I2C1STATbits.IWCOL = 0;
SlaveWriteI2C1(0x00/*data*/);
}while(I2C1STATbits.IWCOL);
I2C1CONbits.SCLREL = 1;
}
//State 5: Slave I2C logic reset by NACK from master.
//I2CSTAT bits: S = 1, D_A = 1, R_W = 0, BF = 0
else if(I2C1STATbits.S && I2C1STATbits.D_A && !I2C1STATbits.R_W && !I2C1STATbits.RBF )
{
I2C1CONbits.SCLREL = 1;
}
//Check for I2C Buffer overun state
else if (I2C1STATbits.RBF || I2C1STATbits.I2COV)
{
I2C1STATbits.I2COV = 0;
aux = SlaveReadI2C1();
I2C1CONbits.SCLREL = 1;
}
else;
IFS1bits.SI2C1IF=0;
}