Quercus47
Posts: 8
Joined: Sat Sep 09, 2017 7:27 pm

I2C smbus2 block data

Tue Sep 12, 2017 3:19 am

Hello, I'm working on a project exchanging data between an RPi and Arduino, and have been forced to switch to I2C as my communication protocol for several reasons. I've had success using simple read and write requests to pass single bytes of data back and forth. But I'm trying to pass a bunch of bytes, so I'm trying to use read_i2c_block_data from the smbus2 library. I continue to get the following error no matter what I try:

Code: Select all

Traceback (most recent call last):
  File "/home/pi/sketchbook/I2Ctalk04/I2Ctalk04.py", line 36, in <module>
    readBunchOfData(4)
  File "/home/pi/sketchbook/I2Ctalk04/I2Ctalk04.py", line 25, in readBunchOfData
    myDataHere = readBlockData(numBytes)
  File "/home/pi/sketchbook/I2Ctalk04/I2Ctalk04.py", line 17, in readBlockData
    x = bus.read_i2c_block_data(address, 0, numBytes)
  File "/usr/local/lib/python3.4/dist-packages/smbus2/smbus2.py", line 391, in read_i2c_block_data
    ioctl(self.fd, I2C_SMBUS, msg)
OSError: [Errno 121] Remote I/O error
Line 17 is the " x = bus.read_i2c_block_data(address, 0, numBytes)" line. I've read that this is sometimes related to there being nothing on the other end of the i2c bus, but I can't see where the problem is. I've also tried several different ways of doing the read_i2c_block_data and this is most similar to the very limited examples I've found. Any suggestion is appreciated. Many thanks.

Here is my code for the Pi:

Code: Select all

from smbus2 import SMBus
import time

bus = SMBus(1)
address = 0x04

def writeNumber(value):
    bus.write_byte(address, value)
    return -1

def readNumber():
    number = bus.read_byte(address)
    return number

def readBlockData(numBytes):
    res3 = []
    x = bus.read_i2c_block_data(address, 0, numBytes)
    res3.extend(x)
    return res3

def readBunchOfData(numBytes):
    # Send number of bytes we are requesting
    writeNumber(numBytes)
    # Receive data
    myDataHere = readBlockData(numBytes)
    # Show what we've got
    print ("We received ", numBytes, " of data")
    for i in range(0, numBytes):
        print (myDataHere[i])
        

while True:
    # For now, hard-code 4 bytes of data
    print ()
    print ("We are requesting ", 4, " bytes of data")
    readBunchOfData(4)
    print ()
Here is the Arduino code:

Code: Select all

#include <Wire.h>

#define SLAVE_ADDRESS 0x04
int number = 0;
int dataNo = 0;

void setup() {
  Serial.begin(9600);
  Wire.begin(SLAVE_ADDRESS);
  
  Wire.onReceive(receiveData);
  Wire.onRequest(sendData);
  
  Serial.println("Ready!");
}

void loop() {
  doingSomething(10);
}

void doingSomething(int loops) {
  for (int i = 0; i<loops; i++) {
    Serial.print("I'm doing something else...");
    Serial.println(i);
    delay(50);
  }
}

void receiveData(int byteCount) {
  while(Wire.available()) {
    number = Wire.read();
    
    if (dataNo == 0) {
      // dataNo, so this is how many bytes to send - currently hard-coded at 4
      dataNo = number;
    }
    else {
      // We should not get here
      Serial.println("We got to hole 1");
    }  
  }
}

void sendData() {
  byte output[] = {0x01,0x02,0x03,0x04};  // This is just some sample data for testing
  Wire.write(output, 4);
  dataNo = 0;
}

User avatar
OutoftheBOTS
Posts: 711
Joined: Tue Aug 01, 2017 10:06 am

Re: I2C smbus2 block data

Tue Sep 12, 2017 6:37 am

Normally I would normally pass 3 values to the bus.write_byte function, it would be the I2C address then the register address then the data

Quercus47
Posts: 8
Joined: Sat Sep 09, 2017 7:27 pm

Re: I2C smbus2 block data

Tue Sep 12, 2017 3:25 pm

Thanks. Although the register address is part of the official I2C protocol and is implemented in smbus2 (x = bus.read_i2c_block_data(address, 0, numBytes), see the middle 0 parameter), it is not implemented that I can see in the arduino Wire module. I've been presuming that Wire 'hides' this parameter on an incoming request for data and is agnostic about any specified register. I.e. (address, 0, numBytes), (address, 3, numBytes) would be treated just the same.

However... I am noticing just now that Wire appears to only implement read and write (presumably the smbus2.read_byte and smbus2.write_byte equivalents), and does not implement at all that I can see the many other read and write options available in smbus2. Perhaps using read_i2c_block_data is simply not possible with the Arduino and Wire.

Although I have found (albeit precious few) examples of people having some success with this and Arduino and Wire. Here is one example, scroll down to the bottom post:
https://raspberrypi.stackexchange.com/q ... ng-the-i2c

Has anyone had any success here?

User avatar
OutoftheBOTS
Posts: 711
Joined: Tue Aug 01, 2017 10:06 am

Re: I2C smbus2 block data

Tue Sep 12, 2017 8:41 pm

First I would check that your wires haven't come loose as I had problems with I2C throwing errors because of cheap dupont wires not getting good enough connection for I2C coms.

I have just looked at your Ardunio code a little closer and notice that it should be printing to the console what it is seeing from its end. does this line of code on the Ardunio execute "Serial.println("We got to hole 1");"

I would also suggest to put "Serial.println("number);" just after "number = Wire.read();" and also put "Serial.println("We r sending dtata");" at the very beginning of sendData() routine so that you know that the Ardunio is trying to send data.

Quercus47
Posts: 8
Joined: Sat Sep 09, 2017 7:27 pm

Re: I2C smbus2 block data

Wed Sep 13, 2017 1:22 am

OutoftheBOTS wrote:
Tue Sep 12, 2017 8:41 pm
... it should be printing to the console what it is seeing from its end. does this line of code on the Ardunio execute "Serial.println("We got to hole 1");"
Do you mean that it should print to the console for purposes of debugging, or because it is somehow related to the i2c process? I'm assuming for debugging, and I did have some of that which I stripped out before posting here to reduce the bloat. The code does print to the console when needed.

Thanks.

User avatar
OutoftheBOTS
Posts: 711
Joined: Tue Aug 01, 2017 10:06 am

Re: I2C smbus2 block data

Wed Sep 13, 2017 2:26 am

Yes for debugging to make sure that everything at the Ardunio end is working fine and you can pin point where the problem is.

At the moment you have code running on the Ardunio and code running on the RPi and not sure which one is causing the problem. At the very least to ensure that the Ardunio is calling the sendData() function by printing this fact to the screen.

User avatar
OutoftheBOTS
Posts: 711
Joined: Tue Aug 01, 2017 10:06 am

Re: I2C smbus2 block data

Wed Sep 13, 2017 2:43 am

Also maybe for the moment even comment out the "writeNumber(numBytes)" from the "readBunchOfData(numBytes) function as what your doing at the moment this isn't needed as u have hard coded 4 bytes.

Quercus47
Posts: 8
Joined: Sat Sep 09, 2017 7:27 pm

Re: I2C smbus2 block data

Fri Sep 15, 2017 11:57 pm

Let me step back for a moment because right now, I'm skeptical that what I'm trying to do is possible... I've read many posts on using I2C on the RPi and between the RPi and Arduino. Several imply that the RPi has fundamental limitations in its ability to implement I2C, such as no support for second start bit. See viewtopic.php?f=44&t=15840.

The example code I've been able to find for using read_i2c_block_data is either for situations not applicable to the RPi/Arduino, or I've not been able to duplicate its success. E.g. the following did not work for me https://raspberrypi.stackexchange.com/q ... ng-the-i2c. I've seen some posts where folks have bit-banged the protocol or dug deep into other packages or low-level commands, but that is above my head to replicate. Please note that I have successfully used write_block_data to send multiple byte packages from the Pi to the Arduino, and also successfully use read_byte and write_byte; it is just read_block_data that not working.

In other words, after spending several days on this, I have yet to see an example, document, tutorial, or code from a successful project, that I can replicate myself, on how to read block data between the RPi and Arduino using I2C.

So... has anyone successfully used read_block_data or its equivalent implementation in smbus, smbus2 or a similar wrapper package to send multi-byte data from the Arduino to the Pi? If so, I would appreciate hearing about your success.

Many thanks.

User avatar
OutoftheBOTS
Posts: 711
Joined: Tue Aug 01, 2017 10:06 am

Re: I2C smbus2 block data

Sat Sep 16, 2017 2:34 am

I have not used it to for coms with Arduniuo but an every interested to know if there is problems in this (as was planning on using I2C coms doing some projects that use RPi as master controller with Arduino for embedded processes).

I have used read_i2c_block_data on a number of occasion to read blocks of data from chips though (a number of different sensors chips and pixy cam).

If it does work fine for other chips but not for Ardunio this would imply that the Ardunio library isn't a standard I2C protocol.

RinksCustoms
Posts: 5
Joined: Sun Mar 26, 2017 9:08 pm

Re: I2C smbus2 block data

Wed Nov 08, 2017 3:05 am

I'm working on the same problem/issue. I had it writing back to the Pi, but it only worked a few times and just spat out garbage (and it was different every time). I'm trying to sort out a way to send 5 'int' from atmega 328p to pi3 over i2c, never thought it would be this difficult :( Now I have an 8ch constant current PCB handmade (14 x 16 cm) drilled (416 holes/vias) and over 200 components ready to go and now the two "hearts" of the system can't communicate back to the brain (pi) but can receive 5 bytes just fine from pi. I have given up on Wire to send multi-byte and even single byte back to pi. Even tried a FOR loop iterating through 12 bytes representing the 5 analog readings, the slave address and a digital input monitoring the output of a mosfet for a water pump.
Currently trying to find info on having the pi also as a slave so that I'm just sending multi-byte transfers between "slaves".

User avatar
OutoftheBOTS
Posts: 711
Joined: Tue Aug 01, 2017 10:06 am

Re: I2C smbus2 block data

Wed Nov 08, 2017 8:28 pm

I was reading on an Ardunuo forum that the internal pullup resistors on the Ardunio( something like 50k) are very big and this means there is problems with 3.3v systems being able to pull them up quick enough because of the charging time of the capacitor with the low current and from the low voltage with high resistor.

U could try to disable the internal pullup resistor on the ardunio and wiring in a 5k to 10k resistor.

Please let me know if this works as I plan to be doing the same thing at some stage.

Return to “Python”