Search code examples
pythonarduinoraspberry-pii2csmbus

Difference I2C Sensor Reading Raspberry Pi and Arduino


I am using the Sensirion SFM3300 flow sensor and can read the correct values with the Arduino with the following code (I2C):

#include <Wire.h>

void setup() {
  // put your setup code here, to run once:
  Wire.begin();
  Serial.begin(115200);
  Wire.beginTransmission(byte(0x40));
  Wire.write(byte(0x10));
  Wire.write(byte(0x00));
  Wire.endTransmission();
}

void loop() {
  // put your main code here, to run repeatedly:
  delay(100);
  Wire.requestFrom(0x40,2);
  uint16_t a = Wire.read();
  uint8_t  b = Wire.read();
  a = (a<<8) | b;
  float flow = ((float)a - 32768) / 120;
  Serial.println(flow);
}

But using the Raspberry Pi I have written the nearly the same code, hoping that it also will works. This is the code:

from smbus2 import SMBus
import time
import numpy as np

address=0x40
bus = SMBus(1)

def write(value):
    bus.write_byte(address,value)

write(0x10)
write(0x00)

while True:
    time.sleep(0.1)
    a = np.uint16(bus.read_byte(0x40))
    b = np.uint8(bus.read_byte(0x40))
    a = (a<<8) | b
    flow = (float(a)-32768)/120
    print(flow)

The code really looks the same, but I only get -273,06666666666 as a return value. Does somebody knows where are the differences between Raspberry Pi and Arduino I2C and can help me to get the right values on the Pi?


Solution

  • I found a working solution. It would be nice if a I2C-expert could tell me why the following code is working instead of the python code above.

    from fcntl import ioctl
    from struct import unpack
    from smbus import SMBus
    
    address = 0x40
    
    SMBus(1).write_byte_data(address,16,0)
    i2c = open("/dev/i2c-1", "rb", buffering=0)
    ioctl(i2c,0x0703,address)
    i2c.read(3)
    
    d0,d1,c = unpack('BBB', i2c.read(3))
    d = d0 << 8 | d1
    a = (float(d)-32768.)/120
    print(a)