hg
Dependents: Example_DS3231_test
Adafruit_SGP30.cpp@0:41a622cdd86d, 2018-07-23 (annotated)
- Committer:
- ndrs_cwt
- Date:
- Mon Jul 23 09:51:43 2018 +0000
- Revision:
- 0:41a622cdd86d
- Child:
- 1:fedfd309fb3c
Port from Adafruit_SGP30 arduino lib(https://github.com/adafruit/Adafruit_SGP30) to use Mbed API
Who changed what in which revision?
User | Revision | Line number | New 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 | } |