Arduino i2c Reading only 80 bytes

I am connecting two Arduinos over i2c protocol and trying to send from one Arduino to another 16 packets by 8 bytes and reading it with another Arduino. For some reason I am only receiving first 80 bytes.
Can any one help me how to transfer 128 or more bytes
There is my example codes:
Master Reading:

#include <Wire.h>
#include <Arduino.h>

unsigned int BEGIN = 0;
byte c[17][9];

void setup() 
{
Serial.begin(9600);
Wire.begin();
//Wire.setClock(300000L); 
}
void loop() 
{
int address=0x55;
unsigned int j=0;
unsigned int k=0;
for (BEGIN=0x00; BEGIN<=0x78; BEGIN=BEGIN+8) //  from 0 to 0x78
  {
    Wire.beginTransmission(address); // link to 0x50 - 0x56   
    Wire.write(0x80); // must act as a position pointer
    Wire.write(BEGIN);
    Wire.endTransmission(false);
    //Wire.endTransmission();
    Wire.requestFrom(address, 8); // request 8 bytes from slave 
    
    while(Wire.available()) // read from chip while avaliable 
    {
      j++;
      c[k][j] = Wire.read();    // reccive byte as byte
    }
   k++;
  }
  Wire.endTransmission();
}

Slave sending:

#include <Wire.h>

byte answer_To_80x00[]={0xE2, 0x00, 0x01, 0x0A, 0x05, 0x05, 0x00, 0x00};
byte answer_To_80x08[]={0xFF, 0x40, 0x00, 0x01, 0x20, 0x18, 0x11, 0x07};
byte answer_To_80x10[]={0x01, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, 0x00};
byte answer_To_80x18[]={0x00, 0x00, 0x00, 0x00, 0x16, 0x01, 0x20, 0x19};

byte answer_To_80x20[]={0x00, 0x00, 0x00, 0x58, 0x1B, 0x33, 0x00, 0x08};
byte answer_To_80x28[]={0x55, 0x41, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00};
byte answer_To_80x30[]={0x00, 0x00, 0x85, 0x00, 0x0A, 0xFF, 0x07, 0x08};
byte answer_To_80x38[]={0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51};

byte answer_To_80x40[]={0x00, 0x4E, 0x20, 0x00, 0x00, 0x47, 0xFD, 0x47};
byte answer_To_80x48[]={0xFD, 0x47, 0xFD, 0x02, 0x00, 0x00, 0x00, 0x00};
byte answer_To_80x50[]={0x00, 0x4D, 0x55, 0x54, 0x00, 0x00, 0x00, 0x00};
byte answer_To_80x58[]={0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x51};

byte answer_To_80x60[]={0x4D, 0x55, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00};
byte answer_To_80x68[]={0x49, 0x4D, 0x50, 0x50, 0x2D, 0x31, 0x38, 0x30};
byte answer_To_80x70[]={0x30, 0x30, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00};
byte answer_To_80x78[]={0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};

int A8_request=0;
int x80_request=0;
int _step = 0;
void setup()
{
  Wire.begin(0x55); // join i2c bus with address 55
  //Wire.setClock(300000L); //300000
  Wire.onReceive(receiveEvent); // register event
  Wire.onRequest(sendEvent);
  Serial.begin(115200);           // start serial for output
}

void loop()
{
  //delay(1);
  //Serial.println("***********");
}

// function that executes whenever data is received from master
// this function is registered as an event, see setup()
void receiveEvent(int howMany)
{
  while(1 < Wire.available()) // loop through all but the last
  {
    byte c = Wire.read(); // receive byte as a character
    if (c==0x80)
      {
        //Serial.println(" chip reccived 0x18 ");
        byte x = Wire.read();// receive byte as an integer
        
        if (x==0x00 and x80_request==0){_step=6;  /*Serial.println(" request from pointer 0x00 sending back E2");*/ x80_request=1; }
        
          if (x==0x00 and x80_request==1 and _step==6) { _step=7;}
          if (x==0x08 and x80_request==1){_step=8;}
          if (x==0x10 and x80_request==1){_step=9;}
          if (x==0x18 and x80_request==1){_step=10;}

          if (x==0x20 and x80_request==1){_step=11;}
          if (x==0x28 and x80_request==1){_step=12;}
          if (x==0x30 and x80_request==1){_step=13;}
          if (x==0x38 and x80_request==1){_step=14;}

          if (x==0x40 and x80_request==1){_step=15;}
          if (x==0x48 and _step==15){_step=16;}
          if (x==0x50 and _step==16){_step=17;}
          if (x==0x58 and _step==17){_step=18;}

          if (x==0x60 and x80_request==1){_step=19;}
          if (x==0x68 and x80_request==1){_step=20;}
          if (x==0x70 and x80_request==1){_step=21;}
          if (x==0x78 and x80_request==1){_step=22; x80_request=0;}
        
      }
      
    //Serial.println(" I reccived: ");
    //Serial.print(c, HEX);         // print the character
    
  }
  byte x = Wire.read();// receive byte as byte
  //Serial.print(" Just reading: ");
  //Serial.println(x, HEX);         // print the hex
}

void sendEvent()
{
 
 if (_step==6) {Wire.write(answer_To_80x00,8);}//{Wire.write(0xE2);}
 if (_step==7) {Wire.write(answer_To_80x00,8);}
 if (_step==8) {Wire.write(answer_To_80x08,8);}

 if (_step==9) {Wire.write(answer_To_80x10,8);}
 if (_step==10) {Wire.write(answer_To_80x18,8);}

 if (_step==11) {Wire.write(answer_To_80x20,8);}
 if (_step==12) {Wire.write(answer_To_80x28,8);}
 if (_step==13) {Wire.write(answer_To_80x30,8);}
 if (_step==14) {Wire.write(answer_To_80x38,8);}

 if (_step==15) {Wire.write(answer_To_80x40,8);}
 if (_step==16) {Wire.write(answer_To_80x48,8);}
 if (_step==17) {Wire.write(answer_To_80x50,8);}
 if (_step==18) {Wire.write(answer_To_80x58,8);}

 if (_step==19) {Wire.write(answer_To_80x60,8);}
 if (_step==20) {Wire.write(answer_To_80x68,8);}
 if (_step==21) {Wire.write(answer_To_80x70,8);}
 if (_step==22) {Wire.write(answer_To_80x78,8);} 
}

There is my result which I am getting from logic analayser,
reading only first 80 bytes and it just stops:

write to 0x55 ack data: 0x80 0x00 
read to 0x55 ack data: 0xE2 0x00 0x01 0x0A 0x05 0x05 0x00 0x00
write to 0x55 ack data: 0x80 0x08 
read to 0x55 ack data: 0xFF 0x40 0x00 0x01 0x20 0x18 0x11 0x07
write to 0x55 ack data: 0x80 0x10 
read to 0x55 ack data: 0x01 0x00 0x00 0x98 0x00 0x00 0x00 0x00
write to 0x55 ack data: 0x80 0x18 
read to 0x55 ack data: 0x00 0x00 0x00 0x00 0x16 0x01 0x20 0x19
write to 0x55 ack data: 0x80 0x20 
read to 0x55 ack data: 0x00 0x00 0x00 0x58 0x1B 0x33 0x00 0x08
write to 0x55 ack data: 0x80 0x28 
read to 0x55 ack data: 0x55 0x41 0x00 0x08 0x00 0x00 0x00 0x00
write to 0x55 ack data: 0x80 0x30 
read to 0x55 ack data: 0x00 0x00 0x85 0x00 0x0A 0xFF 0x07 0x08
write to 0x55 ack data: 0x80 0x38 
read to 0x55 ack data: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x51
write to 0x55 ack data: 0x80 0x40 
read to 0x55 ack data: 0x00 0x4E 0x20 0x00 0x00 0x47 0xFD 0x47
write to 0x55 ack data: 0x80 0x48 
read to 0x55 ack data: 0xFD 0x47 0xFD 0x02 0x00 0x00 0x00 0x00
write to 0x55 ack

I think you are overloading the I2C bus. The Slave is an Arduino, that means some things are in hardware (for example an acknowledge to its I2C address) and some things are in a interrupt function and some things are in your sketch (for example the onRequest handler).

Which Arduino boards do you use ? I assume a basic board, like the Uno or Nano.

I think you are also overloading the Serial bus. When you send too much text to the serial monitor, the Arduino could become 100 times slower or stop.

Can you walk through all these notes, and improve your sketch step by step ?

  1. We don’t use a variable name with all capitals. The word “begin” might be reserved. You use it only locally in the for-loop. That means a local variable is more appropriate.
for (int i=0x00; i<=0x78; i=i+8) //  from 0 to 0x78
{

The “int i=0x00” part is where the integer “i” is created and used at the same time.

  1. When declaring an array that has 16 packets of 8 bytes, then you should use [16][8].
    The first one is myArray[0][0] and the last one is myArray[15][7].

  2. The baudrate of the Master is 9600 and the baudrate of the Slave is 115200. Why ?

  3. When using Arduino to Arduino with I2C, there is no need for a repeated start. You can use Wire.endTransmission() without the ‘false’ parameter.

  4. Sometimes it is safer to wait 1 ms between Wire.endTransmission() and Wire.requestFrom().

...
Wire.endTransmission();

delay( 1);     // extra safety during testing, because Koepel told me so

Wire.requestFrom(address, 8); // request 8 bytes from slave 
...

Perhaps during testing, you should add a delay after the reading the data as well, before the new beginTransmission() is called.

  1. There is a better way to check the Wire.requestFrom().
int n = Wire.requestFrom( address, 8);
if( n == 8)
{
  for( int j=0; j<8; j++)
  {
    c[k][j] = (byte) Wire.read();
  }
}
else
{
  Serial.println( "requestFrom failed");
}

I think this is more straightforward. Use it this way if you like it.

  1. Please remove the last Wire.endTransmission() in the Master sketch. It should not be used after a Wire.requestFrom(). The Wire.endTransmission() may not be used to stop something or end something, that is not what it does.

  2. Slow down your sketch to avoid overloading the I2C bus and/or the Slave.

void loop()
{
 ...

 delay( 100);       // slow down the sketch, request data 10 times per second.
}
  1. The Slave data can be one array. If the numbers are fixed, then you can make it a ‘const’ array.
byte answerData[16][8] = 
{
  { 0xE2, 0x00, 0x01, 0x0A, 0x05, 0x05, 0x00, 0x00 },
  { 0xFF, 0x40, 0x00, 0x01, 0x20, 0x18, 0x11, 0x07 },
  ...
  { 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF },
};
  1. Please do not use the “loop through all but the last”. I know that is in the official example, but it is terrible.

Do you expect two bytes ? Then check if there are two bytes and use them.

void receiveEvent(int howMany)
{
  if( howMany == 2)        // expecting two bytes
  {
    byte firstByte = (byte) Wire.read();
    byte secondByte = (byte) Wire.read();
    ...
  }
}
  1. You don’t need all that code in receiveEvent(). Can you transmit the number of the index ? I don’t understand why the first byte is 0x80, so I don’t know how to make a short example.

  2. You have commented out the Serial functions in the onReceive and onRequest handlers. Can you remove them ? You should not use Serial functions in a interrupt, not even for testing.

  3. Tutorial by Robin2: https://forum.arduino.cc/index.php?topic=683181.0
    An array for your data is okay, but if some day you need to add other things and other data, then you need a ‘struct’.

  4. Did you know that the MKR boards can transfer 256 bytes instead of 32 in a single I2C transaction.

  1. Sometimes it is safer to wait 1 ms between Wire.endTransmission() and Wire.requestFrom().

I don't think that this makes the code better...

  1. Slow down your sketch to avoid overloading the I2C bus and/or the Slave.

You cannot overload the bus this way, so the delay is useless.

Both the _step and the x80_request variables must be declared volatile as they are used in different interrupt routines, otherwise the compiler might optimize some occurrences away.

According to the logic analyzer data you posted the sender stops sending after it sent the slave's address which got acknowledged. This is rather special as the sender shouldn't wait for something there. Did you use exactly the posted code for your test? Did you run the test multiple times and it stopped every time at exactly that position?

pylon:
You cannot overload the bus this way

pylon, the Slave uses clock stretching, but it is still possible to overload the I2C bus for the Slave.

You are right about the SDA and SCL signals of the I2C bus. They go up and down as they do. However, when the Master is continuously pounding the Slave with I2C sessions, then the Slave has not enough time to run all the code.

Thanks a lot for all your answers, I am going to follow your advices and will change code.
Just few notes:

  1. Yes I did run this code multiply times and have all the time same results
  2. YEs I am using current code for my tests, however I am going to modify it and update it later.
  3. I am using Arduino Micro, also I tried Wemos D1 mini, Arduino nano, arduino uno I have many different development boards so it not a problem to try on different platform. Actually I think to try it on ESP32

pylon, the Slave uses clock stretching, but it is still possible to overload the I2C bus for the Slave.

You cannot overload the bus but any device can block it completely by pulling the clock down infinitely. In my naming that isn't an overload.

However, when the Master is continuously pounding the Slave with I2C sessions, then the Slave has not enough time to run all the code.

That's why the slave is using clock stretching to get it's time. While the slave stretches the clock the master have to wait so it cannot start a new session or anything the like. So the only way to "overload" the bus is if the master doesn't implement I2C correctly and doesn't wait if the slave stretches the clock. That doesn't seem to happen here and I wouldn't expect it using AVR Arduinos.

  1. I am using Arduino Micro, also I tried Wemos D1 mini, Arduino nano, arduino uno I have many different development boards so it not a problem to try on different platform. Actually I think to try it on ESP32

As you didn't specify the board used we automatically assumed you to use Arduino UNOs. If you use different boards the reaction can be completely different. Stay at one platform and especially don't mix the boards in one setup (at least until you got it running once).

I don't know if the ESP processors support clock stretching, so please don't use them for the moment.

As you use the Arduino Micro and don't use the Serial object in the sketch, please remove the Serial.begin() calls from setup(). As the Serial object is emulated on the USB bus on this board (CDC) it activates some interrupts which may interfere with the other code.

I'm still surprised where your sketch stops as I would have expected the slave to fail but it seems that the master freezes which I cannot explain at the moment. The slave is addressed and it acknowledged that but I don't see a reason why the slave should block the bus (clock stretching) at that stage given the posted code as you told us you didn't modify it (not even slightly!).

Thanks a lot Pylon for your comments. I modified code slightly and it looks like it start to work.

  1. I have increased array from c[17][9] to c[19][19]
  2. also in the read loop I notice that I start to iterate j++ before writing any values there so I moved it after Wire.read
while(Wire.available()) // read from chip while avaliable
    {
      j++; // moved doww after reading
      c[k][j] = Wire.read();    // reccive byte as byte
    }
   k++;

This is final code which is working correctly now

#include <Wire.h>
#include <Arduino.h>

unsigned int BEGIN = 0;
byte c[19][19];    // changed from [17][9]

void setup()
{
Serial.begin(9600);
Wire.begin();
//Wire.setClock(300000L);
}
void loop()
{
int address=0x55;
unsigned int j=0;
unsigned int k=0;
for (BEGIN=0x00; BEGIN<=0x78; BEGIN=BEGIN+8) //  from 0 to 0x78
  {
    Wire.beginTransmission(address); // link to 0x50 - 0x56   
    Wire.write(0x80); // must act as a position pointer
    Wire.write(BEGIN);
    Wire.endTransmission(false);
    //Wire.endTransmission();
    Wire.requestFrom(address, 8); // request 8 bytes from slave
   
    while(Wire.available()) // read from chip while avaliable
    {
      c[k][j] = Wire.read();    // reccive byte as byte
      j++;
    }
   k++;
  }
  Wire.endTransmission();
}

Also I find out that ESP32 and Wemos have some issue wit Wire librabry and it does not support correctly slave devices. So I stick with Arduino pro Micro / Leonardo
Thanks a lot again. It is very valuable to receive support here.

Please remove that last Wire.endTransmission(), after the Wire.requestFrom().
Read my alternative explanation of the functions: Explanation of the functions of the Wire library · Koepel/How-to-use-the-Arduino-Wire-library Wiki · GitHub.

The Wire.endTransmission() works together with Wire.beginTransmission() to write data. The Wire.endTransmission() may not be used to stop something or end something, that is not what it does. I think its name is wrong, it should be called "ExecuteWritingDataToSlave()".