i2c byte array not functioning as expected

hello,

I'm trying to send a two bytes of information over I2C which I am trying to get running for the first time.
I understand that you can only send over one byte at a time so I am taking the two int variables (0-1023 range) dividing them by 4 to make it less than 255 as I don't need the accuracy +/- 4 of the original values then putting them into an byte array and sending the two values. in the code I can serial.print the values and they are correct (on Slave)but when I send the array, the array value [1] is always 255 and I cant see where I'm going wrong can anyone help me with this

Thanks in advance

Slave Code:

/*
Measuring Current Using ACS712
*/
//#include <TinyWire.h>
//#include <TinyWire.h>
#include <Wire.h>
// Blink Timing Variables
unsigned long prevMillis = 0;
unsigned long offMillis = 0;
const int interval = 400;       // indicator flash timer in milliseconds
const int timeOff = 2000;       //return to default relay setting, timer in milliseconds
int relayState = LOW;           // Set To Deault relay setting

//Array Variables
uint8_t ampArray1[2];           //unsigned (aka positive) 1 byte array
const int num = 40;             // Number of Reads
int readIndex = 0;              // the index of the current reading
int InR[num];             // Right indicator Sensor Array
int totalR = 0;                  // the running total
int averageR = 0;                // the average
int InL[num];             // Left indicator Sensor Array
int totalL = 0;                  // the running total
int averageL = 0;                // the average

// Pins
const int analogInR = A3;
const int analogInL = A2;
const int RELAY = 1;
byte address = 5;
byte Lb,Rb;

void setup(){ 
//TinyWire.begin(address);
//TinyWire.onRequest(ind);
Serial.begin(9600);
Wire.begin(5);
Wire.onRequest(ind);
 pinMode (RELAY, OUTPUT);

for (int thisReading = 0; thisReading < num; thisReading++){
    InR[thisReading]=0;
   InL[thisReading]=0;
  }


}

void loop(){

   

  ///////////// LEFT INDICATOR######################
  totalL = totalL - InL[readIndex];
  // read from the sensor:
  InL[readIndex] = analogRead(analogInL);
  // add the reading to the total:
  totalL = totalL + InL[readIndex];
  // advance to the next position in the array:
  readIndex = readIndex + 1;
  // calculate the average:
  averageL = totalL / num;  
  delay(1);
  
  ///////////// RIGHT INDICATOR######################
  totalR = totalR - InR[readIndex];
  // read from the sensor:
  InR[readIndex] = analogRead(analogInR);
  // add the reading to the total:
  totalR = totalR + InR[readIndex];
  // advance to the next position in the array:
  readIndex = readIndex + 1;
  // calculate the average:
  averageR = totalR / num;  
  delay(1);
  // if we're at the end of the array...
  if (readIndex >= 40) {
    // ...wrap around to the beginning:
    readIndex = 0;
  }
 averageR = averageR*2;      
 averageL = averageL*2;




unsigned long currMillis = millis();
  if (currMillis - prevMillis > interval) {
    prevMillis = currMillis;
    if (averageL >515 || averageR <505)
      if (relayState == LOW){
        relayState = HIGH;
        offMillis = currMillis;}
  
    else
      relayState = LOW;
      digitalWrite(RELAY, relayState);
  }
  
  if (offMillis - prevMillis > timeOff ){
    relayState = LOW;
    
    
    }
     Lb = averageL/4;
     Rb = averageR/4;
   ampArray1[0] = Lb;
   ampArray1[1] = Rb;
  Serial.print("L="); Serial.println(averageL);
  Serial.print("R="); Serial.println(averageR);
  Serial.print("Lb="); Serial.println(Lb);
  Serial.print("Rb="); Serial.println(Rb);
  delay(500);
  
}

 void ind(){
  int i;
 
   ampArray1[0] = Lb;
   ampArray1[1] = Rb;
  for(i=0;i < 2;i++){
   Wire.write(ampArray1[i]);
  //TinyWire.send(ampArray1[i]);
  }
}

Master Code:

#include<Wire.h>

byte a,b;
void setup() {
  Wire.begin();
  Serial.begin(9600);
  // put your setup code here, to run once:

}

void loop() {
  Wire.requestFrom(5,2);

  while(Wire.available()){
    a = Wire.read();
    b = Wire.read();
  }
  int amp = a *4;
  int amp2 = b*4;

  Serial.print("L-A2:  ");   Serial.println(amp);
  Serial.print("R-A3:  ");      Serial.println(amp2);
   Serial.println("  ");
    Serial.print("a-A2:  ");   Serial.println(a);
  Serial.print("b-A3:  ");      Serial.println(b);
   Serial.println("  ");
  delay(3000);
  

}

The behaviour of Wire.write() depends on whether you're a master or slave.

Calling write() from the master fills a 32-byte buffer which is transmitted when endTransmission() is called.

Calling write() from the slave sends the data immediately, and if you call write(uint8_t), you send only one byte and extra bytes requested by the server are garbage. To send multiple bytes from the slave, you have to fill a buffer and send it all at once.

void ind()
{
  uint8_t ampArray1[2]; 
  ampArray1[0] = Lb;
  ampArray1[1] = Rb;
  Wire.write(ampArray1, 2);
}

Calling write() from the slave sends the data immediately, and if you call write(uint8_t), you send only one byte and extra bytes requested by the server are garbage. To send multiple bytes from the slave, you have to fill a buffer and send it all at once.

Excuse me, but this is wrong. Calling Wire.write() on a slave also writes to a buffer (which is also 32 bytes) and the TWI interrupt fills the hardware register byte by byte if the master is requesting. Once a stop condition is reached the remaining buffer is cleared. At least the AVR platform is behaving this way.

@OP: Your accessing ampArray inside and outside interrupt context so it must be declared volatile otherwise the compiler might optimize relevant stuff away.

As your getting 255 it seems that your hardware is not wired correctly (in a non-working I2C bus you always get 0xFF read). Please post a wiring diagram.

I was referring to the slave response in the .onRequest (requestEvent) handler.

See Nick Gammon explanation at Gammon Forum : Electronics : Microprocessors : I2C - Two-Wire Peripheral Interface - for Arduino

Warning - because of the way the Wire library is written, the requestEvent handler can only (successfully) do a single send. The reason is that each attempt to send a reply resets the internal buffer back to the start. Thus in your requestEvent, if you need to send multiple bytes, you should assemble them into a temporary buffer, and then send that buffer using a single Wire.write. For example:

void requestEvent()
  {

  byte buf [2];

  buf [0] = 42;
  buf [1] = 55;
 
  Wire.write (buf, sizeof buf);  // send 2-byte response
  }

Warning - because of the way the Wire library is written, the requestEvent handler can only (successfully) do a single send. The reason is that each attempt to send a reply resets the internal buffer back to the start. Thus in your requestEvent, if you need to send multiple bytes, you should assemble them into a temporary buffer, and then send that buffer using a single Wire.write. For example:

This might have been the case back in 2011 when Nick wrote that post but using the current IDE it's wrong (just look at the library code). You can use Wire.write() multiple times within the requestEvent handler, just take care that the internal buffer of 32 bytes is not overfilled. And always keep in mind that both, the receiveEvent and the requestEvent handlers are called in interrupt context, so p.e. writing to the serial interface is not allowed.

@cattledog, pylon is right, that bug has been fixed in 2016. You may call Wire.write() more than once in the requestEvent.

@sp00ney, perhaps I2C_Anything can be useful. I don't use it, I use a struct with all sorts of data.

@pylon @Koepel

@cattledog, pylon is right, that bug has been fixed in 2016. You may call Wire.write() more than once in the requestEvent.

Thanks for bringing me up to date.

@pylon

so the array needs to be declared "volatile uint8_t ampArray1[2];" when you talk about the internal buffer does my ampArray1 not count? I will try tonight when I get home.

the hardware, sorry I'm crap with wiring diagrams but I hope this helps:

UNO (Slave) to Mega2560 (Master)

two ACS712 - 5A current sensor break out boards (VCC, GND, Sensor (connected to the UNO))

NC relay Breakout board (VCC, GND,INPUT Connected to the UNO))

10w 5v power supply
+5v VCC
GND

UNO
Vin - VCC
GND - GND
A2 - Sensor1
A3 - Sensor2
4 - INPUT (the code above says 1 but I spotted it and changed it then posted the wrong code)
A5- SCL (communication Section on the mega)
A4- SDA (communication Section on the mega)

MEGA2560 (i believe the Mega has the pull up resistors built in)
Vin - VCC
GND - GND
USB - Laptop (arduino IDE 1.6.8)

USB - Laptop (arduino IDE 1.6.8)

I think that is version 1.6.8.
This version of the IDE does not contain the Wire library fix referred to in this thread.

From what I can see, the Wire library change was distributed with 1.6.10.

Either update your IDE or use the method shown in Reply#1.

so the array needs to be declared "volatile uint8_t ampArray1[2];" when you talk about the internal buffer does my ampArray1 not count?

Yes, the declaration should be that way.
Remove these two lines from your ind() handler (you're setting the array earlier and this way you don't have to declare the other variables volatile also):

   ampArray1[0] = Lb;
   ampArray1[1] = Rb;

Your ampArray1 variable is not related to the buffer I meant. That buffer is part of the Wire library and is controlled only by that library.

MEGA2560 (i believe the Mega has the pull up resistors built in)

Correct, but they are quite weak (10kΩ). For short wires to the sensor it should work.