tabroughton
Posts: 1
Joined: Tue Dec 03, 2013 9:58 pm

i2c can read byte but not block (smbus read_i2c_block_data not working)

Mon Jan 22, 2018 1:11 pm

I have an arduino (Atmega328) as slave connected to a pi zero w (running Raspbian stretch lite) as master via i2c.

I'm sending a block of data using the built in Wire library on the arduino and using smbus python (2.7) module.

The reading operations on the pi can read the first byte of what is sent by the arduino but not the block. I'm hoping somebody can tell me why - I've been trying all sorts for a while now and no luck. The simple examples below illustrate the issue:

Code: Select all

#include <Wire.h>

#define SLAVE_ADDRESS 0x04

byte b[4] = {99, 223, 244};

void sendData(){
    Wire.write(b, 3);
}

void setup(){
  Wire.begin(SLAVE_ADDRESS);
  Wire.onRequest(sendData);
}

void loop(){
  delay(1000);
}
(arduino - slavei2c.ino)

Code: Select all

#!/usr/bin/env python
import smbus
bus = smbus.SMBus(1)
address = 0x04

bus.write_i2c_block_data(address, 1, [0])
print bus.read_byte(address)
print bus.read_i2c_block_data(address, 1)
(pi - readi2c.py)

Code: Select all

$ python readi2c.py 
99
Traceback (most recent call last):
  File "readi2c.py", line 8, in <module>
    print bus.read_i2c_block_data(address, 1)
IOError: [Errno 121] Remote I/O error
(output)

The 99 printed in the output is the first byte of what the arduino sent using read_byte the error then comes when using read_i2c_block_data.

Just to check that device can I2c block read:

Code: Select all

$ i2cdetect -F 1
Functionalities implemented by /dev/i2c-1:
I2C                              yes
SMBus Quick Command              yes
SMBus Send Byte                  yes
SMBus Receive Byte               yes
SMBus Write Byte                 yes
SMBus Read Byte                  yes
SMBus Write Word                 yes
SMBus Read Word                  yes
SMBus Process Call               yes
SMBus Block Write                yes
SMBus Block Read                 no
SMBus Block Process Call         no
SMBus PEC                        yes
I2C Block Write                  yes
I2C Block Read                   yes

Please can anyone help?

User avatar
clicky
Posts: 535
Joined: Thu Oct 25, 2012 7:34 am

Re: i2c can read byte but not block (smbus read_i2c_block_data not working)

Mon Jan 22, 2018 9:52 pm

I am curious how to do the same. What I see is that you don't have onReceive as

Code: Select all

bus.write_i2c_block_data(address, [b]1[/b], [0])
you are sending local address (1) as well (also known as register address)

Communication really goes like this:
  • master sends address of i2c device (your case SLAVE_ADDRESS 0x04) shifted to right so it can add r/w bit
  • your slave wakes on it
  • master sends local address in the i2c device (in your case '1') which theoretically you should store somewhere as an, let's say, offset
  • then master switches from writing to reading (last bit in the i2c address now is going to be 1)
  • and then forces slave to return byte by byte.
So maybe what is missing on the 'wire' side is accepting read of that one byte? Also, did you try without first read of one byte - maybe that's what causes the problem? I would, really, do something like this:

Code: Select all

#include <Wire.h>

#define SLAVE_ADDRESS 0x04

byte off = 0;
byte b[4] = {99, 223, 244};

void sendData(){
    Wire.write(b[off++]);
}

void receiveOffset(int howMany){
     while (1 < Wire.available()) {
         off = Wire.read();
     }
     off = Wire.read();    // receive byte as an integer
}

void setup(){
  Wire.begin(SLAVE_ADDRESS);
  Wire.onRequest(sendData);
}

void loop(){
  delay(1000);
}
But take it with a pinch of salt as I didn't try any of it... We are doing something very similar as well (bet you're going to try to read HC SR04 or two :) ) - and can tell you more when I talk to guy who's coding for our Arduino.

Hope those help anyhow! Oh, BTW, did you sign to piwar's discord chat? If not - you can always go there and we can try something more in a real time tomorrow evening...

PS - i2c explained: http://www.ti.com/lit/an/slva704/slva704.pdf

bluetin
Posts: 1
Joined: Thu Mar 22, 2018 1:26 am

Re: i2c can read byte but not block (smbus read_i2c_block_data not working)

Thu Mar 22, 2018 1:49 am

I found a bit of time to look at this issue and here's the code I got working. Even when the code is correct, your error arises when you do not give the I2C time to settle after initialisation. It appears that adding some sleep time between the program start and calling the I2C read method, the program worked without errors.

In this Python solution, note that I'm using Python 3 and smbus2.

So here is the Arduino code:

Code: Select all

#include <Wire.h>

#define SLAVE_ADDRESS 0x08

byte b[4] = {99, 223, 244};
// data buffer
int data[9];

void receiveData(int byteCount){
  int counter = 0;
  while(Wire.available()) {
      data[counter] = Wire.read();
      Serial.print("Got data: ");
      Serial.println(data[counter]);
      counter ++;
  }
}

void sendData(){
    Wire.write(b, 4);
    Serial.println("data sent");
}

void setup(){
  Serial.begin(9600); // start serial for output
  Wire.begin(SLAVE_ADDRESS);
  Wire.onReceive(receiveData);
  Wire.onRequest(sendData);
  Serial.println("I2C Ready!");
}

void loop(){
  delay(1000);
}
And, here is the Python code:

Code: Select all

#!/usr/bin/env python
from time import sleep
import smbus2
bus = smbus2.SMBus(1)
address = 0x08

# Give the I2C device time to settle
sleep(2)

while 1:
	data = bus.read_i2c_block_data(address, 99, 3)
	print(data)
	sleep(0.5)
	break
	

fwperk
Posts: 1
Joined: Tue Feb 09, 2021 2:55 pm

Re: i2c can read byte but not block (smbus read_i2c_block_data not working)

Tue Feb 09, 2021 2:59 pm

Thank you for an example I can actually use, at long last.

Return to “Troubleshooting”