Adafruit_SGP30.cpp 7.1 KB

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