I2C architecture

Hello,
I try to establish a dialog from a master to a slave using I2C bus.
The master send an "order" and the slave must send a response.
The order is a small structure:

union I2C_ORDER{
	struct ORDER{
		unsigned char masterOrder;
		unsigned int masterParam;
		bool logicalOutput2;
	} ORDER;
	char byteVal[sizeof(ORDER)];
};

The response is also a small structure:

union I2C_SLAVE_RESPONSE{
	struct RESPONSE{
		WEIGHT_OUTPUT weight;
		boolean logical1;
		boolean logical2;
		float floatParameter;
		unsigned char parameter;  
		unsigned char error;
	} RESPONSE;	
	char byteVal[sizeof(RESPONSE)];
	unsigned char i2C_address;
};

I use this method to send the order (and get the response):

I2C_SLAVE_RESPONSE I2C_Tools::getDataFromDevice(unsigned char i2cDevice, I2C_ORDER order){
  I2C_SLAVE_RESPONSE response;
  response.i2C_address = i2cDevice;
  Wire.beginTransmission(i2cDevice);
  if (!Wire.endTransmission()){
    Wire.beginTransmission(i2cDevice);
    for (unsigned char i = 0; i < sizeof(I2C_ORDER); i++){
       Wire.write(order.byteVal[i]);   
    }
    Wire.endTransmission();
    delay(5); // Necessary !!!!
    Wire.requestFrom(i2cDevice, sizeof(I2C_SLAVE_RESPONSE));
    
    unsigned char i = 0;
    switch (Wire.available()){
      case sizeof(I2C_SLAVE_RESPONSE):
          while(Wire.available()){
            response.byteVal[i++] = Wire.read(); 
          }
      break;

      default: response.RESPONSE.error = I2C_BAD_RESPONSE_FORMAT;
			   displayRemoteResponse(response);
      break;                
    } // switch on receive size
  } else {
#ifdef DEBUG
    Serial.print(F("Device with i2C adress: ")); Serial.print(i2cDevice, DEC); Serial.println(F(" is not responding"));
#endif
    response.RESPONSE.error = I2C_DEVICE_NOT_RESPONDING;   
  }
  return response;
}

In the slave device, I have methods:

// I2C regsitration
  Wire.begin(scale.hiveConf.i2C_address);
  Wire.onRequest(i2cRequestEvent);
  Wire.onReceive(i2cReceiveEvent); // register event

Basically, I have a switch in the on the i2cReceiveEvent method to identify the "order"

and I send the response int the method:

Wire.write(response.byteVal, sizeof(I2C_SLAVE_RESPONSE));

So if the order is just "sending a value" all work well.

If the order is more complicated, like requesting a temperature using the Dalas library, the system work many times, but after may be 20 cycles of master / slave exchange, the slave will crash !

Is it a problem in my architecture ?

What can be the reason of slave crash ?

Any help will be welcome.

Best regards

Thierry Vorms

You shouldn't return a struct or array by value.

Best for systems with little RAM, avoiding dynamic memory, if the caller provides memory for the function to fill in the result (by reference) and return just an ok status.

bool I2C_Tools::getDataFromDevice(byte i2cDevice, I2C_ORDER& order,  I2C_RESPONSE& response) {
  response.i2C_address = i2cDevice;
  Wire.beginTransmission(i2cDevice);
  if (!Wire.endTransmission()){
    Wire.beginTransmission(i2cDevice);
    for (unsigned char i = 0; i < sizeof(I2C_ORDER); i++){
       Wire.write(order.byteVal[i]);   
    }
    Wire.endTransmission();
    delay(5); // Necessary !!!!
    Wire.requestFrom(i2cDevice, sizeof(I2C_SLAVE_RESPONSE));
   
    unsigned char i = 0;
    switch (Wire.available()){
      case sizeof(I2C_SLAVE_RESPONSE):
          while(Wire.available()){
            response.byteVal[i++] = Wire.read();
          }
      break;

      default: 
          response.RESPONSE.error = I2C_BAD_RESPONSE_FORMAT;
          displayRemoteResponse(response);
          return false;               
    } // switch on receive size
  } else {
#ifdef DEBUG
    Serial.print(F("Device with i2C adress: ")); Serial.print(i2cDevice, DEC); Serial.println(F(" is not responding"));
#endif
    response.RESPONSE.error = I2C_DEVICE_NOT_RESPONDING;
    return false;   
  }
  return true;
}

Of course you could use real c pointers instead of c++ references, but that would need more changes to your code...

Hello,
Many thanks for your response, but I don't understand !

Do you tell me the size of data returned by the slave is too big ?
The structure size is 20 bytes.

Can you explain me with a little more details ?

Best regards

Thierry