I2C pains with Sensirion Pressure Sensor SDP810

Status
Not open for further replies.

eriktru

Member
Hi all,

Long time lurker but first time poster here (be gentle ;) ). I am trying to interface my Teensy with a Sensirion Pressure Sensor SDP810 (datasheet at: http://www.mouser.com/ds/2/682/Sensirion_01102017_1-101551-01-1079500.pdf ).

I have wired it up to my Teensy 3.2 as expected, using 4.7k Ohms for pull up resistors. This is where the issues start. My code is DOA. There is nothing on the Serial Monitor. It compiles, uploads and then, nothing. Thinking it may be due to the wiring, I used the nifty I2C Scanner code from the Arduino website to see if the sensor is indeed being recognised. It was, at the same address as mentioned in the above datasheet (0x25).

I have combed through some other threads on getting I2C to work, but to no avail. If anyone can point me in the right direction, I would be most obliged. Thanks!

Code:
#include "Wire.h"

void setup() {
  Wire.begin();
  Serial.begin(9600);

}

void loop() {
  byte lobyte; 
  byte hibyte;
  
  Wire.beginTransmission(0x25); //address of the SDP sensor
  Wire.write(0x361E);                //command to request data from the sensor, on page 7 of the datasheet
  Wire.endTransmission();
  
  
   Wire.requestFrom(0x25, 2);   // contents of your first two registers as they have the differential pressure data, page 7
   while(Wire.available() < 2 );  // check when there is data      
   {   
      delay(100);
      lobyte = Wire.read();       // read msb
      Serial.println(lobyte, DEC);
      hibyte = Wire.read();      // read lsb
      Serial.println(hibyte, DEC);

      delay(100);
   }
  
}
 
Edit 1.

I changed my while() loop and now I get a stream of 255 on new lines in the Serial Monitor. At least I get something! I still to figure out how to get the required data and bit shift it.

Code:
#include "Wire.h"

void setup() {
  Wire.begin();
  Serial.begin(9600);

}

void loop() {
  byte lobyte; 
  byte hibyte;
  
  Wire.beginTransmission(0x25); //address of the SDP sensor
  Wire.write(0x361E);                //command to request data from the sensor, on page 7 of the datasheet
  Wire.endTransmission();  
  
  Wire.requestFrom(0x25, 2);   // contents of your first two registers
  delay(8);                              //first measurement is available after 8ms, on page 7
  while(Wire.available());         // Check for data from slave
   {   
      
      lobyte = Wire.read();       // read msb
      Serial.println(lobyte);
      hibyte = Wire.read();      // read lsb
      Serial.println(hibyte);

      delay(100);
   }
 
Your C coding of the while is visually misleading. the ";" in while(Wire.available()); terminates the while(), so the "{ }" just delimits a block of code (not part of the while). So I would re-write the sketch in post 1 as
Code:
   while(Wire.available() < 2 ) {  // check when there is data      
      delay(100);
      lobyte = Wire.read();       // read msb
      Serial.println(lobyte, DEC);
      hibyte = Wire.read();      // read lsb
      Serial.println(hibyte, DEC);

      delay(100);
   }

The datasheet seems to suggest that there is a CRC byte following the 2 data bytes, so you might need to read 3 bytes. Also command 0x361e appears to request continuous reading til a stop command is sent . Also the datasheet says the high order byte of the command should be sent first, so you might try Wire.write(0x36); Wire.write(0x1E);
 
Last edited:
Your C coding of the while is visually misleading. the ";" in while(Wire.available()); terminates the while(), so the "{ }" just delimits a block of code (not part of the while). So I would re-write the sketch in post 1 as
:
:
The datasheet seems to suggest that there is a CRC byte following the 2 data bytes, so you might need to read 3 bytes. Also command 0x361e appears to request continuous reading til a stop command is sent . Also the datasheet says the high order byte of the command should be sent first, so you might try Wire.write(0x36); Wire.write(0x1E);

Thank you for your detailed reply, it is most appreciated. And well spotted! Rather surprisingly, I was getting something with the ";" in place, without it, I get nothing on the Serial Monitor. Regarding your second suggestion of writing 0x36 followed by 0x1E, that did not appear to have any effect on the readings.

I made some changes to the code, and now I seem to be getting differential pressure data, albeit with some other information which should not be there. I got rid of the "while(Wire.available()" as the sensor is continuously sending data. I made a new 32bit variable called "combine" to store byte1 (msb) and byte2(lsb). I tried to do some bit-shifting however it does not appear to be correct based on the results I am getting.

Code:
#include "Wire.h"

void setup() {
  Wire.begin();
  Serial.begin(9600);

}

void loop() {
  long combined;  //32 bit variable to store the msb and lsb
  byte msb;    
  byte lsb;
  
  Wire.beginTransmission(0x25); 
  Wire.write(0x361E);
  Wire.endTransmission();
   
  Wire.requestFrom(0x25, 2);     // contents of your first two bytes
  delay(8);                               //first measurement is available after 8ms, on page 7
  msb = Wire.read();               //byte1 is msb
  lsb = Wire.read();                //byte2 is lsb
  combined = msb;                //assign msb to combined variable
  combined << 8;                 //left shift msb by 8 bits 
  combined += lsb;              //add the lsb to the combined variable
  Serial.println(combined);   //print the differential pressure
  delay(500);
   
}


With this code, I get the following results in the Serial Monitor:
Code:
10
8
9
496
4
510
3
507
10
504
509
1
3
4
3
3
508
499
23
:
:

I feel that the differential pressure readings are the one or two digit numbers, whereas the 499, 508 etc are coming from somewhere else as the sensor is just lying on the table and there are no/minimal air drafts present.

As you may have seen from the picture of the sensor in the datasheet, it has two nozzles. I put two pieces of rubber tubing on both. If I blow just into one nozzle I get 128 on the monitor, if I blow just into the other one, I get 382. So, this leads me to think I am getting some pressure data.

Questions now are if I am actually getting the msb as byte1 from the sensor (can the sensor send something in reverse order i.e., starting from byte9)? I am pretty sure I may have bungled up the bit-shifting?

Thank you.
 
I don't have the device, so i can only guess as to what's happening. To figure out what's going on, you should just print out each byte you receive (in HEX). Maybe also print out value of Wire.available(). As noted before, data sheet says device returns 2 data bytes and 1 CRC byte, you need to read/discard that CRC byte. Looking at Wire.cpp, Wire.write(0x361E); sends only one byte, so you need to do Wire.write(0x36); Wire.write(0x1E); (maybe reverse the order if it's not working). Also that command starts continuous mode as I read the data sheet. So you only need to issue those 2 command bytes once, maybe do it in setup() ... good luck.
 
I don't have the device, so i can only guess as to what's happening. To figure out what's going on, you should just print out each byte you receive (in HEX). Maybe also print out value of Wire.available(). As noted before, data sheet says device returns 2 data bytes and 1 CRC byte, you need to read/discard that CRC byte. Looking at Wire.cpp, Wire.write(0x361E); sends only one byte, so you need to do Wire.write(0x36); Wire.write(0x1E); (maybe reverse the order if it's not working). Also that command starts continuous mode as I read the data sheet. So you only need to issue those 2 command bytes once, maybe do it in setup() ... good luck.

Thanks again for your very prompt and insightful answer. I will make the changes. I think you're right that I need to do something with the CRC.

I am curious about
As noted before, data sheet says device returns 2 data bytes and 1 CRC byte, you need to read/discard that CRC byte.
Why do I have to read/disregard this particular CRC? As I am not reading the other data and their accompanying CRC, why is this CRC important? Just for my knowledge (or lack thereof...).

Many thanks!
 
you're right the requestFrom() will generate the NACK/STOP so you don't need to worry about the CRC and following data bytes. it's been a while since i've looked at I2C protocol details. experiment and print. maybe read the product ID bytes ....

and your bit shifting is broken (hence also print byte values in HEX)
Code:
  combined = msb<<8;                //assign msb to combined variable
  combined |= lsb;              //add the lsb to the combined variable

another related library (with 2 byte commands) https://playground.arduino.cc/Code/Sensirion
but no support for SDP810
 
Last edited:
you're right the requestFrom() will generate the NACK/STOP so you don't need to worry about the CRC and following data bytes. it's been a while since i've looked at I2C protocol details. experiment and print. maybe read the product ID bytes ....

and your bit shifting is broken (hence also print byte values in HEX)
Code:
  combined = msb<<8;                //assign msb to combined variable
  combined |= lsb;              //add the lsb to the combined variable

another related library (with 2 byte commands) https://playground.arduino.cc/Code/Sensirion
but no support for SDP810

Thank you very much for your suggestions! That OR was the key. Furthermore, the results were in Two's complement so I had to use signed and unsigned variables to get the right values. Thanks again. Your help was invaluable.
 
This should probably be "int16_t" rather than "long".

Precisely. I found some similar code for the Sensirion Liquid Flow Sensor, and this is what they used.

Code:
uint16_t raw_sensor_value;        //raw sensor value is Two's complement
double signed_sensor_value;       //sensor value with signs
 
Precisely. I found some similar code for the Sensirion Liquid Flow Sensor, and this is what they used.

Code:
uint16_t raw_sensor_value;        //raw sensor value is Two's complement
double signed_sensor_value;       //sensor value with signs

Depending on what your code does (i.e. whether it needs the extra precision or it needs to be fast), it may make sense to use float instead of double. On the Teensy 3.5/3.6, there is hardware support for single precision floating point, but double precision floating point must be emulated in software. On the Teensy 3.2/LC, both floating point formats are emulated, but the float emulatorion should be faster.

Note, due to the Arduino AVR platforms mapping double into float and the Teensy 3.5/3.6 having hardware single precision floating point support, the GCC compiler is told to assume that all floating point constants are single precision. This means that for:

Code:
    double a = 0.1;
    double b = 1.0 / 10.0;

That a and b will have different values, due to 0.1 being converted to ((float)0.1), and then converted back to double, losing the bottom bits. The way to do it is to declare the constant to be long double and then optionally convert it back to double:

Code:
    double c = ((double)0.1L);
 
I just landed here having the exact same problem interfacing a Teensy 3.2 and the Sensirion SDP810.
Would it be possible for you to post the working code in its full?

I spent the last hour trying variations of the bits above, but I cannot get it to work properly (I am in no way an expert in embedded programming).
The help would be much appreciated!

Best regards
 
Status
Not open for further replies.
Back
Top