Skip to content

Commit

Permalink
0.1.4 add crc + error handling (#5)
Browse files Browse the repository at this point in the history
  • Loading branch information
RobTillaart authored Jul 1, 2021
1 parent 1c41269 commit f6e1042
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 34 deletions.
17 changes: 10 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ The SGP30 sensor has a fixed I2C address so only one sensor per I2C bus can be u
- **SGP30(TwoWire \*wire = &Wire)** Constructor with optional the Wire interface as parameter.
- **bool begin()** .
- **bool begin(sda, scl)** idem, for the ESP32 where one can choose the I2C pins.
- **bool isConnected()** checks if the address is visable on the I2C bus.
- **bool isConnected()** checks if the address is visible on the I2C bus.


### Meta
Expand All @@ -67,7 +67,7 @@ The SGP30 sensor has a fixed I2C address so only one sensor per I2C bus can be u

### Synchronous measurements

- **uint32_t lastMeasurement()** timestamp in millis of the last sync measurement made. This convenience function is useful to prevent reading the sensor too often.
- **uint32_t lastMeasurement()** timestamp in milliseconds of the last sync measurement made. This convenience function is useful to prevent reading the sensor too often.
- **bool measure(bool all = false)** if all == false, only the TVOC and CO2 are updated (slow due to blocking), if all == true, also the H2 and the Ethanol values are updated (even slower). Note the measurement is slow as there is an active blocking until the sensor is done. If the last measurement is less than a second ago, no measurement is made and the function returns false.


Expand All @@ -76,9 +76,9 @@ The SGP30 sensor has a fixed I2C address so only one sensor per I2C bus can be u
With the async interface, the user should control that reads are at least one second apart. The user should also take care not to mix up different requests. See examples.

- **void request()** sends a request to the sensor to read CO2 and TVOC.
- **bool read()** returns true if the last request is more than 12 millis ago the CO2 and TVOC are read and updated. Otherwise false is returned.
- **bool read()** returns true if the last request is more than 12 milliseconds ago the CO2 and TVOC are read and updated. Otherwise false is returned.
- **void requestRaw()** sends a request to the sensor to read H2 and Ethanol.
- **bool readRaw()** returns true if the last request is more than 25 millis ago the H2 and Ethanol are read and updated. Otherwise false is returned.
- **bool readRaw()** returns true if the last request is more than 25 milliseconds ago the H2 and Ethanol are read and updated. Otherwise false is returned.


### Get the data
Expand Down Expand Up @@ -127,6 +127,7 @@ use at own risk.
Since 0.1.2 the library has experimental support for H2 and Ethanol concentration in ppm.

One should use these functions more as a relative indication than as an absolute measurement as it is definitely not calibrated.
Runs with different temperature and humidity (different days) give very different values including overflow and infinity.

- **float getH2()** gets the H2 concentration. Units ppm.
- **float getEthanol()** gets the Ethanol concentration. Units ppm.
Expand All @@ -142,10 +143,12 @@ The used references are based upon (1) averaging raw data in outside air at 22°
## Todo

- redo **getID()**
- redo **lastError()**
- test test test ....
- CRC handling
- error handling


The CRC checking + error handling (since 0.1.4) adds around 330 bytes PROGMEM on an UNO.
There might be a need for a minimal class that only reads CO2 and TVOC, no baselines etc.
for the smallest platforms.


## Operational
Expand Down
100 changes: 79 additions & 21 deletions SGP30.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//
// FILE: SGP30.cpp
// AUTHOR: Rob Tillaart
// VERSION: 0.1.3
// VERSION: 0.1.4
// DATE: 2021-06-24
// PURPOSE: SGP30 library for Arduino
// URL: https://github.com/RobTillaart/SGP30
Expand All @@ -12,6 +12,7 @@
// 0.1.1 2021-06-26 add get/setBaseline ++
// 0.1.2 2021-06-26 experimental add units H2 + Ethanol
// 0.1.3 2021-06-26 add get/setTVOCbaseline()
// 0.1.4 2021-07-01 add CRC checking


#include "SGP30.h"
Expand Down Expand Up @@ -79,10 +80,18 @@ bool SGP30::getID()
{
_id[j++] = _wire->read();
_id[j++] = _wire->read();
_wire->read(); // skip crc
uint8_t crc = _wire->read();
uint16_t val = _id[j-2] * 256 + _id[j-1];
if (_CRC8(val) != crc)
{
_error = SGP30_ERROR_CRC;
return false;
}
}
_error = SGP30_OK;
return true;
}
_error = SGP30_ERROR_I2C;
return false;
}

Expand All @@ -97,9 +106,17 @@ uint16_t SGP30::getFeatureSet()
{
rv = _wire->read() << 8;
rv += _wire->read();
_wire->read(); // skip crc
uint8_t crc = _wire->read();
if (_CRC8(rv) != crc)
{
_error = SGP30_ERROR_CRC;
return rv;
}
_error = SGP30_OK;
return rv;
}
return rv;
_error = SGP30_ERROR_I2C;
return 0xFFFF;
}


Expand All @@ -120,9 +137,16 @@ bool SGP30::measureTest()
{
rv = _wire->read() << 8;
rv += _wire->read();
_wire->read(); // skip crc
uint8_t crc = _wire->read();
if (_CRC8(rv) != crc)
{
_error = SGP30_ERROR_CRC;
return false;
}
_error = SGP30_OK;
return rv == 0xD400;
}
_error = SGP30_ERROR_I2C;
return false;
}

Expand Down Expand Up @@ -166,19 +190,28 @@ bool SGP30::read()
if (millis() - _lastRequest < 13) return false; // P11
_lastRequest = 0;

// TODO error handling
// TODO CRC
if (_wire->requestFrom(_address, (uint8_t)6) != 6)
{
_error = SGP30_ERROR_I2C;
return false;
}
_co2 = _wire->read() << 8;
_co2 += _wire->read();
_wire->read(); // skip crc

uint8_t crc = _wire->read();
if (_CRC8(_co2) != crc)
{
_error = SGP30_ERROR_CRC;
return false;
}
_tvoc = _wire->read() << 8;
_tvoc += _wire->read();
_wire->read(); // skip crc
crc = _wire->read();
if (_CRC8(_tvoc) != crc)
{
_error = SGP30_ERROR_CRC;
return false;
}
_error = SGP30_OK;
return true;
}

Expand All @@ -196,18 +229,28 @@ bool SGP30::readRaw()
if (millis() - _lastRequest < 26) return false; // P11
_lastRequest = 0;

// TODO error handling
// TODO CRC
if (_wire->requestFrom(_address, (uint8_t)6) != 6)
{
_error = SGP30_ERROR_I2C;
return false;
}
_h2 = _wire->read() << 8;
_h2 += _wire->read();
_wire->read(); // skip crc
uint8_t crc = _wire->read();
if (_CRC8(_h2) != crc)
{
_error = SGP30_ERROR_CRC;
return false;
}
_ethanol = _wire->read() << 8;
_ethanol += _wire->read();
_wire->read(); // skip crc
crc = _wire->read();
if (_CRC8(_ethanol) != crc)
{
_error = SGP30_ERROR_CRC;
return false;
}
_error = SGP30_OK;
return true;
}

Expand Down Expand Up @@ -268,18 +311,28 @@ void SGP30::setBaseline(uint16_t CO2, uint16_t TVOC)
bool SGP30::getBaseline(uint16_t *CO2, uint16_t *TVOC)
{
_command(0x2015);
// TODO error handling
// TODO CRC
if (_wire->requestFrom(_address, (uint8_t)6) != 6)
{
_error = SGP30_ERROR_I2C;
return false;
}
*CO2 = _wire->read() << 8;
*CO2 += _wire->read();
_wire->read(); // skip crc
uint8_t crc = _wire->read();
if (_CRC8(*CO2) != crc)
{
_error = SGP30_ERROR_CRC;
return false;
}
*TVOC = _wire->read() << 8;
*TVOC += _wire->read();
_wire->read(); // skip crc
crc = _wire->read();
if (_CRC8(*TVOC) != crc)
{
_error = SGP30_ERROR_CRC;
return false;
}
_error = SGP30_OK;
return true;
}

Expand All @@ -293,15 +346,20 @@ void SGP30::setTVOCBaseline(uint16_t TVOC)
bool SGP30::getTVOCBaseline(uint16_t *TVOC)
{
_command(0x20B3);
// TODO error handling
// TODO CRC
if (_wire->requestFrom(_address, (uint8_t)3) != 3)
{
_error = SGP30_ERROR_I2C;
return false;
}
*TVOC = _wire->read() << 8;
*TVOC += _wire->read();
_wire->read(); // skip crc
uint8_t crc = _wire->read();
if (_CRC8(*TVOC) != crc)
{
_error = SGP30_ERROR_CRC;
return false;
}
_error = SGP30_OK;
return true;
}

Expand Down
11 changes: 7 additions & 4 deletions SGP30.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//
// FILE: SGP30.h
// AUTHOR: Rob Tillaart
// VERSION: 0.1.3
// VERSION: 0.1.4
// DATE: 2021-06-24
// PURPOSE: SGP30 library for Arduino
// URL: https://github.com/RobTillaart/SGP30
Expand All @@ -12,9 +12,11 @@
#include "Arduino.h"
#include "Wire.h"

#define SGP30_LIB_VERSION (F("0.1.3"))
#define SGP30_LIB_VERSION (F("0.1.4"))

#define SGP30_OK 0x00
#define SGP30_ERROR_CRC 0xFF
#define SGP30_ERROR_I2C 0xFE


class SGP30
Expand Down Expand Up @@ -56,14 +58,15 @@ class SGP30
uint16_t getCO2() { return _co2; }; // PPM
uint16_t getH2_raw() { return _h2; }; // UNKNOWN
uint16_t getEthanol_raw() { return _ethanol; }; // UNKNOWN
float getH2(); // experimental // PPM
float getEthanol(); // experimental // PPM
float getH2(); // experimental // PPM
float getEthanol(); // experimental // PPM


// CALIBRATION - read datasheet
// T in °C
// RH == 0..100
float setRelHumidity(float T, float RH); // P10
// Absolute humidity in grams / m3
// set Abs Hum to 0 to disables it...
void setAbsHumidity(float AbsoluteHumidity);

Expand Down
2 changes: 1 addition & 1 deletion library.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"type": "git",
"url": "https://github.com/RobTillaart/SGP30.git"
},
"version": "0.1.3",
"version": "0.1.4",
"license": "MIT",
"frameworks": "arduino",
"platforms": "*"
Expand Down
2 changes: 1 addition & 1 deletion library.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name=SGP30
version=0.1.3
version=0.1.4
author=Rob Tillaart <rob.tillaart@gmail.com>
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
sentence=Arduino library for SGP30 environment sensor.
Expand Down

0 comments on commit f6e1042

Please sign in to comment.