Can't read from another Arduino via I2C and Pi

Hello, everyone!
I am working on a project “cable tester”. A few Arduino Due cards are communicating with Raspberry Pi via I2C. Pi is sending numbers to Arduino cards and they are reading if a cable is connected to their pins. So far when a cable is connected to the pins of just one card it’s working perfectly but when the cable is connected from card 1 to card 2 then card 2 is not reading. I am sending from Pi with Java number 1 to card 2 just for reading but it does not work. If someone can help me to fix that I will be very grateful. Thanks in advance!
Here is my code for Pi and Arduino:

Java for Pi:

 for (int i=2; i<54; i++){
          	if (i==21||i==20){continue;
          		}
          	device[4].write((byte) ett);
          	device[7].write((byte) i);
          	a[i]=device[7].read();
          	if (a[i]<120){
        		m1=m1+a[i]+" ";
        	}
          	b[i]=device[4].read();  
        	if (b[i]<120){
        		m2=m2+b[i]+" ";
        	}
        	Thread.sleep(waitTimeRead);
	  	  }

Arduino code:

#include <Wire.h>
#define SIZE 54
#define SLAVE_ADDRESS 0x15 // Slave board with adress 
int number = 0;



void setup() {
  // initialize i2c as slave
  Wire.begin(SLAVE_ADDRESS);
  // define callbacks for i2c communication
  Wire.onReceive(receiveData);
  Wire.onRequest(sendData);
  Serial.begin(9600);
  for (int n = 2; n < 54; n++) {
    if (n == SDA || n == SCL) continue;
    pinMode(n, INPUT_PULLUP);
  }
}

void loop() {
}

// callback for received data
void receiveData(int byteCount) {
  while (Wire.available()) {
    number = Wire.read();
  }
}

// callback for sending data
void sendData() {
  //- - - - - - point 1- - - - - - - - - -
  //----------just reading----------------
  if (number == 1) {
    for (int n = 2; n < 54; n++) {
      if (n == SDA || n == SCL) continue;
      if (digitalRead(n) == LOW) {
        Wire.write(n);
      }
    }
  }
  //- - - - - - point 2- - - - - - - - - -
  //---Reading and creating output "number"
  else if (number > 1 && number < 54) {

    pinMode(number, OUTPUT);//Create output "number"
    digitalWrite(number, LOW);
    for (int n = 2; n < 54; n++) {
      if (n == SDA || n == SCL || n == number) continue;
      if (digitalRead(n) == LOW) {
        Wire.write(n);
      }
    }
    pinMode(number, INPUT_PULLUP);
  }

}

Have I got this right. In principle you have 2 Arduinos, each managing an end of a multicore cable and are synchronously stepping through each permutation of connections to discover failures or unexpected connections. The whole thing is controlled by another device ( a Pi ) ?

I guess each Arduino has a different hardcoded I2C slave address and you have supplied the code for only one example and that you have interconnected the grounds of all devices and that you have checked that, apart from SDA and SDL, no other pin in your range 2 to 54 has another arduino specific purpose.

Yes. :) I have 8 Arduino cards and one Pi but gave an example only with 2 cards and one Raspberry

OK. If you have got to the stage of 1 Arduino and + 1 Pi talking to each other over I2C then the usual problems have already been solved (missing or incorrect value pullup resistors, voltage mismatch etc. etc.).

On the Arduino (in master mode) there is a Wire.beginTransmission(device) and Wire.endTransmission() which returns an error code. There is also a 32 byte buffer size limit. I don't know the Pi well enough to say what the equivalent is.

This is the definitive guide to Arduino I2C: http://www.gammon.com.au/i2c which may help you.

Tonyboy: Yes. :) I have 8 Arduino cards and one Pi but gave an example only with 2 cards and one Raspberry

Nine I2C devices could have a lot of wiring between them. I2C has limits on wire length (bus capacitance). What type of wiring are you using (pF/meter), and what is the TOTAL length. What is the TOTAL pull up resistance on each of the SDA and SCL pins, and where are the resistors located. Post a diagram. Leo..

Hi!
The buffer size limit is increased to 64 bytes (Wire.h line 28 and twi.h line 32). I am using 20 cm Arduino wires for (SDA, SCL, and GND) like those:https://arduino-elektronika.eu/7388-large/40pcs-dupont-wire-jumpercables-21cm-255mm-female-to-male-for-arduino.jpg
So the length of SDA wires is 9x20=180 cm. The length is the same for SCL and GND wires. The resistance for CDA and SCL is over 1k, so I think it should be ok because my devices are running on 3,3V see attached files. I am using Arduino Due and there are 20 000 pull-up resistors build into the Atmega chip. I have attached a diagram.

If your wiring is the exact picture of your schematic, for sure, this will not work at all.

On a DUE, SDA/SCL have already pull ups, therefore you CAN'T connect 8 DUEs with their SDA/SCL.

Instead, connect SDA1/SCL1 (these ones don't have pull ups) of each and every DUE board to the I2C bus, AND add a one and only pull up (2K2 would be OK to 3.3V) to SDA1 and another one to SCL1. Maybe the PI has already pull ups on its I2C bus, I don't know.

The DUEs are in I2C slave mode, the PI in I2C Master mode. Test it with only 1 DUE, when it's OK with one more and so on...

Because you will be using SDA1/SCL1, don't forget to replace everywhere Wire by Wire1 in your I2C slave sketch (add #define Wire Wire1 at the beginning of your sketch, just after including the Library should work).

A though: IMO your I2C bus length is above the usual length, the bus will collect lots of EMI and this is an issue in I2C.

You could also have a synchronisation problem if I understand your logic correctly.
The master expects each slave to return a maximum of 1 result per loop iteration, but I believe the slave could return multiple values, depending on the number of unexpected connections found:

for (int i = 2; i < 54; i++) {
  if (i == 21 || i == 20) {
    continue;
  }
  device[4].write((byte) ett);
  device[7].write((byte) i);
  a[i] = device[7].read();  // this could return multiple values from the slave
                            // from this statement, depending on the state of the connections
                            // from this construct:  for (int n = 2; n < 54; n++) { . . .
  if (a[i] < 120) {
    m1 = m1 + a[i] + " ";
  }
  b[i] = device[4].read();  // this could return multiple values as above
  if (b[i] < 120) {
    m2 = m2 + b[i] + " ";
  }
  Thread.sleep(waitTimeRead);
}

Thanks for your reply, but I have an example which is working fine with SDA and SCL . The problem is that I don’t want to use “byte buf;” because if I have a cable connected to pins 4 (card 1) and 44 (card 2) and 6 (card 1) to 46 (card 2) like this 4-44 and 6-46 the output is: 44, 46, 4, 6. If the cable is connected like this 4-46 and 6-44 the output is the same 44, 46, 4, 6 but it should be 46, 44, 6, 4. So I cant check if the cable is correct. Therefore I want to send to Pi instead “byte buf;” the numbers separate without sorting them.
Here is the Arduino code with buf:

#include <Wire.h>
#define SLAVE_ADDRESS 0x5 // Slave board with address 
#define SIZE 54
int number=0;
byte buf[SIZE];

void setup() {
 // initialize i2c as slave
 Wire.begin(SLAVE_ADDRESS);
 // define callbacks for i2c communication
 Wire.onReceive(receiveData);
 Wire.onRequest(sendData);
 Serial.begin(9600);
 for (int n = 2; n < SIZE; n++) {
   if (n == SDA || n == SCL) continue;
   pinMode(n, INPUT_PULLUP);
 }
}

void loop() {
 //- - - - - - point 3- - - - - - - - - -
 if (number == 0) {
   //buf[0] = number;
   for (int n = 2; n < SIZE; n++) {
     if (n == SDA || n == SCL) continue;
     pinMode(n, INPUT_PULLUP);
     buf[n] = 0;
   }
 }
 delay(200);
}

// callback for received data
void receiveData(int byteCount) {
 while (Wire.available()) {
   number = Wire.read();
 }
}

// callback for sending data
void sendData() {
 //- - - - - - punkt 1- - - - - - - - - -
 //----------just reading-------------
 if (number == 1) {
   //buf[0] = number;
   for (int n = 2; n < SIZE; n++) {
     if (n == SDA || n == SCL) continue;
     int l = digitalRead(n);
     if (l == 0) {
       buf[n] = n;
     }

   }
   Wire.write (buf, sizeof (buf));
 }
 //- - - - - - point 2- - - - - - - - - -
 //---Reading and creating output "number"
 else if (number > 1 && number < 54) {

   pinMode(number, OUTPUT);//Create output "number"
   digitalWrite(number, 0);
   for (int n = 2; n < SIZE; n++) {
     if (n == SDA || n == SCL || n == number) continue;
     if (digitalRead(n) == 0) {
       buf[n] = n;
     }
   }

   Wire.write (buf, sizeof (buf));

 }

}

If your example sketch works with 1 DUE board, this is because the PI has no pull ups !

Add 2.2K pull ups and swap all your boards on SDA1/SCL1

Yes, I think I have a synchronization problem. I will try to fix that "a = device[7].read();" I will try with 2.2K on SDA1/SCL1.

I will try with 2.2K on SDA1/SCL1.

Or keep a single DUE with SDA/SCL (with the builtin pull ups necessary for the I2C bus) and swap the 7 others on SDA1/SCL1.

I tried and it worked thanks! But in case I have a cable connected to pins 4 (card 1) to pin 6 (card 1) the output is correct: 4, 6. But card 2 is not reading. If I comment this row “pinMode(number, INPUT_PULLUP);” and have a cable connected to pin 4 (card 1) and 52 (card 2) then the output is 52,52,52,52…

 //- - - - - - point 2- - - - - - - - - -
 //---Reading and creating output "number"
 else if (number > 1 && number < 54) {

   pinMode(number, OUTPUT);//Create output "number"
   digitalWrite(number, LOW);
   for (int n = 2; n < 54; n++) {
     if (n == SDA || n == SCL || n == number) continue;
     if (digitalRead(n) == LOW) {
       Wire.write(n);
     }
   }
   //pinMode(number, INPUT_PULLUP);
 }

Post your full and actual code for an I2C slave.

I attached them as “.txt” files.

Arduino_code.txt (1.31 KB)

Java_for_Pi.txt (1.41 KB)