Protocolo I2C entre PIC32mx y Arduino Uno

Estoy implementando una forma de transferir datos usando el protocolo I2C entre PIC32mx y Arduino Uno. Decidí establecer PIC como maestro y Arduino como esclavo . Pasé por todas las definiciones y configuraciones para el I2C en el PIC porque ya lo tengo funcionando perfectamente con un barómetro. Consideremos al Arduino como un esclavo más en este protocolo. Entonces, desde el lado maestro de PIC tengo el siguiente código

#define EEPROM_I2C_BUS              I2C1
#define i2d_address                 0x14
#define I2C_CLOCK_FREQ              5000


BOOL BarI2CTransmitOneByte( UINT8 data )
{
// Wait for the transmitter to be ready
while(G_RUNNING && !I2CTransmitterIsReady(EEPROM_I2C_BUS));

// Transmit the byte
if(I2CSendByte(EEPROM_I2C_BUS, data) == I2C_MASTER_BUS_COLLISION)
{
    DBPRINTF("Error: I2C Master Bus Collision\n");
    return FALSE;
}
// Wait for the transmission to finish
while(G_RUNNING && !I2CTransmissionHasCompleted(EEPROM_I2C_BUS));

return TRUE;
}

void BarI2CStopTransfer( void )
{
I2C_STATUS  status;

// Send the Stop signal
I2CStop(EEPROM_I2C_BUS);

// Wait for the signal to complete
do
{
    status = I2CGetStatus(EEPROM_I2C_BUS);

} while( G_RUNNING && !(status & I2C_STOP) );
}


BOOL BarI2CStartTransfer( BOOL restart )
{
I2C_STATUS  status;

//    // Send the Stop signal
// I2CStop(EEPROM_I2C_BUS);

// Send the Start (or Restart) signal
if(restart)
{
    I2CRepeatStart(EEPROM_I2C_BUS);
}
else
{
    // Wait for the bus to be idle, then start the transfer
    while( G_RUNNING && !I2CBusIsIdle(EEPROM_I2C_BUS) );

    if(I2CStart(EEPROM_I2C_BUS) != I2C_SUCCESS)
    {
        DBPRINTF("Error: Bus collision during transfer Start\n");
        return FALSE;
    }
}
// Wait for the signal to complete
do
{
    status = I2CGetStatus(EEPROM_I2C_BUS);

} while ( !(status & I2C_START) );

return TRUE;
} 


void main(){
UINT32              actualClock;
BOOL                Success2 = TRUE;

actualClock = I2CSetFrequency(EEPROM_I2C_BUS, GetPeripheralClock(), I2C_CLOCK_FREQ);
if ( abs(actualClock-I2C_CLOCK_FREQ) > I2C_CLOCK_FREQ/10 )
{
   //DBPRINTF("Error: I2C1 clock frequency (%u) error exceeds 10%%.\n", (unsigned)actualClock);
}
// Enable the I2C bus
I2CEnable(EEPROM_I2C_BUS, TRUE);


I2C_FORMAT_7_BIT_ADDRESS(SlaveAddress,  i2d_address, I2C_WRITE);
i2cData[0] = SlaveAddress.byte;
i2cData[1] = 0x03;         // EEPROM location to read (high address byte)
DataSz = 2;


if( !BarI2CStartTransfer(FALSE) )
{
    while(G_RUNNING && 1);
}

Index = 0;
while(Success2 & (Index < DataSz) )
{
    // Transmit a byte
    if (BarI2CTransmitOneByte(i2cData[Index]))
    {
        // Advance to the next byte
        Index++;
    }
    else
    {
        Success2 = FALSE;
    }

    // Verify that the byte was acknowledged
    if(!I2CByteWasAcknowledged(EEPROM_I2C_BUS))
    {
        DBPRINTF("Error: Sent byte was not acknowledged\n");
        Success2 = FALSE;
    }
}

BarI2CStopTransfer();

if(Success2)
{
    // Send a Repeated Started condition
    if( !BarI2CStartTransfer(FALSE) )
    {
        while(1);
    }

    // Transmit the address with the READ bit set
    I2C_FORMAT_7_BIT_ADDRESS(SlaveAddress,  i2d_address, I2C_READ);
    if (BarI2CTransmitOneByte(SlaveAddress.byte))
    {
        // Verify that the byte was acknowledged
        if(!I2CByteWasAcknowledged(EEPROM_I2C_BUS))
        {
            DBPRINTF("Error: Sent byte was not acknowledged\n");
            Success2 = FALSE;
        }
    }
    else
    {
        Success2 = FALSE;
    }
}
// Read the data from the desired address
if(Success2)
{
    if(I2CReceiverEnable(EEPROM_I2C_BUS, TRUE) == I2C_RECEIVE_OVERFLOW)
    {
        DBPRINTF("Error: I2C Receive Overflow\n");
        Success2 = FALSE;
    }
    else
    {
        while(!I2CReceivedDataIsAvailable(EEPROM_I2C_BUS));
        i2cbyte = I2CGetByte(EEPROM_I2C_BUS);
    }
}
BarI2CStopTransfer();
if(!Success2)
{
    while( G_RUNNING && 1);
}

Para el lado esclavo de Arduino , escribí el siguiente código:

void setup(void) 
{
Wire.begin(20);
Wire.onReceive(receiveEvent);
Wire.onRequest(requestEvent);
Serial.begin(9600); // start serial comm
}

void receiveEvent(int howMany){
int x = Wire.read();   
}

void requestEvent(){
Wire.write('x');
}

void loop(){
}

Entonces, desde el lado del PIC, estoy enviando el byte 0x03 que recibo en el método receiveEvent en el lado de Arduino. En este punto todo está funcionando bien. Después de eso, se llama a requestEvent y el carácter 'x' se envía al lado PIC. Ahora el lado PIC está bloqueando la DBPRINTF("Error: I2C Receive Overflow\n");oración, lo que significa que estoy tardando demasiado en recibir el byte 'x' del lado Arduino y la línea SDA tampoco se libera.

Tengo pull ups en mi protocolo I2C a 3.3V ( Master-PIC ) y trato de comunicarme usando A4(SDA)y A5(SCL)en el lado Slave-Arduino que está a 5V. Estoy siguiendo este Tutorial cuidadosamente y tratando de replicar la parte de "Lectura de un esclavo" pero sin éxito.

EDITAR: estoy siguiendo el procedimiento y estoy recibiendo el byte correctamente desde el lado de arduino, sin embargo, el código está bloqueado en el RFIDI2CStopTransfer();lado del PIC y no sé por qué. ¿Hay alguien que pueda ayudarme con este problema?

Tus fragmentos de código son demasiado incompletos en mi opinión. No ha mostrado ninguna de las funciones maestras como BarI2CTransmitOneByte() y BarI2CStartTransfer(). Además, no ha mostrado una captura de alcance o analizador lógico que muestre que el tráfico es el que espera. También parece que está utilizando la misma función para enviar inicio y reinicio (BarI2CStartTransfer): en PIC32 (al igual que PIC24), el inicio y el reinicio son bits separados en el registro I2CxCON (SEN y RSEN respectivamente). Agregue un poco más de carne a esta pregunta.
Ya actualicé mi publicación con las funciones que me pediste. Eche un vistazo, no estoy usando la misma función para iniciar y reiniciar la transferencia. Desafortunadamente no tengo un analizador lógico aquí @AdamLawrence
@scuba se deshace de Serial.print() en requestEvent. Tomará alrededor de 13 ms segundos imprimir esa cadena, demasiado tiempo. ¿Intentaste mi recomendación anterior?
@TisteAndii sí señor y sin resultados. Ya eliminé Serial.print() en requestEvent y tampoco hubo resultados. Estoy tratando de seguir esto ( robot-electronics.co.uk/i2c-tutorialtutorial ) y parece que mi código lo está haciendo perfectamente. no tengo mas ideas
Tu enlace está roto. Por recomendación, quise decir el código de muestra PIC32 cuyo enlace pastebin te envié en la sala de chat. También en su código actual, parece que está definiendo funciones dentro de main()
hubo un error en copiar y pegar robot-electronics.co.uk/i2c-tutorial . Como el código principal. lo estoy arreglando
Con el código que sugiere, no puedo ir más allá del método de transferencia de inicio. Lo comprobé con un punto de interrupción.
@scuba el error de desbordamiento del receptor ocurre porque se recibieron datos mientras había datos no leídos en el búfer rx. Intente llamar a GetByte antes de habilitar el receptor. También intente editar el código aquí: people.ece.cornell.edu/land/courses/ece4760/PIC32/PLIB_examples/… ; es más claro y ha sido probado dada su fuente.
Parece que Arduino está forzando la línea al valor lógico 1 y nunca baja al final en el último StopTransfer(). Creo que el problema está en el lado de Arduino, ¿no?
Seguí su discusión con Majenko. ¿Has probado mi código PIC32 con sus sugerencias sobre la dirección? ¿Alguna mejora en absoluto? ¿O se detiene en el mismo punto?
@TisteAndii está solucionado. Estaba usando el esclavo número 7 y parece que está reservado, así que cambié a 20 y ahora funciona perfectamente.
@buceo Genial. Es posible que desee publicar una respuesta aquí y en Arduino.SE.
@TisteAndii, ¿puedes mirar la edición que hice?
¿Eliminó Serial.print() en requestEvent? Actualice el código en su pregunta, si ha realizado algún cambio. ¿Comienza StopTransfer() o se atasca en el ciclo while anterior? ¿Y qué es exactamente G_RUNNING?
Ya actualicé el código. Eliminé Serial.print() y el problema está en el costado del PIC32. Está atascado en StopTransfer, dentro del bucle do{ }while.
Tal vez sea porque no estás haciendo NACK. Agregue I2CAcknowledgeByte(EEPROM_I2C_BUS, FALSE); while (!I2CAcknowledgeHasCompleted(EEPROM_I2C_BUS));después I2CGetByte()y vuelva a intentarlo. Si se atasca, ¿dónde se atasca esta vez?

Respuestas (1)

Parte del problema estaba relacionado con la dirección que utilicé para comunicarme con Arduino. Estaba usando 0x07 como dirección pero está reservado, así que cambié a 0x14 (20 en decimal). Sin embargo, he editado la publicación para obtener ayuda con este nuevo problema.