Sensirion / arduino-i2c-scd4x

Arduino library for Sensirion SCD4x sensors
BSD 3-Clause "New" or "Revised" License
48 stars 19 forks source link

Library error in Forced Recalibration #11

Closed dduehren closed 2 years ago

dduehren commented 2 years ago

I keep getting "Not enough data received" error when I execute a forced recalibration. I believe it's because the wrong number of bytes is expected in a the response. The library expects 5 but the response is only 3.

The write command is 5 bytes : 2 for command, 2 for data, 1 for crc The response command is 3 bytes: 2 for data, 1 for crc

dduehren commented 2 years ago

Changing the value to 3 in the .cpp file didn't fix the problem. So please look into why this function always reports Not enough data received.

psachs commented 2 years ago

Hi @dduehren

The issue is not due to the driver implementation. The performForcedCalibration command is receiving 3 bytes as expected, eventhough the buffer is 5 bytes.

"Not enough data received" is mostly triggered due to unstable connection or power supply since the underlying I2C library (Wire) can't decode the data.

Please also note to do force re-calibration not during the measurement. The following example shows how I tested force re-calibration on a Arduino Nano.


    // do a force recalibration
    uint16_t frc_correction;
    error = scd4x.performForcedRecalibration(700, frc_correction);
    if (error) {
        Serial.print("Error trying to execute performForcedRecalibration(): ");
        errorToString(error, errorMessage, 256);
        Serial.println(errorMessage);
    } else if (frc_correction == 0xffff) {
        Serial.println("Forced recalibration failed.");
    } else {
        Serial.print("FRC correction: ");
        Serial.println((int16_t)frc_correction - 0x8000);
    }
dduehren commented 2 years ago

First, thanks for replying. I will try to check the i2c power, though I doubt very much that it's the problem because the other sensors work on it. Does the scd40 take more power than the scd30? The data sheet says it's lower power. And yes I know that it has to be out of measurement mode for at least 30 seconds - I've followed the data sheet carefully. And just for the record, here is my code that's running on an 8266 <// must be preceeded by MeasOnOff(off) command - just once for a set of parameters & commands. P.S. what are the escape characters you used to get nice formatting? The `` don't work at least in this browser. void sensors::setCO2frc(uint16_t frcCO2){ //sets the current CO2 level to do Forced Calibration of SCDxx uint16_t frcCorrection; if(sensorInit&SCD30InitBit){ airSensor.setForcedRecalibrationFactor(frcCO2); if (airSensor.getForcedRecalibration(&frcCorrection) == true){ Debug.print(DBG_INFO, F("frcCorrection %d 0xffff indicates failure"), frcCorrection);
} } if (sensorInit&SCD40InitBit) { Debug.print(DBG_INFO, F("scd40 FRC function")); error = scd4x.performForcedRecalibration(frcCO2,frcCorrection); if (error){ scderrorMsg(error, 11); } } else { // Convert value to CO2 ppm with: value - 0x8000 Debug.print(DBG_INFO, F("frcCorrection %d 0xffff indicates failure"), frcCorrection-0x8000); } }

psachs commented 2 years ago

Just to clarify. The problem is not due to insufficient power supply but unstable connection with too much noise. You can fight that by e.g. using a lower the I2C frequency or ensure better connection of the sensor (e.g. bad cable, bad soldering points, ...)

The SCD40 takes less power then the SCD30 and should work on a 8266.

btw for code formatting you find a button "<>" on the top bar which will insert the right character (use three of them on a separate line as start and end of a code block)

dduehren commented 2 years ago

At some point I will hook up a scope to see what's going on with the command. I put it on a line with more power and got the same result. I guess I could also look at the value of my pull-up resistors on the i2c lines. What speed do you recommend?

As for formatting, when I click on the <> symbol, I get two single quotes; But putting code between them or between two of them does nothing. You're method worked pretty well but no color. Thanks. There should be better documentation on this.

// must be preceeded by MeasOnOff(off) command - just once for a set of parameters & commands
void sensors::setCO2frc(uint16_t frcCO2){
    //sets the current CO2 level to do Forced Calibration of SCDxx
    uint16_t frcCorrection;
    if(sensorInit&SCD30InitBit){
        airSensor.setForcedRecalibrationFactor(frcCO2);
        if (airSensor.getForcedRecalibration(&frcCorrection) == true){
         Debug.print(DBG_INFO, F("frcCorrection %d 0xffff indicates failure"), frcCorrection);            
            }
        }
    if (sensorInit&SCD40InitBit) {
        Debug.print(DBG_INFO, F("scd40 FRC function"));
       error = scd4x.performForcedRecalibration(frcCO2,frcCorrection);
     if (error){
        scderrorMsg(error, 11);
          }
        } else {
         // Convert value to CO2 ppm with: value - 0x8000
         Debug.print(DBG_INFO, F("frcCorrection %d 0xffff indicates failure"), frcCorrection-0x8000);
        }
}
psachs commented 2 years ago

To get coloring you have to specify the programming language when starting a block e.g. for c++ ```cpp It's a bit hard to explain as github will just interpret the formatting if written down correctly.

Default I2C frequency should not be higher than 100kHz. If you have a longer cable or a lot of noise you can try to lower it to eg. half of that. You can also lower the pull-up resistors. This will help to get a faster rise in the I2C signal, however I would strongly advice you to not go lower then 2kOhm. Else the lines might draw more then 3mA. Please also note that ESP8266 development boards have built-in pull-up resistors for the built-in i2c pins so you don't need additional ones.

I don't think the power source is the problem (as you tested it).

Extent421 commented 2 years ago

I just ran into this, also with an ESP8266. In my case it was because using the ESP in a mesh network, and attempting to call the scd library from inside a callback from a network event. This meant the call was happening outside of loop() context, and delay() was not functioning (immediately returns, instead of actually doing the delay) Making sure that all of my calls to the library happen within loop resolves it.