Adafruit_DPS310.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529
  1. /**************************************************************************/
  2. /**
  3. * @file Adafruit_DPS310.cpp
  4. * @author Limor Fried (Adafruit Industries)
  5. * @mainpage Adafruit DSP310 Barometric Pressure Sensor Library
  6. * @section intro_sec Introduction
  7. *
  8. * I2C Driver for the [Adafruit DPS310 barometric pressure breakout
  9. board](https://www.adafruit.com/product/4494)
  10. *
  11. * Adafruit invests time and resources providing this open source code,
  12. * please support Adafruit and open-source hardware by purchasing products from
  13. * Adafruit!
  14. * @see Adafruit_DPS310
  15. * @section dependencies Dependencies
  16. * This library depends on the [Adafruit BusIO
  17. library](https://github.com/adafruit/Adafruit_BusIO) and the [Adafruit Unified
  18. Sensor Library](https://github.com/adafruit/Adafruit_Sensor)
  19. * @section license License
  20. *
  21. * BSD (see license.txt)
  22. */
  23. /**************************************************************************/
  24. #if ARDUINO >= 100
  25. #include "Arduino.h"
  26. #else
  27. #include "WProgram.h"
  28. #endif
  29. #include <Adafruit_DPS310.h>
  30. #include <Wire.h>
  31. static int32_t oversample_scalefactor[] = {524288, 1572864, 3670016, 7864320,
  32. 253952, 516096, 1040384, 2088960};
  33. /**************************************************************************/
  34. /*!
  35. @brief Instantiates a new DPS310 class
  36. */
  37. /**************************************************************************/
  38. Adafruit_DPS310::Adafruit_DPS310(void) {
  39. temp_sensor = new Adafruit_DPS310_Temp(this);
  40. pressure_sensor = new Adafruit_DPS310_Pressure(this);
  41. }
  42. /**************************************************************************/
  43. /*!
  44. @brief Cleans up any allocations in our object
  45. */
  46. /**************************************************************************/
  47. Adafruit_DPS310::~Adafruit_DPS310(void) {
  48. delete temp_sensor;
  49. delete pressure_sensor;
  50. }
  51. /*!
  52. * @brief Sets up the hardware and initializes I2C
  53. * @param i2c_address
  54. * The I2C address to be used.
  55. * @param wire
  56. * The Wire object to be used for I2C connections.
  57. * @return True if initialization was successful, otherwise false.
  58. */
  59. bool Adafruit_DPS310::begin_I2C(uint8_t i2c_address, TwoWire *wire) {
  60. if (!i2c_dev) {
  61. i2c_dev = new Adafruit_I2CDevice(i2c_address, wire);
  62. }
  63. spi_dev = NULL;
  64. if (!i2c_dev->begin()) {
  65. return false;
  66. }
  67. return _init();
  68. }
  69. /*!
  70. * @brief Sets up the hardware and initializes hardware SPI
  71. * @param cs_pin The arduino pin # connected to chip select
  72. * @param theSPI The SPI object to be used for SPI connections.
  73. * @return True if initialization was successful, otherwise false.
  74. */
  75. boolean Adafruit_DPS310::begin_SPI(uint8_t cs_pin, SPIClass *theSPI) {
  76. i2c_dev = NULL;
  77. if (!spi_dev) {
  78. spi_dev = new Adafruit_SPIDevice(cs_pin,
  79. 1000000, // frequency
  80. SPI_BITORDER_MSBFIRST, // bit order
  81. SPI_MODE0, // data mode
  82. theSPI);
  83. }
  84. if (!spi_dev->begin()) {
  85. return false;
  86. }
  87. return _init();
  88. }
  89. /*!
  90. * @brief Sets up the hardware and initializes software SPI
  91. * @param cs_pin The arduino pin # connected to chip select
  92. * @param sck_pin The arduino pin # connected to SPI clock
  93. * @param miso_pin The arduino pin # connected to SPI MISO
  94. * @param mosi_pin The arduino pin # connected to SPI MOSI
  95. * @return True if initialization was successful, otherwise false.
  96. */
  97. bool Adafruit_DPS310::begin_SPI(int8_t cs_pin, int8_t sck_pin, int8_t miso_pin,
  98. int8_t mosi_pin) {
  99. i2c_dev = NULL;
  100. if (!spi_dev) {
  101. spi_dev = new Adafruit_SPIDevice(cs_pin, sck_pin, miso_pin, mosi_pin,
  102. 1000000, // frequency
  103. SPI_BITORDER_MSBFIRST, // bit order
  104. SPI_MODE0); // data mode
  105. }
  106. if (!spi_dev->begin()) {
  107. return false;
  108. }
  109. return _init();
  110. }
  111. /*!
  112. * @brief Common initialization code for I2C & SPI
  113. * @return True if initialization was successful, otherwise false.
  114. */
  115. bool Adafruit_DPS310::_init(void) {
  116. // Check connection
  117. Adafruit_BusIO_Register chip_id = Adafruit_BusIO_Register(
  118. i2c_dev, spi_dev, ADDRBIT8_HIGH_TOREAD, DPS310_PRODREVID, 1);
  119. // make sure we're talking to the right chip
  120. if (chip_id.read() != 0x10) {
  121. // No DPS310 detected ... return false
  122. return false;
  123. }
  124. reset();
  125. _readCalibration();
  126. // default to high precision
  127. configurePressure(DPS310_64HZ, DPS310_64SAMPLES);
  128. configureTemperature(DPS310_64HZ, DPS310_64SAMPLES);
  129. // continuous
  130. setMode(DPS310_CONT_PRESTEMP);
  131. // wait until we have at least one good measurement
  132. while (!temperatureAvailable() || !pressureAvailable()) {
  133. delay(10);
  134. }
  135. return true;
  136. }
  137. /**************************************************************************/
  138. /*!
  139. @brief Performs a software reset
  140. */
  141. /**************************************************************************/
  142. void Adafruit_DPS310::reset(void) {
  143. Adafruit_BusIO_Register SOFTRESET = Adafruit_BusIO_Register(
  144. i2c_dev, spi_dev, ADDRBIT8_HIGH_TOREAD, DPS310_RESET, 1);
  145. SOFTRESET.write(0x89);
  146. // Wait for a bit till its out of hardware reset
  147. delay(10);
  148. Adafruit_BusIO_Register MEAS_CFG = Adafruit_BusIO_Register(
  149. i2c_dev, spi_dev, ADDRBIT8_HIGH_TOREAD, DPS310_MEASCFG, 1);
  150. Adafruit_BusIO_RegisterBits SENSOR_RDY =
  151. Adafruit_BusIO_RegisterBits(&MEAS_CFG, 1, 6);
  152. while (!SENSOR_RDY.read()) {
  153. delay(1);
  154. }
  155. }
  156. static int32_t twosComplement(int32_t val, uint8_t bits) {
  157. if (val & ((uint32_t)1 << (bits - 1))) {
  158. val -= (uint32_t)1 << bits;
  159. }
  160. return val;
  161. }
  162. void Adafruit_DPS310::_readCalibration(void) {
  163. // Wait till we're ready to read calibration
  164. Adafruit_BusIO_Register MEAS_CFG = Adafruit_BusIO_Register(
  165. i2c_dev, spi_dev, ADDRBIT8_HIGH_TOREAD, DPS310_MEASCFG, 1);
  166. Adafruit_BusIO_RegisterBits CALIB_RDY =
  167. Adafruit_BusIO_RegisterBits(&MEAS_CFG, 1, 7);
  168. while (!CALIB_RDY.read()) {
  169. delay(1);
  170. }
  171. uint8_t coeffs[18];
  172. for (uint8_t addr = 0; addr < 18; addr++) {
  173. Adafruit_BusIO_Register coeff = Adafruit_BusIO_Register(
  174. i2c_dev, spi_dev, ADDRBIT8_HIGH_TOREAD, 0x10 + addr, 1);
  175. coeffs[addr] = coeff.read();
  176. }
  177. _c0 = ((uint16_t)coeffs[0] << 4) | (((uint16_t)coeffs[1] >> 4) & 0x0F);
  178. _c0 = twosComplement(_c0, 12);
  179. _c1 = twosComplement((((uint16_t)coeffs[1] & 0x0F) << 8) | coeffs[2], 12);
  180. _c00 = ((uint32_t)coeffs[3] << 12) | ((uint32_t)coeffs[4] << 4) |
  181. (((uint32_t)coeffs[5] >> 4) & 0x0F);
  182. _c00 = twosComplement(_c00, 20);
  183. _c10 = (((uint32_t)coeffs[5] & 0x0F) << 16) | ((uint32_t)coeffs[6] << 8) |
  184. (uint32_t)coeffs[7];
  185. _c10 = twosComplement(_c10, 20);
  186. _c01 = twosComplement(((uint16_t)coeffs[8] << 8) | (uint16_t)coeffs[9], 16);
  187. _c11 = twosComplement(((uint16_t)coeffs[10] << 8) | (uint16_t)coeffs[11], 16);
  188. _c20 = twosComplement(((uint16_t)coeffs[12] << 8) | (uint16_t)coeffs[13], 16);
  189. _c21 = twosComplement(((uint16_t)coeffs[14] << 8) | (uint16_t)coeffs[15], 16);
  190. _c30 = twosComplement(((uint16_t)coeffs[16] << 8) | (uint16_t)coeffs[17], 16);
  191. /*
  192. Serial.print("c0 = "); Serial.println(_c0);
  193. Serial.print("c1 = "); Serial.println(_c1);
  194. Serial.print("c00 = "); Serial.println(_c00);
  195. Serial.print("c10 = "); Serial.println(_c10);
  196. Serial.print("c01 = "); Serial.println(_c01);
  197. Serial.print("c11 = "); Serial.println(_c11);
  198. Serial.print("c20 = "); Serial.println(_c20);
  199. Serial.print("c21 = "); Serial.println(_c21);
  200. Serial.print("c30 = "); Serial.println(_c30);
  201. */
  202. }
  203. /**************************************************************************/
  204. /*!
  205. @brief Whether new temperature data is available
  206. @returns True if new data available to read
  207. */
  208. /**************************************************************************/
  209. bool Adafruit_DPS310::temperatureAvailable(void) {
  210. Adafruit_BusIO_Register MEAS_CFG = Adafruit_BusIO_Register(
  211. i2c_dev, spi_dev, ADDRBIT8_HIGH_TOREAD, DPS310_MEASCFG, 1);
  212. Adafruit_BusIO_RegisterBits tempbit =
  213. Adafruit_BusIO_RegisterBits(&MEAS_CFG, 1, 5);
  214. return tempbit.read();
  215. }
  216. /**************************************************************************/
  217. /*!
  218. @brief Whether new pressure data is available
  219. @returns True if new data available to read
  220. */
  221. /**************************************************************************/
  222. bool Adafruit_DPS310::pressureAvailable(void) {
  223. Adafruit_BusIO_Register MEAS_CFG = Adafruit_BusIO_Register(
  224. i2c_dev, spi_dev, ADDRBIT8_HIGH_TOREAD, DPS310_MEASCFG, 1);
  225. Adafruit_BusIO_RegisterBits presbit =
  226. Adafruit_BusIO_RegisterBits(&MEAS_CFG, 1, 4);
  227. return presbit.read();
  228. }
  229. /**************************************************************************/
  230. /*!
  231. * @brief Calculates the approximate altitude using barometric pressure and the
  232. * supplied sea level hPa as a reference.
  233. * @param seaLevelhPa
  234. * The current hPa at sea level.
  235. * @return The approximate altitude above sea level in meters.
  236. */
  237. /**************************************************************************/
  238. float Adafruit_DPS310::readAltitude(float seaLevelhPa) {
  239. float altitude;
  240. _read();
  241. altitude = 44330 * (1.0 - pow((_pressure / 100) / seaLevelhPa, 0.1903));
  242. return altitude;
  243. }
  244. /**************************************************************************/
  245. /*!
  246. @brief Set the operational mode of the sensor (continuous or one-shot)
  247. @param mode can be DPS310_IDLE, one shot: DPS310_ONE_PRESSURE or
  248. DPS310_ONE_TEMPERATURE, continuous: DPS310_CONT_PRESSURE, DPS310_CONT_TEMP,
  249. DPS310_CONT_PRESTEMP
  250. */
  251. /**************************************************************************/
  252. void Adafruit_DPS310::setMode(dps310_mode_t mode) {
  253. Adafruit_BusIO_Register MEAS_CFG = Adafruit_BusIO_Register(
  254. i2c_dev, spi_dev, ADDRBIT8_HIGH_TOREAD, DPS310_MEASCFG, 1);
  255. Adafruit_BusIO_RegisterBits modebits =
  256. Adafruit_BusIO_RegisterBits(&MEAS_CFG, 3, 0);
  257. modebits.write(mode);
  258. }
  259. /**************************************************************************/
  260. /*!
  261. @brief Set the sample rate and oversampling averaging for pressure
  262. @param rate How many samples per second to take
  263. @param os How many oversamples to average
  264. */
  265. /**************************************************************************/
  266. void Adafruit_DPS310::configurePressure(dps310_rate_t rate,
  267. dps310_oversample_t os) {
  268. Adafruit_BusIO_Register PRS_CFG = Adafruit_BusIO_Register(
  269. i2c_dev, spi_dev, ADDRBIT8_HIGH_TOREAD, DPS310_PRSCFG, 1);
  270. Adafruit_BusIO_RegisterBits ratebits =
  271. Adafruit_BusIO_RegisterBits(&PRS_CFG, 3, 4);
  272. Adafruit_BusIO_RegisterBits osbits =
  273. Adafruit_BusIO_RegisterBits(&PRS_CFG, 4, 0);
  274. ratebits.write(rate);
  275. osbits.write(os);
  276. Adafruit_BusIO_Register CFG_REG = Adafruit_BusIO_Register(
  277. i2c_dev, spi_dev, ADDRBIT8_HIGH_TOREAD, DPS310_CFGREG, 1);
  278. Adafruit_BusIO_RegisterBits shiftbit =
  279. Adafruit_BusIO_RegisterBits(&CFG_REG, 1, 2);
  280. if (os > DPS310_8SAMPLES) {
  281. shiftbit.write(1);
  282. } else {
  283. shiftbit.write(0);
  284. }
  285. pressure_scale = oversample_scalefactor[os];
  286. }
  287. /**************************************************************************/
  288. /*!
  289. @brief Set the sample rate and oversampling averaging for temperature
  290. @param rate How many samples per second to take
  291. @param os How many oversamples to average
  292. */
  293. /**************************************************************************/
  294. void Adafruit_DPS310::configureTemperature(dps310_rate_t rate,
  295. dps310_oversample_t os) {
  296. Adafruit_BusIO_Register TMP_CFG = Adafruit_BusIO_Register(
  297. i2c_dev, spi_dev, ADDRBIT8_HIGH_TOREAD, DPS310_TMPCFG, 1);
  298. Adafruit_BusIO_RegisterBits ratebits =
  299. Adafruit_BusIO_RegisterBits(&TMP_CFG, 3, 4);
  300. Adafruit_BusIO_RegisterBits osbits =
  301. Adafruit_BusIO_RegisterBits(&TMP_CFG, 4, 0);
  302. ratebits.write(rate);
  303. osbits.write(os);
  304. temp_scale = oversample_scalefactor[os];
  305. // Set shift bit if necessary
  306. Adafruit_BusIO_Register CFG_REG = Adafruit_BusIO_Register(
  307. i2c_dev, spi_dev, ADDRBIT8_HIGH_TOREAD, DPS310_CFGREG, 1);
  308. Adafruit_BusIO_RegisterBits shiftbit =
  309. Adafruit_BusIO_RegisterBits(&CFG_REG, 1, 3);
  310. if (os > DPS310_8SAMPLES) {
  311. shiftbit.write(1);
  312. } else {
  313. shiftbit.write(0);
  314. }
  315. // Find out what our calibration source is
  316. Adafruit_BusIO_Register TMP_COEFF = Adafruit_BusIO_Register(
  317. i2c_dev, spi_dev, ADDRBIT8_HIGH_TOREAD, DPS310_TMPCOEFSRCE, 1);
  318. Adafruit_BusIO_RegisterBits srcbit =
  319. Adafruit_BusIO_RegisterBits(&TMP_COEFF, 1, 7);
  320. // Serial.print("temp coeff: 0x"); Serial.println(TMP_COEFF.read(), HEX);
  321. // Serial.print("src bit: 0x"); Serial.println(srcbit.read(), HEX);
  322. // the bit is in another register
  323. Adafruit_BusIO_RegisterBits extbit =
  324. Adafruit_BusIO_RegisterBits(&TMP_CFG, 1, 7);
  325. extbit.write(srcbit.read());
  326. }
  327. /**************************************************************************/
  328. /*!
  329. @brief Read the XYZ data from the sensor and store in the internal
  330. raw_pressure, raw_temperature, _pressure and _temperature variables.
  331. */
  332. /**************************************************************************/
  333. void Adafruit_DPS310::_read(void) {
  334. Adafruit_BusIO_Register PRS_B2 = Adafruit_BusIO_Register(
  335. i2c_dev, spi_dev, ADDRBIT8_HIGH_TOREAD, DPS310_PRSB2, 3, MSBFIRST);
  336. Adafruit_BusIO_Register TMP_B2 = Adafruit_BusIO_Register(
  337. i2c_dev, spi_dev, ADDRBIT8_HIGH_TOREAD, DPS310_TMPB2, 3, MSBFIRST);
  338. raw_temperature = twosComplement(TMP_B2.read(), 24);
  339. raw_pressure = twosComplement(PRS_B2.read(), 24);
  340. _scaled_rawtemp = (float)raw_temperature / temp_scale;
  341. _temperature = _scaled_rawtemp * _c1 + _c0 / 2.0;
  342. // Serial.print("Temp: "); Serial.println(_temperature);
  343. // Serial.print("Raw prs: " ); Serial.println(raw_pressure);
  344. _pressure = (float)raw_pressure / pressure_scale;
  345. // Serial.print("Scaled prs:" ); Serial.println(_pressure, 6);
  346. /*
  347. Serial.println(_c00);
  348. Serial.println(_pressure * ((int32_t)_c10 + _pressure * ((int32_t)_c20 +
  349. _pressure * (int32_t)_c30)), 6); Serial.println(_scaled_rawtemp *
  350. ((int32_t)_c01 + _pressure * ((int32_t)_c11 + _pressure * (int32_t)_c21)), 6);
  351. */
  352. _pressure =
  353. (int32_t)_c00 +
  354. _pressure * ((int32_t)_c10 +
  355. _pressure * ((int32_t)_c20 + _pressure * (int32_t)_c30)) +
  356. _scaled_rawtemp *
  357. ((int32_t)_c01 +
  358. _pressure * ((int32_t)_c11 + _pressure * (int32_t)_c21));
  359. // Serial.print("Press: "); Serial.println(_pressure);
  360. }
  361. /**************************************************************************/
  362. /*!
  363. @brief Gets the most recent sensor event, Adafruit Unified Sensor format
  364. @param temp_event Pointer to an Adafruit Unified sensor_event_t object that
  365. we'll fill in with temperature data
  366. @param pressure_event Pointer to an Adafruit Unified sensor_event_t object
  367. that we'll fill in with pressure data
  368. @returns True on successful read
  369. */
  370. /**************************************************************************/
  371. bool Adafruit_DPS310::getEvents(sensors_event_t *temp_event,
  372. sensors_event_t *pressure_event) {
  373. _read();
  374. if (temp_event != NULL) {
  375. /* Clear the event */
  376. memset(temp_event, 0, sizeof(sensors_event_t));
  377. // fill in deets
  378. temp_event->version = 1;
  379. temp_event->sensor_id = _sensorID;
  380. temp_event->type = SENSOR_TYPE_AMBIENT_TEMPERATURE;
  381. temp_event->timestamp = millis();
  382. temp_event->temperature = _temperature;
  383. }
  384. if (pressure_event != NULL) {
  385. memset(pressure_event, 0, sizeof(sensors_event_t));
  386. pressure_event->version = 1;
  387. pressure_event->sensor_id = _sensorID;
  388. pressure_event->type = SENSOR_TYPE_PRESSURE;
  389. pressure_event->timestamp = millis();
  390. pressure_event->pressure = _pressure / 100;
  391. }
  392. return true;
  393. }
  394. /*!
  395. @brief Gets an Adafruit Unified Sensor object for the temp sensor component
  396. @return Adafruit_Sensor pointer to temperature sensor
  397. */
  398. Adafruit_Sensor *Adafruit_DPS310::getTemperatureSensor(void) {
  399. return temp_sensor;
  400. }
  401. /*!
  402. @brief Gets an Adafruit Unified Sensor object for the pressure sensor
  403. component
  404. @return Adafruit_Sensor pointer to pressure sensor
  405. */
  406. Adafruit_Sensor *Adafruit_DPS310::getPressureSensor(void) {
  407. return pressure_sensor;
  408. }
  409. /**************************************************************************/
  410. /*!
  411. @brief Gets the sensor_t data for the DPS310's temperature sensor
  412. */
  413. /**************************************************************************/
  414. void Adafruit_DPS310_Temp::getSensor(sensor_t *sensor) {
  415. /* Clear the sensor_t object */
  416. memset(sensor, 0, sizeof(sensor_t));
  417. /* Insert the sensor name in the fixed length char array */
  418. strncpy(sensor->name, "DPS310", sizeof(sensor->name) - 1);
  419. sensor->name[sizeof(sensor->name) - 1] = 0;
  420. sensor->version = 1;
  421. sensor->sensor_id = _sensorID;
  422. sensor->type = SENSOR_TYPE_AMBIENT_TEMPERATURE;
  423. sensor->min_delay = 0;
  424. sensor->min_value = -40.0; /* Temperature range -40 ~ +85 C */
  425. sensor->max_value = +85.0;
  426. sensor->resolution = 0.01; /* 0.01 C */
  427. }
  428. /**************************************************************************/
  429. /*!
  430. @brief Gets the temperature as a standard sensor event
  431. @param event Sensor event object that will be populated
  432. @returns True
  433. */
  434. /**************************************************************************/
  435. bool Adafruit_DPS310_Temp::getEvent(sensors_event_t *event) {
  436. return _theDPS310->getEvents(event, NULL);
  437. }
  438. /**************************************************************************/
  439. /*!
  440. @brief Gets the sensor_t data for the DPS310's pressure sensor
  441. */
  442. /**************************************************************************/
  443. void Adafruit_DPS310_Pressure::getSensor(sensor_t *sensor) {
  444. /* Clear the sensor_t object */
  445. memset(sensor, 0, sizeof(sensor_t));
  446. /* Insert the sensor name in the fixed length char array */
  447. strncpy(sensor->name, "DPS310", sizeof(sensor->name) - 1);
  448. sensor->name[sizeof(sensor->name) - 1] = 0;
  449. sensor->version = 1;
  450. sensor->sensor_id = _sensorID;
  451. sensor->type = SENSOR_TYPE_PRESSURE;
  452. sensor->min_delay = 0;
  453. sensor->min_value = 300.0; /* 300 ~ 1200 hPa */
  454. sensor->max_value = 1200.0;
  455. sensor->resolution = 0.002; /* 0.002 hPa relative */
  456. }
  457. /**************************************************************************/
  458. /*!
  459. @brief Gets the pressure as a standard sensor event
  460. @param event Sensor event object that will be populated
  461. @returns True
  462. */
  463. /**************************************************************************/
  464. bool Adafruit_DPS310_Pressure::getEvent(sensors_event_t *event) {
  465. return _theDPS310->getEvents(NULL, event);
  466. }