1
\$\begingroup\$

I am implementing a way to transfer data using I2C protocol between PIC32mx and Arduino Uno. I've decided to establish PIC as master and Arduino as slave. I passed by all the definitions and configs for the I2C in the PIC because I already have it working perfectly with a barometer. Let's consider the Arduino as one more slave in this protocol. So from the PIC master-side I have the following code

#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);
}

For the Arduino slave-side I wrote this following code:

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(){
}

So from the PIC side I am sending the byte 0x03 which I receive in the receiveEvent method in the Arduino side. At this point everything is working well. After that the requestEvent is called and the 'x' character is beeing sent to the PIC side. Now the PIC side is blocking in the DBPRINTF("Error: I2C Receive Overflow\n"); sentence which means I am taking too long to receive the 'x' byte from the Arduino side and the SDA line is never released as well.

I have pull ups in my I2C protocol at 3.3V (Master-PIC) and I trying to communicate using the A4(SDA) and A5(SCL) in the Slave-Arduino side which is at 5V. I am following this Tutorial carefully and trying to replicate the "Reading from a slave" part but without success.

EDIT: I am following the procedure and I am receiving the byte properly from the arduino side however the code is locked up in the RFIDI2CStopTransfer(); in the PIC side and I don't know why. Is there someone who can help me with this issue?

\$\endgroup\$
  • \$\begingroup\$ Your code fragments are a little too incomplete in my opinion. You haven't shown any of the master functions like BarI2CTransmitOneByte() and BarI2CStartTransfer(). Also you haven't shown a scope or logic analyzer capture showing that the traffic is what you expect. Also it appears that you're using the same function to send start and restart (BarI2CStartTransfer) - in PIC32 (much like PIC24) start and restart are separate bits in the I2CxCON register (SEN and RSEN respectively). Please add some more meat to this question. \$\endgroup\$ – Adam Lawrence Apr 6 '16 at 12:34
  • \$\begingroup\$ I already updated my post with the functions you asked me for. Please take a look, I am not using the same function to start and restart transfer. Unfortunately I don't have a logic analyzer here @AdamLawrence \$\endgroup\$ – scuba Apr 6 '16 at 14:20
  • \$\begingroup\$ @scuba ditch the Serial.print() in requestEvent. It'll take about 13ms seconds to print that string--too long. Did u try my earlier recommendation? \$\endgroup\$ – TisteAndii Apr 6 '16 at 14:35
  • 1
    \$\begingroup\$ @scuba the receiver overflow error occurs because data was received while there was unread data in the rx buffer. Try calling GetByte before you enable the receiver. Also try editing the code here: people.ece.cornell.edu/land/courses/ece4760/PIC32/PLIB_examples/…; its clearer and has been tested given its source. \$\endgroup\$ – TisteAndii Apr 6 '16 at 16:30
  • 1
    \$\begingroup\$ @scuba Great. You might want to post an answer here and in Arduino.SE. \$\endgroup\$ – TisteAndii Apr 8 '16 at 13:43
1
\$\begingroup\$

Some part of the the issue was related with the address I've use to communicate with the Arduino. I was using 0x07 as an address but it is reserved so I changed to 0x14 (20 in decimal). However I've edited the post in order to get some help with this new issue.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.