11

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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Aeolus
  • 996
  • 1
  • 8
  • 22
  • Can you show hardware schematics or explain physical setup please. In short have you run the Pull Up Resistor calculations? – Paul Sullivan Sep 23 '18 at 21:52

4 Answers4

4

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

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
domen
  • 1,819
  • 12
  • 19
  • Thanks for the tips. Unfortunately my oscilloscope is broken. I am fairly new to I2C, but this isn't my first time using it. The one thing I could find was that the raspberry pi doesn't natively support clock stretching and the sensor does. Could this cause the problem I am seeing? – Aeolus Sep 10 '18 at 11:03
  • Could be. A good example when a scope comes very handy :) You could try bitbanged i2c (gpio-i2c?) which seems to support clock stretching (I guess this fits into "replace any HW components" in answer ;) ). – domen Sep 10 '18 at 12:14
  • You can attach a second RPi running https://github.com/richardghirst/Panalyzer to check if that's what causing the problem. – rbanffy Sep 17 '18 at 08:27
1

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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
0

Using SMBus for this I²C device is not right.

You should compare the SMBus 6.5.7 Block Read (which is read_i2c_block_data, if I am right) to your device datasheet 1.3.4 Get data ready status. They are different as the SMBus sends the command byte.

The device interface looks simple enough for you not to need a library. Just open the i2c-dev, do the I2C_SLAVE ioctl to set address, and then write of two bytes and read of three bytes. The kernel I²C device interface document tells the details.

I2C_SLAVE=0x703
with open('/dev/i2c-1', 'r+b') as f:
    fcntl.ioctl(f, I2C_SLAVE, 0x61)
    f.write(b'\2\2')
    data = f.read(3)

To get the ioctl I2C_SLAVE value, compile a small C program to print it.

#include <stdio.h>
#include <linux/i2c-dev.h>

int main() { printf("%#x\n", I2C_SLAVE); return 0; }

Something like cc file.c && ./a.out to see the value.

The datasheet does say in 1.1 "the master has to support clock stretching." Without clock stretching you must be prepared for errors. There are ways to have clock stretching on Raspberry Pi using i2c-gpio. I'm sorry I did not have time to go through the details here, but Google finds at least some instructions.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Marko Kohtala
  • 744
  • 6
  • 16
0

It could be a pull-up resistor problem.

See I²C Bus Pull-up Resistor Calculation

Pull-up Resistor Calculation

A strong pull-up (small resistor) prevents the I²C pin on an IC from being able to drive low. The VOL level that can be read as a valid logical low by the input buffers of an IC determines the minimum pull-up resistance [RP (min)]. RP (min) is a function of VCC, VOL (max), and IOL.

Rp(min) = (VCC - VOL(max)) / IOL

The maximum pull-up resistance is limited by the bus capacitance (Cb) due to I²C standard rise time specifications. If the pull-up resistor value is too high, the I²C line may not rise to a logical high before it is pulled low. The response of an RC circuit to a voltage step of amplitude VCC, starting at time t = 0 is characterized by the time constant RC.

Community
  • 1
  • 1
Paul Sullivan
  • 2,865
  • 2
  • 19
  • 25
  • It seems coincidental that it is related to 00 or 01 (only a small problem could lead to a 0 becoming a 1 and vice versa) and 50% of the time seems like chance to me – Paul Sullivan Sep 23 '18 at 22:01