Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

I²C bytes received out of order using Raspberry Pi Python SMBus

I am setting up a Raspberry Pi to record data (CO2, humidity, and temperature) from the Sensirion SCD30 sensor. My code is in Python 3, using the SMBus library to communicate with the sensor over the I²C pins in the Raspberry Pi's GPIO. There is a command to determine whether the sensor is ready to send data.

Link to SCD30 interface datasheet

Link to SCD30 library for Arduino by Sparkfun

The value 0x0202 is sent over I²C, and three bytes of data are returned:

0x00 0x00 0x81 for data not ready
0x00 0x01 0xB0 for data ready

The first two bytes are the MSB and the LSB of the data ready value. Combined properly, they should be 0x0000 and 0x0001.

The third byte is the CRC8 of the first two bytes. This is calculated with a polynomial of 0x31 and an initialization of 0xFF.

About half the time, the bytes are sent in the wrong order. Instead of MSB LSB CRC it is sent MSB CRC LSB. For example, if the data is ready it might send 0x00, 0xB0, 0x01 instead of 0x00, 0x01, 0xB0. I can't figure out why this is happening, and I'm concerned there is some corruption or issues in sending data. I could change the code to recognize if the CRC is the second byte, but I would like to find the underlying problem.

I am sending and receiving I²C data using the smbus library. This is my code to send commands and read data:

bus = smbus.SMBus(0)
I2C_ADDRESS = 0x61

def sendCommand(self, cmd):  # Sends a 2 byte command (cmd)
    data = [0]*2
    data[0] = cmd >> 8  # Splits 2 byte command into MSB and LSB
    data[1] = cmd & 0xFF
    bus.write_i2c_block_data(I2C_ADDRESS, data[0], data[1:])

def readRegister(self, reg, length):  # Sends 2 byte command (reg) and receives (length) bytes
    sendCommand(reg)
    data = bus.read_i2c_block_data(I2C_ADDRESS, 0, length)
    return data

For the example I gave above, I would run the following code:

ready = readRegister(0x0202, 3)  # Returns a list of 3 bytes
print(ready)

And it would return a list of the three bytes demonstrated above.

like image 589
Aeolus Avatar asked Sep 08 '18 15:09

Aeolus


2 Answers

The SMBus library is not right, as the SCD30 requires longer I²C commands than the Linux i2c-dev library provides.

We are successfully using pigpiod for talking via Python to the sensor. Our code for the SCD30 and install instructions (as well as solutions for the clock stretching issue) can be found here on GitHub.

like image 105
Michael Maier Avatar answered Oct 20 '22 23:10

Michael Maier


What sort of tools and skills have you got?

(My first reaction was to search for SCD30 errata, but I can't find any, nor does quick web search reveal any similar problems.)

If you have an oscilloscope or logical analyser, look at SCL and SDA, and confirm the problem is on Raspberry Pi (could be on the sensor as well).

Can you replace any hardware components of the setup - just to eliminate the odd chance of something being faulty.

Can you rewrite the code in C (using /dev/i2c-x), and see if the problem still persists - this would either tell you problem is either in the kernel driver for the I²C master, wiring, SCD30 chip or in library smbus or other software that sits between your piece of code and the kernel driver.

Good luck

like image 38
domen Avatar answered Oct 20 '22 23:10

domen