Skip to content

Commit

Permalink
Merge pull request #2 from RobTillaart/develop
Browse files Browse the repository at this point in the history
add get/set baseline ++
  • Loading branch information
RobTillaart authored Jun 26, 2021
2 parents a3720d3 + 3e37d72 commit 59f1f9c
Show file tree
Hide file tree
Showing 12 changed files with 330 additions and 47 deletions.
42 changes: 25 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,18 @@ Warning: experimental, 0.1.0 is functional not complete.

## Description

The SVP30 from Sensirion is an environment sensor that measures H2 and Ethanol in the air. From these numbers an intern algorithm derives an CO2 equivalent and a TVOC measurement.
The SGP30 from Sensirion is an environment sensor that measures H2 and Ethanol in the air. From these numbers an intern algorithm derives an CO2 equivalent and a TVOC measurement.

The CO2 units are ppm, the TVOC units are ppb. Units for H2 and Ethanol are unknown. For larger concentrations the resolution drops, see datasheet.

The sensor can be read up to once per second (1 Hz).
The CO2 and TVOC values can be read up to once per second (1 Hz). Ethanol and H2, the raw data can be sampled up to 40 Hz.

The library supports 2 types of interfaces, a synchronous and an asynchronous interface. The sync interface is blocking for up to 40 milliseconds which was enough to trigger the implementation of an async interface. Note: the sync interface is implemented with the async interface.

The SGP30 works with I2C bus at 100 KHz and 400 KHz. In a short test it worked well up to 600 KHz. A faster I2C clock does not give the sync interface much (relative) gain, however for the async the relative gain is much more.

It may take up to 10 seconds (maybe more) before the sensor produces real data.


#### multi sensors.

Expand Down Expand Up @@ -65,47 +69,51 @@ The library caches the last read values, and these are the functions to access t
- **uint16_t getTVOC()** gets the TVOC concentration (ppb)
- **uint16_t getCO2()** gets the CO2 **equivalent** concentration (ppm)
- **uint16_t getH2()** gets the H2 concentration. Units unknown.
- **uint16_t getEthanol()** gets the Ethanol concnetration. Units unknown.
- **uint16_t getEthanol()** gets the Ethanol concentration. Units unknown.


### Calibration

- **float setRelHumidity(float T, float RH)** sets the compensation for temperature and **relative** humidity. These values can be obtained e.g. from an SHT30, DHT22 or similar sensor.
- **void setAbsHumidity(float AbsoluteHumidity)** sets the compensation for **absolute** humidity.
Check the datasheet for operating range, figure 7.

- **float setRelHumidity(float T, float RH)** sets the compensation for temperature (5-55°C) and **relative** humidity (10-95%). These values can be obtained e.g. from an SHT30, DHT22 or similar sensor.
- **void setAbsHumidity(float AbsoluteHumidity)** sets the compensation for **absolute** humidity. Concentration is in gram per cubic meter (g/m3)


### Baseline functions

- TODO
The baseline functions give the sensor a reference value. After running in a known condition e.g. outside in open air, one can get the baseline values as a sort of calibration. Please read the datasheet carefully before using these functions.

Note: if the sensor has no reads done, these values tend to go to zero. This is because the baselines are based upon recent reads.

### MISC
- **bool getBaseline(uint16_t *CO2, uint16_t *TVOC)**
- **void setBaseline(uint16_t CO2, uint16_t TVOC)**

- **int lastError()** returns last error. (needs rework)

### Misc

- **int lastError()** returns last error. (needs rework)

## Todo

No particular order.
## Todo

- measure performance at different I2C speeds.
- get units H2 right
- get units Ethanol right
- redo **getID()**
- redo **lastError()**
- should **getFeatureSet()** become **bool checkFeatureSet()**?
- implement get Acquisition Baseline() functions.
- implement the TVOC starter baseline.
- test test test ....
= extend unit tests
- improve documentation
- get units H2 right if possible
- get units Ethanol right if possible
- CRC handling
- error handling


## Operational

See examples


## Links

https://www.adafruit.com/product/3709
https://www.adafruit.com/product/3709 - the sensor.

61 changes: 51 additions & 10 deletions SGP30.cpp
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
//
// FILE: SGP30.cpp
// AUTHOR: Rob Tillaart
// VERSION: 0.1.0
// VERSION: 0.1.1
// DATE: 2021-06-24
// PURPOSE: SGP30 library for Arduino
// URL: https://github.com/RobTillaart/SGP30
// https://www.adafruit.com/product/3709
//
// HISTORY:
// 0.1.0 2021-06-24 initial version
//
// 0.1.1 2021-06-26 add get/setBaseline ++


#include "SGP30.h"
Expand Down Expand Up @@ -187,6 +187,7 @@ void SGP30::requestRaw()
_command(0x2050);
}


bool SGP30::readRaw()
{
if (_lastRequest == 0) return false;
Expand All @@ -202,15 +203,13 @@ bool SGP30::readRaw()
_h2 = _wire->read() << 8;
_h2 += _wire->read();
_wire->read(); // skip crc

_ethanol = _wire->read() << 8;
_ethanol += _wire->read();
_wire->read(); // skip crc
return true;
}



/////////////////////////////////////////////////////
//
// CALIBRATION
Expand Down Expand Up @@ -238,7 +237,32 @@ void SGP30::setAbsHumidity(float AbsoluteHumidity)
uint8_t tmp = (AbsoluteHumidity - AH) * 256;
AH = (AH << 8) | tmp;

_setCommand(0x2061, AH); // P 11
_command(0x2061, AH); // P 11
}


void SGP30::setBaseline(uint16_t CO2, uint16_t TVOC)
{
_command(0x201E, CO2, 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)
{
return false;
}
*CO2 = _wire->read() << 8;
*CO2 += _wire->read();
_wire->read(); // skip crc
*TVOC = _wire->read() << 8;
*TVOC += _wire->read();
_wire->read(); // skip crc
return true;
}


Expand Down Expand Up @@ -268,14 +292,30 @@ int SGP30::_command(uint16_t cmd)
}


int SGP30::_setCommand(uint16_t cmd, uint16_t val)
int SGP30::_command(uint16_t cmd, uint16_t v1)
{
_wire->beginTransmission(_address);
_wire->write(cmd >> 8);
_wire->write(cmd & 0xFF);
_wire->write(v1 >> 8);
_wire->write(v1 & 0xFF);
_wire->write(_CRC8(v1));
_error = _wire->endTransmission();
return _error;
}


int SGP30::_command(uint16_t cmd, uint16_t v1, uint16_t v2)
{
_wire->beginTransmission(_address);
_wire->write(cmd >> 8);
_wire->write(cmd & 0xFF);
_wire->write(val >> 8);
_wire->write(val & 0xFF);
_wire->write(_CRC8(val));
_wire->write(v1 >> 8);
_wire->write(v1 & 0xFF);
_wire->write(_CRC8(v1));
_wire->write(v2 >> 8);
_wire->write(v2 & 0xFF);
_wire->write(_CRC8(v2));
_error = _wire->endTransmission();
return _error;
}
Expand All @@ -288,7 +328,8 @@ uint8_t SGP30::_CRC8(uint16_t data)
uint8_t val[2];
val[0] = data >> 8;
val[1] = data & 0xFF;
uint8_t crc = 0xFF;

uint8_t crc = 0xFF; // start value
for(uint8_t i = 0; i < 2; i++)
{
crc ^= val[i];
Expand Down
25 changes: 11 additions & 14 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.0
// VERSION: 0.1.1
// DATE: 2021-06-24
// PURPOSE: SGP30 library for Arduino
// URL: https://github.com/RobTillaart/SGP30
Expand All @@ -12,7 +12,7 @@
#include "Arduino.h"
#include "Wire.h"

#define SGP30_LIB_VERSION (F("0.1.0"))
#define SGP30_LIB_VERSION (F("0.1.1"))

#define SGP30_OK 0x00

Expand Down Expand Up @@ -65,18 +65,13 @@ class SGP30
// set Abs Hum to 0 to disables it...
void setAbsHumidity(float AbsoluteHumidity);

// TODO NEXT RELEASE
/*
something like this
void setAcqBase() {}; // 0x201e
void getAcqBase() {}; // 0x2015
void setTVOCBase() {}; // 0x2077
void getTVOCBase() {}; // 0x20B3
void setBaseline(uint16_t CO2, uint16_t TVOC);
bool getBaseline(uint16_t *CO2, uint16_t *TVOC);

split getAcqBase in 2 calls?
uint16_t getCO2base();
uint16_t getTVOCbase();
/*
// faster startup
void setTVOCStarter() {}; // 0x2077
void getTVOCStarter() {}; // 0x20B3
*/


Expand All @@ -92,8 +87,10 @@ class SGP30
uint32_t _lastTime = 0;
uint32_t _lastRequest = 0;

// TODO improve?
int _command(uint16_t cmd);
int _setCommand(uint16_t cmd, uint16_t val);
int _command(uint16_t cmd, uint16_t v1);
int _command(uint16_t cmd, uint16_t v1, uint16_t v2);
uint8_t _CRC8(uint16_t val);
void _init();

Expand Down
102 changes: 102 additions & 0 deletions examples/SGP30_I2C_performance/SGP30_I2C_performance.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
//
// FILE: SGP30_I2C_performance.ino
// AUTHOR: Rob Tillaart
// PURPOSE: demo SGP30
// DATE: 2021-06-25
// URL: https://github.com/RobTillaart/SGP30
// https://www.adafruit.com/product/3709


#include "SGP30.h"


SGP30 SGP;

uint32_t start, stop;

void setup()
{
Serial.begin(115200);
while (!Serial) {
delay(1);
yield();
};

Serial.print(__FILE__);
Serial.println(SGP30_LIB_VERSION);
Serial.println();

Serial.print("BEGIN:\t");
Serial.println(SGP.begin());
Serial.print("TEST:\t");
Serial.println(SGP.measureTest());

delay(1000);

// has 12 millisecond delay build in...
Serial.println("\nMEASURE()");
for (uint32_t sp = 100000; sp <= 600000; sp += 50000)
{
Wire.setClock(sp);
start = micros();
SGP.measure(false);
stop = micros();
Serial.print(sp);
Serial.print("\t");
Serial.println(stop - start);
delay(1000);
}

// has 40 millisecond delay build in...
Serial.println("\nMEASURE()");
for (uint32_t sp = 100000; sp <= 600000; sp += 50000)
{
Wire.setClock(sp);
start = micros();
SGP.measure(true);
stop = micros();
Serial.print(sp);
Serial.print("\t");
Serial.println(stop - start);
delay(1000);
}


Serial.println("\nREQUEST()");
for (uint32_t sp = 100000; sp <= 600000; sp += 50000)
{
Wire.setClock(sp);
start = micros();
SGP.request();
stop = micros();
Serial.print(sp);
Serial.print("\t");
Serial.println(stop - start);
delay(1000);
}

Serial.println("\nREAD()");
for (uint32_t sp = 100000; sp <= 600000; sp += 50000)
{
Wire.setClock(sp);
start = micros();
SGP.read();
stop = micros();
Serial.print(sp);
Serial.print("\t");
Serial.println(stop - start);
SGP.request();
delay(1000);
}



}


void loop()
{
}


// -- END OF FILE --
Loading

0 comments on commit 59f1f9c

Please sign in to comment.