Sending specific read and write bits over I2C (CPS121 Barometer)

Hi,

Attempting to issue a measurement request and data request from a Consensic CPS121 barometer, over its I2C interface. Here is the Datasheet, and an example of the data request format:

The somewhat unusual (to me) format of the host sending bytes then receiving bytes (including the write and read bits on the host side) seems to be causing issues with Arduino’s implementation of the Wire library.

My implementation is below, which produces the following output, which definitely doesn’t work:

2 0 0 0 0
//Measurement Request
Wire.beginTransmission(Addr);
  Wire.write(0x6C);
  Wire.write(0x30);
  Wire.write(0xA);
  Wire.endTransmission();

  delay(500);


//Get Data Request
 Wire.beginTransmission(Addr); 
  Wire.write(0x6C);
 Wire.write(0x06);
  Wire.write(0x6C);

  // Request 5 bytes of data    
  Wire.requestFrom(Addr, 5);

  if(Wire.available()==5) {
    for(int i = 0; i < 5; i++) {
      Serial.print(Wire.read());
      Serial.print("      ");
    }
    Serial.println();

    Wire.endTransmission(true);
  }

Any ideas as to what I need to do for this odd communication method?

Thanks

have a looks the this example:

based on that IMHO, your code should look something like this for the data request in your post:

(compiles, not tested!)

#include <Wire.h>

#define Addr 0x6C //I2C address of CPS121 barometer
void setup() {
  Serial.begin(115200);
  Wire.begin();                // join i2c bus (address optional for master)
}

void loop() {
  // step 1: instruct sensor to return a particular reading
  Wire.beginTransmission(Addr); //transmit to device
  Wire.write(byte(0x06));      // sets register pointer to register (0x06)
  Wire.endTransmission();      // stop transmitting

  // step 2: wait for readings to happen (delay might be optional)
  delay(70);

  // step 3: request reading from sensor
  Wire.requestFrom(Addr, 5);    // request 5 bytes from slave device (3 pressure and 2 temperature data)

  // step 4: receive reading from sensor
  while (Wire.available() < 5); //wait till all 5 bytes are received;

  //step 5: read received bytes
  uint32_t  pressure_reading = 0;
  uint16_t  temperature_reading = 0;
  pressure_reading = Wire.read(); // receive high byte (overwrites previous reading)
  pressure_reading = pressure_reading  << 8;    // shift high byte to be high 8 bits
  pressure_reading  |= Wire.read(); // receive low byte as lower 8 bits
  pressure_reading = pressure_reading  << 8;    // shift high byte to be high 8 bits
  pressure_reading  |= Wire.read(); // receive low byte as lower 8 bits
  Serial.print("pressure: ");   // print the reading
  Serial.println(pressure_reading, DEC);  // print the reading
  
  temperature_reading = Wire.read(); // receive high byte (overwrites previous reading)
  temperature_reading = temperature_reading  << 8;    // shift high byte to be high 8 bits
  temperature_reading  |= Wire.read(); // receive low byte as lower 8 bits
  Serial.print("temperature: ");   // print the reading
  Serial.println(temperature_reading, DEC);

  delay(1000);                  // wait a bit since people have to read the output :)
}

hope that helps…

Unfortunately this still just returns nothing but 0s. The calls to endTransmission return 0, which I believe represents an ACK message?

When you want to measure the baromic pressure, then you can buy a sensor that has been tested, on a module to make it work well, with a tutorial and with a library: Adafruit BME280 I2C or SPI Temperature Humidity Pressure Sensor [STEMMA QT] : ID 2652 : $14.95 : Adafruit Industries, Unique & fun DIY electronics and kits.

Everyone can buy random things from aliexpress.

That said, it is challenge to make it work.
Did you read the datasheet ? It needs to be taken out of the sleep mode.

#include <Wire.h>

const int Addr = 0x6C;

void setup()
{
 Serial.begin(115200);
 Serial.println( "The sketch has started");

 Wire.begin();

 // ------------------------------------------
 // Test if the sensor can be seen at its address.
 // ------------------------------------------
 Wire.beginTransmission(Addr);
 int error = Wire.endTransmission();
 if( error == 0)
 {
   Serial.println( "The sensor is detected.");
 }
 else
 {
   Serial.println( "Error, no sensor found.");
 }
}

void loop()
{
 // ------------------------------------------
 // Wakeup the sensor and start measurement.
 // ------------------------------------------
 Wire.beginTransmission(Addr);
 Wire.write( 0x30);        // select register 0x30
 Wire.write( 0x0A);
 Wire.endTransmission();
 delay( 5);          // wait for measurement according to datasheet.

 // ------------------------------------------
 // Read the data.
 // ------------------------------------------
 Wire.beginTransmission(Addr);
 Wire.write( 0x06);     // select register 0x06
 Wire.endTransmission( false);   // repeated start

 Wire.requestFrom(Addr, 5);    // request 5 bytes from slave device (3 pressure and 2 temperature data)

 //step 5: read received bytes
 uint32_t  pressure_reading = 0;
 ...
}

In the datasheet I see a “repeated start”, so I have added that.

The datasheet is not as hard to understand as a BME280, so I hope you see some numbers with this small sketch.

Please don’t do this:while (Wire.available() < 5);That is not how the Wire library works.
Also, don’t add a Wire.endTransmission() after a Wire.requestFrom().

Unfortunately this is not the type of scenario where I cant just stick an adafruit product on an Arduino and call it a day. Otherwise, I would not have selected an obscure smd only LGA package.

The fact I have a imagery from the datasheet in my original post implies to me at least that I have read the datasheet. My original code even includes the request to make a measurement.

The code is now working, the element I was missing was the false parameter when ending the transmission before requesting the 5 bytes.