hg
Dependents: Example_DS3231_test
Adafruit_SGP30.cpp
- Committer:
- ndrs_cwt
- Date:
- 2018-07-23
- Revision:
- 0:41a622cdd86d
- Child:
- 1:fedfd309fb3c
File content as of revision 0:41a622cdd86d:
/*! * @file Adafruit_SGP30.cpp * * @mainpage Adafruit SGP30 gas sensor driver * * @section intro_sec Introduction * * This is the documentation for Adafruit's SGP30 driver for the * Arduino platform. It is designed specifically to work with the * Adafruit SGP30 breakout: http://www.adafruit.com/products/3709 * * These sensors use I2C to communicate, 2 pins (SCL+SDA) are required * to interface with the breakout. * * Adafruit invests time and resources providing this open source code, * please support Adafruit and open-source hardware by purchasing * products from Adafruit! * * * @section author Author * Written by Ladyada for Adafruit Industries. * * @section license License * BSD license, all text here must be included in any redistribution. * */ #include "mbed.h" #include "Adafruit_SGP30.h" //#define I2C_DEBUG /**************************************************************************/ /*! @brief Instantiates a new SGP30 class */ /**************************************************************************/ Adafruit_SGP30::Adafruit_SGP30(PinName sda, PinName scl) : _i2c(sda, scl) { } /**************************************************************************/ /*! @brief Setups the hardware and detects a valid SGP30. Initializes I2C then reads the serialnumber and checks that we are talking to an SGP30 @param theWire Optional pointer to I2C interface, otherwise use Wire @returns True if SGP30 found on I2C, False if something went wrong! */ /**************************************************************************/ bool Adafruit_SGP30::begin() { //Mbed use 8bit addr _i2caddr = SGP30_I2CADDR_DEFAULT << 1; uint8_t command[3]; command[0] = 0x36; command[1] = 0x82; command[2] = 0x0; if (! readWordFromCommand(command, 2, 5, serialnumber, 3)) return false; uint16_t featureset; command[0] = 0x20; command[1] = 0x2F; if (! readWordFromCommand(command, 2, 10, &featureset, 1)) return false; //Serial.print("Featureset 0x"); Serial.println(featureset, HEX); if (featureset != SGP30_FEATURESET) return false; if (! IAQinit()) return false; return true; } /**************************************************************************/ /*! @brief Commands the sensor to begin the IAQ algorithm. Must be called after startup. @returns True if command completed successfully, false if something went wrong! */ /**************************************************************************/ bool Adafruit_SGP30::IAQinit(void) { uint8_t command[2]; command[0] = 0x20; command[1] = 0x03; return readWordFromCommand(command, 2, 10); } /**************************************************************************/ /*! @brief Commands the sensor to take a single eCO2/VOC measurement. Places results in {@link TVOC} and {@link eCO2} @returns True if command completed successfully, false if something went wrong! */ /**************************************************************************/ bool Adafruit_SGP30::IAQmeasure(void) { uint8_t command[2]; command[0] = 0x20; command[1] = 0x08; uint16_t reply[2]; if (! readWordFromCommand(command, 2, 12, reply, 2)) return false; TVOC = reply[1]; eCO2 = reply[0]; return true; } /**************************************************************************/ /*! @brief Request baseline calibration values for both CO2 and TVOC IAQ calculations. Places results in parameter memory locaitons. @param eco2_base A pointer to a uint16_t which we will save the calibration value to @param tvoc_base A pointer to a uint16_t which we will save the calibration value to @returns True if command completed successfully, false if something went wrong! */ /**************************************************************************/ bool Adafruit_SGP30::getIAQBaseline(uint16_t *eco2_base, uint16_t *tvoc_base) { uint8_t command[2]; command[0] = 0x20; command[1] = 0x15; uint16_t reply[2]; if (! readWordFromCommand(command, 2, 10, reply, 2)) return false; *eco2_base = reply[0]; *tvoc_base = reply[1]; return true; } bool Adafruit_SGP30::getIAQRaw(uint16_t *H2_raw, uint16_t *Eth_raw) { uint8_t command[2]; command[0] = 0x20; command[1] = 0x50; uint16_t reply[2]; if (! readWordFromCommand(command, 2, 40, reply, 2)) return false; *H2_raw = reply[0]; *Eth_raw = reply[1]; return true; } /**************************************************************************/ /*! @brief Assign baseline calibration values for both CO2 and TVOC IAQ calculations. @param eco2_base A uint16_t which we will save the calibration value from @param tvoc_base A uint16_t which we will save the calibration value from @returns True if command completed successfully, false if something went wrong! */ /**************************************************************************/ bool Adafruit_SGP30::setIAQBaseline(uint16_t eco2_base, uint16_t tvoc_base) { uint8_t command[8]; command[0] = 0x20; command[1] = 0x1e; command[2] = tvoc_base >> 8; command[3] = tvoc_base & 0xFF; command[4] = generateCRC(command+2, 2); command[5] = eco2_base >> 8; command[6] = eco2_base & 0xFF; command[7] = generateCRC(command+5, 2); return readWordFromCommand(command, 8, 10); } /**************************************************************************/ /*! @brief I2C low level interfacing */ /**************************************************************************/ bool Adafruit_SGP30::readWordFromCommand(uint8_t command[], uint8_t commandLength, uint16_t delayms, uint16_t *readdata, uint8_t readlen) { uint8_t retval; #ifdef I2C_DEBUG printf("\t\t-> "); #endif retval = _i2c.write((int)_i2caddr, (const char*)command, (int)commandLength); //0=OK, 1=Fail https://os.mbed.com/docs/v5.9/reference/i2c.html if ( retval != 0) return false; #ifdef I2C_DEBUG for (uint8_t i=0; i<commandLength; i++) { printf("0x"); printf("%x", command[i]); printf(", "); } #endif #ifdef I2C_DEBUG printf("\n"); #endif wait_ms(delayms); if (readlen == 0) return true; uint8_t replylen = readlen * (SGP30_WORD_LEN +1); uint8_t replybuffer[replylen]; retval = _i2c.read((int)_i2caddr, (char*)replybuffer, (int)replylen); //0=OK, 1=Fail https://os.mbed.com/docs/v5.9/reference/i2c.html if ( retval != 0) return false; #ifdef I2C_DEBUG printf("\t\t<- "); for (uint8_t i=0; i<replylen; i++) { printf("0x"); printf("%x", replybuffer[i]); printf(", "); } #endif #ifdef I2C_DEBUG printf("\n"); #endif for (uint8_t i=0; i<readlen; i++) { uint8_t crc = generateCRC(replybuffer+i*3, 2); #ifdef I2C_DEBUG printf("\t\tCRC calced: 0x"); printf("%x", crc); printf(" vs. 0x"); printf("%x\n" ,replybuffer[i * 3 + 2]; #endif if (crc != replybuffer[i * 3 + 2]) return false; // success! store it readdata[i] = replybuffer[i*3]; readdata[i] <<= 8; readdata[i] |= replybuffer[i*3 + 1]; #ifdef I2C_DEBUG printf("\t\tRead: 0x"); printf("%x\n", readdata[i]); #endif } return true; } uint8_t Adafruit_SGP30::generateCRC(uint8_t *data, uint8_t datalen) { // calculates 8-Bit checksum with given polynomial uint8_t crc = SGP30_CRC8_INIT; for (uint8_t i=0; i<datalen; i++) { crc ^= data[i]; for (uint8_t b=0; b<8; b++) { if (crc & 0x80) crc = (crc << 1) ^ SGP30_CRC8_POLYNOMIAL; else crc <<= 1; } } return crc; }