Wire.write() more than 32 bytes

I know this has been asked a million times but i searched everywhere and haven't found a solution to my problem.

I have a struct,

struct a {
uint32_t vars[50];
}
a struct;

I want to send it over I2C that is limited to 32byte packets. Can someone please show me how to send and receive that struct over i2c?

First of all, you should not use the I2C bus to communicate between processors. It is not that kind of bus. Projects fail because of that.
You could upgrade to a MKR Zero or similar board (up to 256 bytes) or a ESP32.
Are you expecting working examples ? That is not possible, there are many ways that it can go wrong, and it depends on your project what the best solution is.
The Slave has to respond quickly to the I2C bus, and therefor it is better not to use libraries that turn off interrupts (Neopixel, FastLED, OneWire, DHT, SoftwareSerial, an so on).

50 * 4 bytes = 200 bytes.
Which Arduino boards do you use ?

Master is requesting data:

The easiest way is to add a index as first byte and perhaps the amount of data in a second byte. The Slave only has to pull that data from the array. Even if the Slave is disconnected, the Master is still in control and can deal with that.
A problem is when, for example, a temperature sensor is disconnected from the Slave, or the data in the Slave is no more updated and the Master does not know that.
Another problem is that the Master is kept busy during all the requests. A slow Slave will keep the Master even longer busy.
If the Slave has only now and then new data, and only a few new samples, then the Slave could tell the Master which data is new. That would require other code.

Master sends data:

The easiest way is also here to use a index in the first byte. The length is known in the Slave, so the amount of data in the second byte is not really needed, but it does no harm.
The Master has to check if that data has arrived in the Slave.
The Slave stores the data in a array, that's all.
A problem is that the Slave does not really know when a refresh of all the data was done. It is possible to add also commands, to tell the Slave to use the new data. Then the code gets complex and is no longer straightforward.
Also in this situation, the Master is busy during sending all the data.

I have a small network of i2c devices aprox 16 slaves and one of the slaves is also a master on another bus.

Main master "arduino mega" But im working with my submodule that is a ESP32 running multiple I2C busses at default speed. The submodule should send that struct to the master. I compress the padding from the struct on the ESP32 and send it to the master. but im limited to 32 byte packets.

I understand how i could Wire.write(array[index]); but im not able to produce anything to receive the bytes and put them back together.

Which part of my reply did you not understand ?
I'm curious about the padding. I hope you are not sending readable ASCII over I2C.
How long are the wires and what kind of pullup do you have ?
It is not allowed to connect the SDA and SCL from the Arduino Mega board to the SDA and SCL of a ESP32.
How does the Slave tell the Master that it has new data ?

I was not joking when I wrote that the I2C bus is not that kind of bus (the kind of bus that you think it is). The I2C bus is to retrieve a few fixed number of bytes from a sensor.

Can you tell more about the data ? Does all the data belong together or are they just individual temperatures. If they are all individual temperatures, then it is okay to miss a few once in a while.

This application does indeed seem more suited to something like RS-485. Note that this is just an electrical standard. It's up to you to define the appropriate (robust) protocol.

1 Like

The data consists of multiple types. byte/2byte/4byte.

I2c wasn't my first choice, but considering how "plug and play" it is, it gets the job done. My cables are shielded a short. as long as the bus capacitance and rise/fall times are good, then what's the problem? I know what I2C is I understand how it works. I simply asked how to basically send a bytestream over I2C. but whatever, i suppose i will just send 32bytes worth of variables at a time and make a million read/writes operations.

The only i2c communication with the salve is the master sending it a command and then requesting data from the slave. But ill just keep incrementing the command and requesting 32bytes at a time.

Assume that you have10 bytes data to send to Slave (with slaveAddress 0x53) using I2C Bus. Here are the codes for you (not compiled and not tested.).

#include<Wire.h>

byte myData[]= {1, 2,3, 4, 5, 6, 7, 8,, 9. 10};

void setup()
{
     Serial.begin(9600);
     Wire.begin();
     //------------------------
    Wire.beginTransmission(0x53);
    Wire.write(myData, sizeof myData);
    Wire.endTransmission();
}

void loop(){}

I think we have a miscommunication here.

The I2C is not plug and play. It does not get the job done. It is really a bad idea to use the I2C bus between boards. The rise and fall times are not important, because that can be solved by lowering the clock speed. The I2C bus can not deal with crosstalk between SDA and SCL. You have to be sure there will be no crosstalk between those wires. Keep those wires away from each other.

The Master sending a chunk of 30 bytes:

Wire.beginTransmission( 0x10);
Wire.write(index);         // first time 0, next time 30, next time 60
Wire.write(length);       // first time 30, next time 30, last time the remaining bytes
Wire.write(buffer, length);
Wire.endTransmission();

The Slave sending a chunk of 30 bytes (not tested):

void onRequest()
{
  Wire.write( index);    // index is global variable. It should have been reset before
  Wire.write( length);   // length should be 30 default.
  Wire.write( (byte *) (buffer + index), length);

  // Increase the index and wrap around when the end is reached.
  index += length;
  if( index > total_buffer_size)
  {
    index = 0;
    length = 30;
  }

  if( index + length > total_buffer_size)
  {
    length = total_buffer_size - index;
  }
}

What is the purpose of the above two bytes data? Codes indicate that the buffer is an array and contains the 30-byte data.

Assuming you want to take the above comments, "under advisement", i.e. mostly ignore them, your solution would be to re-design your data protocol to fit the transmission protocol.

Not, try to force the transmission protocol to bend to the requirements of your data protocol.

I'm not sure what you're up to and you've been a little coy about that, but I would suggest packetizing the data stream.

Kindly, post the correct version of the above structure declaration. Can you use a keyword as a variable/identifier?

What keyword?

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.