Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 12 of 12

Thread: I2C pains with Sensirion Pressure Sensor SDP810

  1. #1
    Junior Member
    Join Date
    Nov 2017
    Posts
    6

    I2C pains with Sensirion Pressure Sensor SDP810

    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/Sensi...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);
       }
      
    }

  2. #2
    Junior Member
    Join Date
    Nov 2017
    Posts
    6
    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);
       }

  3. #3
    Senior Member manitou's Avatar
    Join Date
    Jan 2013
    Posts
    1,265
    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 by manitou; 11-14-2017 at 05:44 PM.

  4. #4
    Hi

    maybe https://github.com/PX4/Firmware/tree...sdp3x_airspeed might be interesting for you.

    It is for an SPD33. At first glance a close cousin of SPD810.

  5. #5
    Junior Member
    Join Date
    Nov 2017
    Posts
    6
    Quote Originally Posted by manitou View Post
    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.

  6. #6
    Senior Member manitou's Avatar
    Join Date
    Jan 2013
    Posts
    1,265
    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.

  7. #7
    Junior Member
    Join Date
    Nov 2017
    Posts
    6
    Quote Originally Posted by manitou View Post
    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!

  8. #8
    Senior Member manitou's Avatar
    Join Date
    Jan 2013
    Posts
    1,265
    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 by manitou; 11-17-2017 at 12:20 PM.

  9. #9
    Junior Member
    Join Date
    Nov 2017
    Posts
    6
    Quote Originally Posted by manitou View Post
    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.

  10. #10
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    16,287
    Quote Originally Posted by eriktru View Post
    Code:
      long combined;  //32 bit variable to store the msb and lsb
    This should probably be "int16_t" rather than "long".

  11. #11
    Junior Member
    Join Date
    Nov 2017
    Posts
    6
    Quote Originally Posted by PaulStoffregen View Post
    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

  12. #12
    Senior Member+ MichaelMeissner's Avatar
    Join Date
    Nov 2012
    Location
    Ayer Massachussetts
    Posts
    2,573

    Cool

    Quote Originally Posted by eriktru View Post
    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);

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •