I2C basic problems

Hi everyone,

Been trying to use I2C in my acquisition setup but can't figure out what the problem is...
(this is actually extracted from this post http://forum.arduino.cc/index.php?topic=295146.new#new but I think the title doesn't reflect the content anymore so I'm opening a new thread).

I narrowed it to very basic functions that I can't even make work, basically I'm trying to send 4 bytes over I2C (onRequest from a master) and retrieve them and print them to the serial.

Nothing really exotic, isn't it?

Here's the function for the slave that gets called onRequest:

void I2Csend()
{    
  int p=591;

  Wire.write(byte(T[8]));
  Serial.println(byte(T[8]));

  byte  x=lowByte(p);
  Wire.write(x);
  Serial.println(x);

  byte y=highByte(p);
  Wire.write(y);
  Serial.println(y);

  Wire.write(byte(7));
  Serial.println(byte(7));

}

And if I look at the console, I do get : 24, 79, 2, 7 (by heart).

And this code on the master reader (that I trigger every 150mS) :

void I2C()     

{

  if(millis()>TKperiod)
  {
    TKperiod=millis()+150;

    Wire.requestFrom(0x47, 4);
  
  while(Wire.available()>0)
  {
    T[8]=Wire.read();
    h=Wire.read();
    l=Wire.read();
    m=Wire.read();
    T[m]=word(h,l);
  }
   
}

While the I2C on the slave gets requested (since I get the serial.print in the console and they show the right figures), on the Master I get these :

7 255 255 255 0

which is in order : T[8], h, l, m, T[m]

So first of all, it seems the I2C buffer is LIFO and not FIFO (anyone can confirm me on that?).

But also, I really don't understand why only the 7 gets transmitted and none of the others...????

Oh and just one thing : on the slave arduino, there is a delay(100) in the loop due to some conversions from a thermocouple MUX shield that requires it, but as someone pointed out earlier, I2C got it's own hardware so it shouldn't be a problem... right? (seeking confirmation there ;D )

Thanks for your help! :slight_smile: :slight_smile: :slight_smile:

Marc

Here’s the function for the slave that gets called onRequest:

The function that gets called is an interrupt service routine. Interrupts are disabled while an interrupt routine does its thing.

Serial.print() relies on interrupts to do its thing. You can NOT call Serial.print() in an ISR.

On the master, you send a request for data. You expect a response consisting of 4 bytes nanoseconds later. Is that realistic?

Serial.print() relies on interrupts to do its thing. You can NOT call Serial.print() in an ISR.

Ok, thanks for the clarification, but at first (when I wasn't debugging) I didn't have the serial.print and it worked just the same.

Actually, I don't know why but even now it's printing the right values on the slave side.

On the master, you send a request for data. You expect a response consisting of 4 bytes nanoseconds later. Is that realistic?

Funny, even my poorly talented self thought of it at one point. I did add a 5mS delay just after the request.

Made no change though...

I'm questionning myself now :

You can NOT call Serial.print() in an ISR.

Did you mean, You can not : it won't work or you can not : it will f*** shit up?

You might get away with calling Serial.print() in an ISR. IF there is room in the outgoing serial buffer, the function will add data to the buffer and return.

If there is not room, the function will wait for room in the buffer. Room is made in the buffer by sending data, which happens using interrupts. Since interrupts don't happen while your ISR is running, room will never be made in the buffer, so Serial.print() will never return, and your Arduino appears to do nothing.

I2C communications is entirely interrupt driven. The master should have an onReceive() event handler defined, too. Make the request, and return. The onReceive() handler should deal with the response. Whenever it arrives.

Ok I understand why it's working (the serial buffer is pretty much used only for this...).

What I don't understand is why the I2C examples in the Arduino Learning part do not include an onReceive() handler on the master side.
I will include one and see if it does any good.

Could that be the reason of my problems?

Thanks for the help,

Marc

So I tried with the onReceive (even though the examples say it is used in the case of a slave and not a master...) :

So my sending code is this :

void I2Csend()
{    
  int p=591;

  Wire.write(byte(T[8]));

  byte  x=lowByte(p);
  Wire.write(x);


  byte y=highByte(p);
  Wire.write(y);

  Wire.write(byte(7));


}

And my receiving code :

void I2C()      //First requesting

{

  if(millis()>TKperiod)
  {
    TKperiod=millis()+120;

    //MasterReader

    Wire.requestFrom(0x47, 4);
  
 
  }
}


void I2Creceive (int numBytes) //Handler of Wire.onReceive
{
  while(Wire.available()>0)
  {
    T[8]=Wire.read();
    h=Wire.read();
    l=Wire.read();
    m=Wire.read();
    T[m]=word(h,l);
  }
}

But I don't get anything better...

Anyone? :slight_smile: :slight_smile:

:slight_smile: :slight_smile: :slight_smile: :slight_smile:

It works!!!! 8)

Ok, so I didn't know it was an issue and it's not written anywhere but in my case, if I want to send several bytes, I have to put them in an array, basically what I have to do is this :

byte buffer[x];

buffer[0]=a;
buffer[1]=b;
buffer[3]=c;
buffer[4]=d;
etc...

wire.write(buffer,4)

Have no idea why, but it works!