I2C How to request 2 different data packages on same device?

In short:

I have 1 Arduino with Ethernet shield using NTP to set internal time and also a web page to submit text messages. : SLAVE I2C

I have a second Arduino showing time and the txt message on 3 Sure3208 matrix led's. MASTER I2C

Now I want to send my text message and correct time to the second arduino, when asked for.

time is 8 bytes
text is 96 bytes

can I make my MASTER I2C ask for 96 bytes and thus receive the text message and than some where else ask for 8 bytes end thus receive time?

MASTER:

Wire.beginTransmission(SLAVE);
Wire.requestFrom(SLAVE,8);
Wire.endTransmission();
rcv_bytes = Wire.receive();
timebuffer = rcv_bytes;

Wire.beginTransmission(SLAVE);
Wire.requestFrom(SLAVE,96);
Wire.endTransmission();
rcv_bytes = Wire.receive();
txtbufffer = rcv_bytes;

or maybe I should think this differently.

I'll send an extra byte in front of the data 'T' or 'M' meaning Time or Message.

The I2Cmaster will send 'T' + time when every 6 hours (or so).
The I2Cmaster will send 'M' + message every time it's needed.

the I2Cslave now receives all bytes (including the first 'T' or 'M' and can fill the correct buffers to hold correct time or message

Or an other way I consider:

Let the slave arduino have 2 wire.begin instances, so it acts as 2 different I2C slaves.
This way time request and message request will be separated.

BUT, can you setup an arduino act as 2 I2C slaves?

In between the wire.beginTransmission() and the wire.endTransmission() calls, you can call wire.write() (or wire.send(), depending on IDE version) to send the slave additional data, that it can read to decide what to return.

It might be easier for the master to just request the slave to send all data, and have the slave return the time and message. The master can then sort out the time from the message.

This isn't right:

Wire.beginTransmission(SLAVE);
Wire.requestFrom(SLAVE,8);
Wire.endTransmission();
rcv_bytes = Wire.receive();

You should send something and then request a response. ie.

Wire.beginTransmission(SLAVE);
Wire.send ("T");  // tell it you want the time
Wire.endTransmission();

// get response
Wire.requestFrom(SLAVE,8);  // get 8 bytes back

// receive up to 8 bytes
if (Wire.available () >= 8)
  {
  rcv_bytes = Wire.receive();
  // and so on for another 7
  }

BUT, can you setup an arduino act as 2 I2C slaves?

What do you mean? A slave will respond to a request from any master, and you can have more than one master.

See here for more info:

@Nick Gammon and @PaulS thanks for your reply.

What do you mean? A slave will respond to a request from any master, and you can have more than one master.

I thought, I wouldn't be able to ask for 2 different kinds of data packages. But thanks to your example on your link (@Nick Gammon), I now understand you can have your master ask for specific data and let your slave answer accordingly.

Now reading that link, I came across this:

It isn't currently mentioned in the documentation, but the internal buffer used for I2C communications is 32 bytes. That means you can transfer a maximum of 32 bytes in one transaction.

It also isn't particularly clear, but the functions Wire.beginTransmission and Wire.send don't actually send anything. They simply prepare an internal buffer (with a maximum length of 32 bytes) for the transmission. This is so that the hardware can then clock out the data at a high rate. For example:

:astonished:

I have to send about 96 bytes, now what? do I have to split up? 3 x 32 ?

or maybe I could ask 3 times for M1, M2 and M3 and use buffer[97] where M1 is buffer[0 till 31], M2 is buffer[32-63] and M3 is buffer [64-95]

You can increase the buffer by changing a couple of spots in the library, but be warned that the library makes five copies of the buffer, so your overhead will go from 5 * 32 (160 bytes) to 5 * 96 (480) bytes. This is out of around 2048 bytes of RAM, assuming you have an Atmega328 or similar.

You could split up your messages into three parts, as you suggest. You might look into if you really need 96 bytes.

You might try some sort of compression scheme. For example, if the message is fairly fixed (ie. not completely free-form) then "fixed" words like "starting up" or "error" could be rendered with a dictionary lookup. For example, you might use bytes 0x80 to 0xFF to be dictionary words, giving you 128 of them.

You might also simply send a length byte first, and then as many packets as necessary to make up that length. So if the message changes, then the first byte could be the length (eg. 24) followed by 24 bytes of message. And then you only send a second packet if you exceed the limit (31 in this case because you need 1 for the length).

@Nick Gammon

Thanks again. I'll be testing this after New Year.

The text messages are free submitted on a webpage form and have a max of 96 bytes. So they can be 1 till 96 bytes large. I do have an END of TEXT character that's been added by my code into the buffer. And bufferlength gets adapted accordingly. So this means bufferlength is automatically set to 5 (+1) when you type: HELLO (well you actually always do, but my buffer is filled with spaces, before it get's filled with the actual message, otherwise shorter text gets mangled up with a previous longer message)

Handy because, I really do know how big my buffer is at the moment I have to send it. This means I can make a piece of code that checks actual bufferlength and acts as indicated like:

if (bufferlenght < 32){
  Wire.beginTransmission(4);
  for (int i = 0; i < (bufferlength +1); i++;){
    Wire.write() = buffer[i];
  }
  Wire.endTransmission(); 
}
if (bufferlenght > 31 && bufferlenght < 64){
  Wire.beginTransmission(4);
  for (int i = 0; i < 32; i++;){
    Wire.write() = buffer[i];
  }
  Wire.endTransmission();
  Wire.beginTransmission(4);
  for (int i = 32; i < (bufferlength +1); i++;){
    Wire.write() = buffer[i];
  }
  Wire.endTransmission();
}
if (bufferlenght > 63){
  Wire.beginTransmission(4);
  for (int i = 0; i < 32; i++;){
    Wire.write() = buffer[i];
  }
  Wire.endTransmission();
  Wire.beginTransmission(4);
  for (int i = 32; i < 64; i++;){
    Wire.write() = buffer[i];
  }
  Wire.endTransmission();
  Wire.beginTransmission(4);
  for (int i = 64; i < (bufferlength +1); i++;){
    Wire.write() = buffer[i];
  }
  Wire.endTransmission();
}

I'll only have to add a recognize byte as first. maybe I can add 'A' 'B' and 'C'. So the slave knows witch part it is receiving and can then put all parts back together in 1buffer ready to be shown on a DOT matrix