Port from Adafruit's SGP30 arduino lib(https://github.com/adafruit/Adafruit_SGP30) to use Mbed api

Dependents:   AMU_Polytech_Marseille_STM32InTheSky_01_05_2019 Sensor_SGP30 Sensor_iAQ_sgp30_bme_si7051 POCBreath_V2_smd_commercial

Committer:
ndrs_cwt
Date:
Mon Jul 23 09:51:43 2018 +0000
Revision:
0:41a622cdd86d
Port from Adafruit_SGP30 arduino lib(https://github.com/adafruit/Adafruit_SGP30) to use Mbed API

Who changed what in which revision?

UserRevisionLine numberNew contents of line
ndrs_cwt 0:41a622cdd86d 1 /*!
ndrs_cwt 0:41a622cdd86d 2 * @file Adafruit_SGP30.cpp
ndrs_cwt 0:41a622cdd86d 3 *
ndrs_cwt 0:41a622cdd86d 4 * @mainpage Adafruit SGP30 gas sensor driver
ndrs_cwt 0:41a622cdd86d 5 *
ndrs_cwt 0:41a622cdd86d 6 * @section intro_sec Introduction
ndrs_cwt 0:41a622cdd86d 7 *
ndrs_cwt 0:41a622cdd86d 8 * This is the documentation for Adafruit's SGP30 driver for the
ndrs_cwt 0:41a622cdd86d 9 * Arduino platform. It is designed specifically to work with the
ndrs_cwt 0:41a622cdd86d 10 * Adafruit SGP30 breakout: http://www.adafruit.com/products/3709
ndrs_cwt 0:41a622cdd86d 11 *
ndrs_cwt 0:41a622cdd86d 12 * These sensors use I2C to communicate, 2 pins (SCL+SDA) are required
ndrs_cwt 0:41a622cdd86d 13 * to interface with the breakout.
ndrs_cwt 0:41a622cdd86d 14 *
ndrs_cwt 0:41a622cdd86d 15 * Adafruit invests time and resources providing this open source code,
ndrs_cwt 0:41a622cdd86d 16 * please support Adafruit and open-source hardware by purchasing
ndrs_cwt 0:41a622cdd86d 17 * products from Adafruit!
ndrs_cwt 0:41a622cdd86d 18 *
ndrs_cwt 0:41a622cdd86d 19 *
ndrs_cwt 0:41a622cdd86d 20 * @section author Author
ndrs_cwt 0:41a622cdd86d 21 * Written by Ladyada for Adafruit Industries.
ndrs_cwt 0:41a622cdd86d 22 *
ndrs_cwt 0:41a622cdd86d 23 * @section license License
ndrs_cwt 0:41a622cdd86d 24 * BSD license, all text here must be included in any redistribution.
ndrs_cwt 0:41a622cdd86d 25 *
ndrs_cwt 0:41a622cdd86d 26 */
ndrs_cwt 0:41a622cdd86d 27
ndrs_cwt 0:41a622cdd86d 28 #include "mbed.h"
ndrs_cwt 0:41a622cdd86d 29 #include "Adafruit_SGP30.h"
ndrs_cwt 0:41a622cdd86d 30
ndrs_cwt 0:41a622cdd86d 31 //#define I2C_DEBUG
ndrs_cwt 0:41a622cdd86d 32
ndrs_cwt 0:41a622cdd86d 33 /**************************************************************************/
ndrs_cwt 0:41a622cdd86d 34 /*!
ndrs_cwt 0:41a622cdd86d 35 @brief Instantiates a new SGP30 class
ndrs_cwt 0:41a622cdd86d 36 */
ndrs_cwt 0:41a622cdd86d 37 /**************************************************************************/
ndrs_cwt 0:41a622cdd86d 38 Adafruit_SGP30::Adafruit_SGP30(PinName sda, PinName scl) : _i2c(sda, scl) {
ndrs_cwt 0:41a622cdd86d 39 }
ndrs_cwt 0:41a622cdd86d 40
ndrs_cwt 0:41a622cdd86d 41 /**************************************************************************/
ndrs_cwt 0:41a622cdd86d 42 /*!
ndrs_cwt 0:41a622cdd86d 43 @brief Setups the hardware and detects a valid SGP30. Initializes I2C
ndrs_cwt 0:41a622cdd86d 44 then reads the serialnumber and checks that we are talking to an SGP30
ndrs_cwt 0:41a622cdd86d 45 @param theWire Optional pointer to I2C interface, otherwise use Wire
ndrs_cwt 0:41a622cdd86d 46 @returns True if SGP30 found on I2C, False if something went wrong!
ndrs_cwt 0:41a622cdd86d 47 */
ndrs_cwt 0:41a622cdd86d 48 /**************************************************************************/
ndrs_cwt 0:41a622cdd86d 49 bool Adafruit_SGP30::begin() {
ndrs_cwt 0:41a622cdd86d 50 //Mbed use 8bit addr
ndrs_cwt 0:41a622cdd86d 51 _i2caddr = SGP30_I2CADDR_DEFAULT << 1;
ndrs_cwt 0:41a622cdd86d 52
ndrs_cwt 0:41a622cdd86d 53 uint8_t command[3];
ndrs_cwt 0:41a622cdd86d 54 command[0] = 0x36;
ndrs_cwt 0:41a622cdd86d 55 command[1] = 0x82;
ndrs_cwt 0:41a622cdd86d 56 command[2] = 0x0;
ndrs_cwt 0:41a622cdd86d 57 if (! readWordFromCommand(command, 2, 5, serialnumber, 3))
ndrs_cwt 0:41a622cdd86d 58 return false;
ndrs_cwt 0:41a622cdd86d 59
ndrs_cwt 0:41a622cdd86d 60 uint16_t featureset;
ndrs_cwt 0:41a622cdd86d 61 command[0] = 0x20;
ndrs_cwt 0:41a622cdd86d 62 command[1] = 0x2F;
ndrs_cwt 0:41a622cdd86d 63 if (! readWordFromCommand(command, 2, 10, &featureset, 1))
ndrs_cwt 0:41a622cdd86d 64 return false;
ndrs_cwt 0:41a622cdd86d 65 //Serial.print("Featureset 0x"); Serial.println(featureset, HEX);
ndrs_cwt 0:41a622cdd86d 66 if (featureset != SGP30_FEATURESET)
ndrs_cwt 0:41a622cdd86d 67 return false;
ndrs_cwt 0:41a622cdd86d 68 if (! IAQinit())
ndrs_cwt 0:41a622cdd86d 69 return false;
ndrs_cwt 0:41a622cdd86d 70
ndrs_cwt 0:41a622cdd86d 71 return true;
ndrs_cwt 0:41a622cdd86d 72 }
ndrs_cwt 0:41a622cdd86d 73
ndrs_cwt 0:41a622cdd86d 74 /**************************************************************************/
ndrs_cwt 0:41a622cdd86d 75 /*!
ndrs_cwt 0:41a622cdd86d 76 @brief Commands the sensor to begin the IAQ algorithm. Must be called after startup.
ndrs_cwt 0:41a622cdd86d 77 @returns True if command completed successfully, false if something went wrong!
ndrs_cwt 0:41a622cdd86d 78 */
ndrs_cwt 0:41a622cdd86d 79 /**************************************************************************/
ndrs_cwt 0:41a622cdd86d 80 bool Adafruit_SGP30::IAQinit(void) {
ndrs_cwt 0:41a622cdd86d 81 uint8_t command[2];
ndrs_cwt 0:41a622cdd86d 82 command[0] = 0x20;
ndrs_cwt 0:41a622cdd86d 83 command[1] = 0x03;
ndrs_cwt 0:41a622cdd86d 84 return readWordFromCommand(command, 2, 10);
ndrs_cwt 0:41a622cdd86d 85 }
ndrs_cwt 0:41a622cdd86d 86
ndrs_cwt 0:41a622cdd86d 87 /**************************************************************************/
ndrs_cwt 0:41a622cdd86d 88 /*!
ndrs_cwt 0:41a622cdd86d 89 @brief Commands the sensor to take a single eCO2/VOC measurement. Places results in {@link TVOC} and {@link eCO2}
ndrs_cwt 0:41a622cdd86d 90 @returns True if command completed successfully, false if something went wrong!
ndrs_cwt 0:41a622cdd86d 91 */
ndrs_cwt 0:41a622cdd86d 92 /**************************************************************************/
ndrs_cwt 0:41a622cdd86d 93 bool Adafruit_SGP30::IAQmeasure(void) {
ndrs_cwt 0:41a622cdd86d 94 uint8_t command[2];
ndrs_cwt 0:41a622cdd86d 95 command[0] = 0x20;
ndrs_cwt 0:41a622cdd86d 96 command[1] = 0x08;
ndrs_cwt 0:41a622cdd86d 97 uint16_t reply[2];
ndrs_cwt 0:41a622cdd86d 98 if (! readWordFromCommand(command, 2, 12, reply, 2))
ndrs_cwt 0:41a622cdd86d 99 return false;
ndrs_cwt 0:41a622cdd86d 100 TVOC = reply[1];
ndrs_cwt 0:41a622cdd86d 101 eCO2 = reply[0];
ndrs_cwt 0:41a622cdd86d 102 return true;
ndrs_cwt 0:41a622cdd86d 103 }
ndrs_cwt 0:41a622cdd86d 104
ndrs_cwt 0:41a622cdd86d 105 /**************************************************************************/
ndrs_cwt 0:41a622cdd86d 106 /*!
ndrs_cwt 0:41a622cdd86d 107 @brief Request baseline calibration values for both CO2 and TVOC IAQ calculations. Places results in parameter memory locaitons.
ndrs_cwt 0:41a622cdd86d 108 @param eco2_base A pointer to a uint16_t which we will save the calibration value to
ndrs_cwt 0:41a622cdd86d 109 @param tvoc_base A pointer to a uint16_t which we will save the calibration value to
ndrs_cwt 0:41a622cdd86d 110 @returns True if command completed successfully, false if something went wrong!
ndrs_cwt 0:41a622cdd86d 111 */
ndrs_cwt 0:41a622cdd86d 112 /**************************************************************************/
ndrs_cwt 0:41a622cdd86d 113 bool Adafruit_SGP30::getIAQBaseline(uint16_t *eco2_base, uint16_t *tvoc_base) {
ndrs_cwt 0:41a622cdd86d 114 uint8_t command[2];
ndrs_cwt 0:41a622cdd86d 115 command[0] = 0x20;
ndrs_cwt 0:41a622cdd86d 116 command[1] = 0x15;
ndrs_cwt 0:41a622cdd86d 117 uint16_t reply[2];
ndrs_cwt 0:41a622cdd86d 118 if (! readWordFromCommand(command, 2, 10, reply, 2))
ndrs_cwt 0:41a622cdd86d 119 return false;
ndrs_cwt 0:41a622cdd86d 120 *eco2_base = reply[0];
ndrs_cwt 0:41a622cdd86d 121 *tvoc_base = reply[1];
ndrs_cwt 0:41a622cdd86d 122 return true;
ndrs_cwt 0:41a622cdd86d 123 }
ndrs_cwt 0:41a622cdd86d 124
ndrs_cwt 0:41a622cdd86d 125 bool Adafruit_SGP30::getIAQRaw(uint16_t *H2_raw, uint16_t *Eth_raw) {
ndrs_cwt 0:41a622cdd86d 126 uint8_t command[2];
ndrs_cwt 0:41a622cdd86d 127 command[0] = 0x20;
ndrs_cwt 0:41a622cdd86d 128 command[1] = 0x50;
ndrs_cwt 0:41a622cdd86d 129 uint16_t reply[2];
ndrs_cwt 0:41a622cdd86d 130 if (! readWordFromCommand(command, 2, 40, reply, 2))
ndrs_cwt 0:41a622cdd86d 131 return false;
ndrs_cwt 0:41a622cdd86d 132 *H2_raw = reply[0];
ndrs_cwt 0:41a622cdd86d 133 *Eth_raw = reply[1];
ndrs_cwt 0:41a622cdd86d 134 return true;
ndrs_cwt 0:41a622cdd86d 135 }
ndrs_cwt 0:41a622cdd86d 136
ndrs_cwt 0:41a622cdd86d 137 /**************************************************************************/
ndrs_cwt 0:41a622cdd86d 138 /*!
ndrs_cwt 0:41a622cdd86d 139 @brief Assign baseline calibration values for both CO2 and TVOC IAQ calculations.
ndrs_cwt 0:41a622cdd86d 140 @param eco2_base A uint16_t which we will save the calibration value from
ndrs_cwt 0:41a622cdd86d 141 @param tvoc_base A uint16_t which we will save the calibration value from
ndrs_cwt 0:41a622cdd86d 142 @returns True if command completed successfully, false if something went wrong!
ndrs_cwt 0:41a622cdd86d 143 */
ndrs_cwt 0:41a622cdd86d 144 /**************************************************************************/
ndrs_cwt 0:41a622cdd86d 145 bool Adafruit_SGP30::setIAQBaseline(uint16_t eco2_base, uint16_t tvoc_base) {
ndrs_cwt 0:41a622cdd86d 146 uint8_t command[8];
ndrs_cwt 0:41a622cdd86d 147 command[0] = 0x20;
ndrs_cwt 0:41a622cdd86d 148 command[1] = 0x1e;
ndrs_cwt 0:41a622cdd86d 149 command[2] = tvoc_base >> 8;
ndrs_cwt 0:41a622cdd86d 150 command[3] = tvoc_base & 0xFF;
ndrs_cwt 0:41a622cdd86d 151 command[4] = generateCRC(command+2, 2);
ndrs_cwt 0:41a622cdd86d 152 command[5] = eco2_base >> 8;
ndrs_cwt 0:41a622cdd86d 153 command[6] = eco2_base & 0xFF;
ndrs_cwt 0:41a622cdd86d 154 command[7] = generateCRC(command+5, 2);
ndrs_cwt 0:41a622cdd86d 155
ndrs_cwt 0:41a622cdd86d 156 return readWordFromCommand(command, 8, 10);
ndrs_cwt 0:41a622cdd86d 157 }
ndrs_cwt 0:41a622cdd86d 158
ndrs_cwt 0:41a622cdd86d 159 /**************************************************************************/
ndrs_cwt 0:41a622cdd86d 160 /*!
ndrs_cwt 0:41a622cdd86d 161 @brief I2C low level interfacing
ndrs_cwt 0:41a622cdd86d 162 */
ndrs_cwt 0:41a622cdd86d 163 /**************************************************************************/
ndrs_cwt 0:41a622cdd86d 164
ndrs_cwt 0:41a622cdd86d 165
ndrs_cwt 0:41a622cdd86d 166 bool Adafruit_SGP30::readWordFromCommand(uint8_t command[], uint8_t commandLength, uint16_t delayms, uint16_t *readdata, uint8_t readlen)
ndrs_cwt 0:41a622cdd86d 167 {
ndrs_cwt 0:41a622cdd86d 168 uint8_t retval;
ndrs_cwt 0:41a622cdd86d 169
ndrs_cwt 0:41a622cdd86d 170
ndrs_cwt 0:41a622cdd86d 171 #ifdef I2C_DEBUG
ndrs_cwt 0:41a622cdd86d 172 printf("\t\t-> ");
ndrs_cwt 0:41a622cdd86d 173 #endif
ndrs_cwt 0:41a622cdd86d 174
ndrs_cwt 0:41a622cdd86d 175 retval = _i2c.write((int)_i2caddr, (const char*)command, (int)commandLength);
ndrs_cwt 0:41a622cdd86d 176 //0=OK, 1=Fail https://os.mbed.com/docs/v5.9/reference/i2c.html
ndrs_cwt 0:41a622cdd86d 177 if ( retval != 0)
ndrs_cwt 0:41a622cdd86d 178 return false;
ndrs_cwt 0:41a622cdd86d 179
ndrs_cwt 0:41a622cdd86d 180 #ifdef I2C_DEBUG
ndrs_cwt 0:41a622cdd86d 181 for (uint8_t i=0; i<commandLength; i++) {
ndrs_cwt 0:41a622cdd86d 182 printf("0x");
ndrs_cwt 0:41a622cdd86d 183 printf("%x", command[i]);
ndrs_cwt 0:41a622cdd86d 184 printf(", ");
ndrs_cwt 0:41a622cdd86d 185 }
ndrs_cwt 0:41a622cdd86d 186 #endif
ndrs_cwt 0:41a622cdd86d 187
ndrs_cwt 0:41a622cdd86d 188 #ifdef I2C_DEBUG
ndrs_cwt 0:41a622cdd86d 189 printf("\n");
ndrs_cwt 0:41a622cdd86d 190 #endif
ndrs_cwt 0:41a622cdd86d 191
ndrs_cwt 0:41a622cdd86d 192 wait_ms(delayms);
ndrs_cwt 0:41a622cdd86d 193
ndrs_cwt 0:41a622cdd86d 194
ndrs_cwt 0:41a622cdd86d 195
ndrs_cwt 0:41a622cdd86d 196 if (readlen == 0)
ndrs_cwt 0:41a622cdd86d 197 return true;
ndrs_cwt 0:41a622cdd86d 198
ndrs_cwt 0:41a622cdd86d 199 uint8_t replylen = readlen * (SGP30_WORD_LEN +1);
ndrs_cwt 0:41a622cdd86d 200 uint8_t replybuffer[replylen];
ndrs_cwt 0:41a622cdd86d 201
ndrs_cwt 0:41a622cdd86d 202 retval = _i2c.read((int)_i2caddr, (char*)replybuffer, (int)replylen);
ndrs_cwt 0:41a622cdd86d 203
ndrs_cwt 0:41a622cdd86d 204 //0=OK, 1=Fail https://os.mbed.com/docs/v5.9/reference/i2c.html
ndrs_cwt 0:41a622cdd86d 205 if ( retval != 0)
ndrs_cwt 0:41a622cdd86d 206 return false;
ndrs_cwt 0:41a622cdd86d 207
ndrs_cwt 0:41a622cdd86d 208 #ifdef I2C_DEBUG
ndrs_cwt 0:41a622cdd86d 209 printf("\t\t<- ");
ndrs_cwt 0:41a622cdd86d 210 for (uint8_t i=0; i<replylen; i++) {
ndrs_cwt 0:41a622cdd86d 211 printf("0x");
ndrs_cwt 0:41a622cdd86d 212 printf("%x", replybuffer[i]);
ndrs_cwt 0:41a622cdd86d 213 printf(", ");
ndrs_cwt 0:41a622cdd86d 214 }
ndrs_cwt 0:41a622cdd86d 215 #endif
ndrs_cwt 0:41a622cdd86d 216
ndrs_cwt 0:41a622cdd86d 217
ndrs_cwt 0:41a622cdd86d 218 #ifdef I2C_DEBUG
ndrs_cwt 0:41a622cdd86d 219 printf("\n");
ndrs_cwt 0:41a622cdd86d 220 #endif
ndrs_cwt 0:41a622cdd86d 221
ndrs_cwt 0:41a622cdd86d 222 for (uint8_t i=0; i<readlen; i++) {
ndrs_cwt 0:41a622cdd86d 223 uint8_t crc = generateCRC(replybuffer+i*3, 2);
ndrs_cwt 0:41a622cdd86d 224 #ifdef I2C_DEBUG
ndrs_cwt 0:41a622cdd86d 225 printf("\t\tCRC calced: 0x");
ndrs_cwt 0:41a622cdd86d 226 printf("%x", crc);
ndrs_cwt 0:41a622cdd86d 227 printf(" vs. 0x");
ndrs_cwt 0:41a622cdd86d 228 printf("%x\n" ,replybuffer[i * 3 + 2];
ndrs_cwt 0:41a622cdd86d 229 #endif
ndrs_cwt 0:41a622cdd86d 230 if (crc != replybuffer[i * 3 + 2])
ndrs_cwt 0:41a622cdd86d 231 return false;
ndrs_cwt 0:41a622cdd86d 232 // success! store it
ndrs_cwt 0:41a622cdd86d 233 readdata[i] = replybuffer[i*3];
ndrs_cwt 0:41a622cdd86d 234 readdata[i] <<= 8;
ndrs_cwt 0:41a622cdd86d 235 readdata[i] |= replybuffer[i*3 + 1];
ndrs_cwt 0:41a622cdd86d 236 #ifdef I2C_DEBUG
ndrs_cwt 0:41a622cdd86d 237 printf("\t\tRead: 0x");
ndrs_cwt 0:41a622cdd86d 238 printf("%x\n", readdata[i]);
ndrs_cwt 0:41a622cdd86d 239 #endif
ndrs_cwt 0:41a622cdd86d 240 }
ndrs_cwt 0:41a622cdd86d 241 return true;
ndrs_cwt 0:41a622cdd86d 242 }
ndrs_cwt 0:41a622cdd86d 243
ndrs_cwt 0:41a622cdd86d 244 uint8_t Adafruit_SGP30::generateCRC(uint8_t *data, uint8_t datalen) {
ndrs_cwt 0:41a622cdd86d 245 // calculates 8-Bit checksum with given polynomial
ndrs_cwt 0:41a622cdd86d 246 uint8_t crc = SGP30_CRC8_INIT;
ndrs_cwt 0:41a622cdd86d 247
ndrs_cwt 0:41a622cdd86d 248 for (uint8_t i=0; i<datalen; i++) {
ndrs_cwt 0:41a622cdd86d 249 crc ^= data[i];
ndrs_cwt 0:41a622cdd86d 250 for (uint8_t b=0; b<8; b++) {
ndrs_cwt 0:41a622cdd86d 251 if (crc & 0x80)
ndrs_cwt 0:41a622cdd86d 252 crc = (crc << 1) ^ SGP30_CRC8_POLYNOMIAL;
ndrs_cwt 0:41a622cdd86d 253 else
ndrs_cwt 0:41a622cdd86d 254 crc <<= 1;
ndrs_cwt 0:41a622cdd86d 255 }
ndrs_cwt 0:41a622cdd86d 256 }
ndrs_cwt 0:41a622cdd86d 257 return crc;
ndrs_cwt 0:41a622cdd86d 258 }