Problem of using raspberry Pi to read multi bytes from arduino via i2c

Dear All,

I connect a raspberry pi (B) to arduino via i2c.
The problem is the result read by python via i2c is different from which print via serial port.
from i2c, it got:
[9, 0, 255, 255, 255, 255, 255, 255, 255]

print by serial port, it got:
11 2 3 4

I have try to set the digital ouput and read the analog input of arduino, either python 2 + smbus or python3 + quick2wire get the similar result:

[9, 0, 255, 255, 255, 255, 255, 255, 255] for python 2 with smbus
and

b'\t\x00\xff\xff\xff\xff\xff\xff\xff' for python3 with quick2wire.

Here is the terminal result print via serial port of arduino:

Ready!
data received: 0
Sensors send: 11 2 3 4 count: 9

The following is th arduino code:

#include <Wire.h>

#define SLAVE_ADDRESS 0x04

int number = 0;
int state = 0;
double temp;

int index = 0;

const char pinWritings[] = {2, 3, 4, 5, 6, 7, 8, 9};
int cmd=0;

const char pinReadings[] = {A0, A1, A2, A3};
typedef struct {
  byte address;
  int values[4];
} data;
data d;

void setup() {
  int i;
  //initialize all the pins for the Relays
  for (int i = 0; i < sizeof(pinWritings); i++)
  {
    pinMode(pinWritings[i], OUTPUT);
  }
  
  //d.address = SLAVE_ADDRESS;
  d.address = byte(0x31);
  //initialize all the pins for the Relays
  for (int i = 0; i < sizeof(pinReadings); i++)
  {
    d.values[i] = 0x31 + i;
  }
  
 pinMode(LED_BUILTIN, OUTPUT);
 Serial.begin(9600); 
 // initialize i2c as slave
 Wire.begin(SLAVE_ADDRESS);

 // define callbacks for i2c communication
 Wire.onReceive(receiveData);
 Wire.onRequest(sendData);
 Serial.println("Ready!");
}

void loop() {
  delay(100);
  //GetAnalog();
  //sendData();
}

// callback for received data
void receiveData(int byteCount){

 while(Wire.available()) {
  number = Wire.read();
  Serial.print("data received: ");
  Serial.println(number);
  if (number != 0)
    {
      setGPIO(number);
    }
   if (number == 0)
   {
     sendData();
   }
 }
}

// callback for sending data
void sendData(){
  int count;
  count = Wire.write((byte *)&d, sizeof(d));
  Serial.print("Sensors ");
  Serial.print(" send: ");
  Serial.write((byte *)&d, sizeof(d));
  Serial.print(" count: ");
  Serial.println(count);

}

//Get the value of sensors for A0 to A3
void GetAnalog(void)
{ 
  int i = 0;
  for (i; i < sizeof(pinReadings); i++)
  {
    d.values[i] =  0x64 + i;//analogRead(pinReadings[i]);
    // apply the calibration to the sensor reading
    //d.values[i] = map(d.values[i], 0, 1023, 0, 255);
    // in case the sensor value is outside the range seen during calibration
    //d.values[i] = constrain(d.values[i], 0, 255);  
    Serial.print("sensor ");
    Serial.print(i);
    Serial.print(" detected: ");
    Serial.println(d.values[i]);
    delay(1000);
  }
}

void setGPIO(int cmd)
{
   Serial.print(" Get command: ");
   Serial.println(cmd, BIN);
  int i;
  for (i = 0; i < sizeof(pinWritings); i = i + 1)
  {
     digitalWrite(pinWritings[i],(1 << i & cmd) >> i);
     Serial.print("Pin ");
     Serial.print(i);    
     Serial.print(" setted: ");
     Serial.println((1 << i & cmd) >> i, BIN);
  }
}

and the python 2 with smbus is as follows:

import smbus
import time

address = 0x04

if __name__=="__main__":
	bus = smbus.SMBus(1)    # 0 = /dev/i2c-0 (port I2C0), 1 = /dev/i2c-1 (port I2C1)
	
	while True:
		try:
			value = int(str(input("Enter 0 - 255:")).strip())
		except Exception as e:
			print(e)
			continue
			
		bus.write_byte(address, value)
		#bus.write_byte_data(address, 0, value)
		time.sleep(1)
		
		number = bus.read_i2c_block_data(address, 0x00, 9)
		#number = bus.read_byte(address)
		# number = bus.read_byte_data(address, 1)
		print(number)
		datas = [(number[i]<<8) + number[i+1] for i in range(1,9,2)] #1,3,5,7
		print(datas)

and the python3 + quick2wire code also as follows:

from quick2wire.i2c import I2CMaster, writing_bytes, reading
import time

address = 0x04

if __name__=="__main__":		
	with I2CMaster() as master:
		while True:
			try:
				value = int(str(input("Enter 0 - 255:")).strip())
			except Exception as e:
				print(e)
				continue
			number = master.transaction(writing_bytes(address, value),
										reading(address, 9))[0]
			print(number)
			print(number[0])
			datas = [(number[i+1]<<8) + number[i] for i in range(1,9,2)] #1,3,5,7
			print(datas)
			time.sleep(1)

Can you clarify two things:

  1. How is this connected - is it all 3.3V or are you using a level shifter? Do you
    have pull-up resistors?

  2. Which end is meant to be I2C master and which end slave?

Sorry, I forgot to clarify the hardware connection with details.
I used a seperated ic ADuM1250 between the Rpi and Arduino, and the Raspberryy Pi is the master device, and Arduino is the slave device.
In fact, when I change to read only one byte, it can get the correct value.
ie. number = bus.read_byte(address)

MarkT:
Can you clarify two things:

  1. How is this connected - is it all 3.3V or are you using a level shifter? Do you
    have pull-up resistors?
    I used a seperated ic ADuM1250 between the Rpi and Arduino;
    http://www.analog.com/en/interface-isolation/digital-isolators/adum1250/products/product.html

  2. Which end is meant to be I2C master and which end slave?
    The Raspberryy Pi is the master device, and Arduino is the slave device.

I solved it by adding more delay for waiting the reading finished.
The code is as follows:
——————————————————————————————————————————————————
from quick2wire.i2c import I2CMaster, writing_bytes, reading
import time

import struct
from collections import namedtuple

address = 0x04

if name=="main":
with I2CMaster() as master:
while True:
try:
value = int(str(input("Enter 0 - 255:")).strip())
except Exception as e:
print(e)
continue

master.transaction(writing_bytes(address,value))
time.sleep(1)

sensors = master.transaction(reading(address, 8))[0]
print(sensors)
Sensors = namedtuple("Sensors", "A0 A1 A2 A3")
s = Sensors._make(struct.unpack("<HHHH", sensors))
print(s)
time.sleep(1)