i2c between arduino not reading array more than 8 in size.

hello everyone, i having problem with i2c communucation.

my setup is 2 arduino. one is mega the master and the second is a mega also a slave.

the master requestfrom the slave.

basically the slave has 7 sensor attach to it.

when i try with array of size 7(tomaster[7]) it work correctly,the array get pass to the master but with array of size 9( tomaster[9]) the array is not pass.

Am passing an array of data type float.(volatile float tomaster[9]:wink:
Any help will be most welcome.

here is my code:
My slave:

//i2c slave mega
#include <OneWire.h>
#include <Wire.h>
#include <DallasTemperature.h>

#define ONE_WIRE_BUS A2
OneWire ourWire(ONE_WIRE_BUS);
DallasTemperature sensorstemp(&ourWire);


// array to send to master
volatile float tomaster[9];
//----//

//variable used by temperature sensor
float temperature=0.00;
//------//




//variable used by voltage sensor
int val11;
float val2;
float voltage=0.00;
//-------//

//variable used by light sensor
int sensorPin = 0;//lightsensor on A0 on uno
int lightsensor;
//-------//

// lowest and highest sensor readings for rain sensor:
const int sensorMin = 0;     // sensor minimum
const int sensorMax = 1024;  // sensor maximum
float range;
//------//

// variable for mq3 sensor:
int mq3val=0;
//------//

// variable for mq135 sensor:
int mq135val=0;
//------//

// variable and pins for distance sensor:
#include <NewPing.h>
#define TRIGGER_PIN  14  // Arduino pin tied to trigger pin on the ultrasonic sensor.
#define ECHO_PIN     15  // Arduino pin tied to echo pin on the ultrasonic sensor.
#define MAX_DISTANCE 300 // Maximum distance we want to ping for (in centimeters). Maximum sensor distance is rated at 400-500cm.
NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE); // NewPing setup of pins and maximum distance.
int distances;
//------//


void setup() {
Serial.begin(9600);
Wire.begin(5);//Address of slave uno
Wire.onRequest(requestEvent);
/*-( Start up the DallasTemperature library )-*/
sensorstemp.begin();
}




void loop() {
  



  
// reading the temperature sensor in celsius
sensorstemp.requestTemperatures(); // Send the command to get temperatures
temperature=sensorstemp.getTempCByIndex(0);
delay(50);
//-------//



//reading the voltage sensor from 0.00 to 25v
float volt;
val11=analogRead(A1);
volt=val11/4.092;
val2=(volt/10);
voltage=val2;
delay(50);
//-------//


//reading light sensor data from 0 - 960 A0
int sensorValue = analogRead(sensorPin);
lightsensor=(sensorValue);
delay(50);
//---------------//


// read the sensor on analog A3:
  int sensorReading = analogRead(A3);
  // map the sensor range (four options):
  // ex: 'long int map(long int, long int, long int, long int, long int)'
range = map(sensorReading, sensorMin, sensorMax, 0, 3);
delay(50);
//------//

// read the sensor on analog A4:
mq3val=analogRead(A4);
delay(50);
//------//
// read the sensor on analog A5:
mq135val=analogRead(A5);
delay(50);
//------//

// read the sensor on tx & rx pin:
// Wait 50ms between pings (about 20 pings/sec). 29ms should be the shortest delay between pings.
delay(50);
distances=sonar.ping_cm(); // Send ping, get distance in cm and print result (0 = outside set distance range)
//------//





// storing in volatile array.
// The interrupts are disabled, to prevent that the requestEvent has half-a-written value.
noInterrupts();          // disable interrupts.
tomaster[0] = lightsensor; // storing the lightsensor to array nodepayload
tomaster[1] = voltage;     // storing the voltage to array nodepayload
tomaster[2] = temperature;// storing the temperature to array nodepayload
tomaster[3] = range;
tomaster[4] = mq3val;
tomaster[5] = mq135val;
tomaster[6] = distances;
tomaster[7] = 51.508131;
tomaster[8] = -0.128002;

interrupts();              // enable interrupts
//--------//


//for debuging purpose
//Serial.println(lightsensor);
//Serial.println(tomaster[0]);
//Serial.println(voltage);
//Serial.println(tomaster[1]);
//Serial.println(temperature);
//Serial.println(tomaster[2]);
//Serial.println(range);
//Serial.println(tomaster[3]);
//Serial.println(mq3val);
//Serial.println(tomaster[4]);
//Serial.println(mq135val);
//Serial.println(tomaster[5]);
//Serial.println(distances);
//Serial.println(tomaster[6]);
//------//

}
//end of loop//


//onrequest function
void requestEvent(){
//tomaster is my array
Wire.write((char*)tomaster, sizeof(tomaster)); 
  }

The master:

#include <Wire.h>

float fromslave[9];

void setup() {
  Serial.begin(9600);
  Wire.begin();        // Activate I2C link
}

void loop() {
  
   Wire.requestFrom(5, sizeof(fromslave));    
   int n = Wire.available();         
   if( n == sizeof(fromslave)) {       
     Wire.readBytes( (char *) fromslave, sizeof(fromslave));    
     
     for( int i=0; i<9; i++) {
       Serial.println(fromslave[i]);
     }
     Serial.println("-----");
   }

   delay(500);     // slow down sketch, run loop once a second.
}

I think the code is okay.
A float is 4 bytes, 9 of them is 36 bytes.
The size of the buffers inside the Wire library is 32 bytes, but I don't know if the full 32 bytes can be used. I read somewhere that an extra byte is needed during the I2C transmission.

That means 7 float number of 4 bytes each is 28 bytes, that is safe. Use 7 as the maximum.

If you pack the integers and float into a 'struct', it will fit.
Or you can send a command to the Slave. For example '0' or '1' for two sets of data. The Slave should have a onReceive() handler and store that value. The onRequest() uses that value to return set '0' or set '1' of the data.

Changing to a struct is not that hard.
Now you have:

volatile float tomaster[9];

That becomes a struct (the same struct for Master and Slave):

// size of struct is 24 bytes
struct myData_STRUCT
{
  int lightsensor; 
  float voltage;  
  float temperature;
  float range;
  int mq3val;
  int mq135val;
  int distances;
  float test = 51.508131;
};

volatile myData_STRUCT myData;

...

myData.lightsensor = lightsensor; // storing the lightsensor to array nodepayload
myData.voltage = voltage;     // storing the voltage to array nodepayload
myData.temperature = temperature;// storing the temperature to array nodepayload

...

Wire.write((char*) &myData, sizeof(myData));

The name of an array is a pointer, but the name of a struct is the complete struct. That is why &myData is used to get a pointer to it. That is because the 'struct' is almost like a new type of variable, just like 'int' or 'long' or 'float'.

The rest is the same, disable the interrupts when the struct is filled, and so on.

The sizeof(myData) is the same as the sizeof(myData_STRUCT). The definition of the struct or the actual struct itself can be used for sizeof().

Koepel's method will work nicely for you. You might want to consider sending the raw data, if smaller, then process in the destination device.

I do about the same thing passing 1024 bytes from an array of 512 words from each of four Nanos to a Mega in 32 byte chunks. The onReceive event tells the appropriate Nano which chunk to send. The onRequest event gets the data which the Nano already knows about. The data is accumulated into one array and sent to shore by nRF24 in the same chunk fashion.

thanks for the code koepel, but when i increase the buffer length in the twi.h and wire.h library it work ok. is this ok to do or will fail in the futur. the buffer was 32 byte i increase it to 128 byte

As far as I know, that is possible. The buffer length is software only. There are three buffers, one to transmit, one to receive, and one that the receive buffer is copied to. That makes 3*128 = 384 byte.
You have to change that in every new version :frowning:

My suggestion is to keep the Wire library original and solve it in the sketch. Calling Wire.requestFrom() a few times (often together with writing a register address of the Slave) to get all the data is normal.

ok i stick to your code many thanks. :slight_smile: