From 28499bee82f3fb7d0ba9a976a1cc5e2311abd728 Mon Sep 17 00:00:00 2001 From: Cedric von Gunten Date: Sun, 7 Jan 2024 16:14:19 +0100 Subject: [PATCH 1/3] feature: added qmp6988 sensor --- README.md | 5 +- components/qmp6988/.eil.yml | 23 ++ components/qmp6988/CMakeLists.txt | 11 + components/qmp6988/LICENSE | 28 ++ components/qmp6988/component.mk | 2 + components/qmp6988/qmp6988.c | 319 ++++++++++++++++++ components/qmp6988/qmp6988.h | 197 +++++++++++ devtools/persons.yml | 4 + examples/qmp6988/default/CMakeLists.txt | 8 + examples/qmp6988/default/Makefile | 6 + examples/qmp6988/default/README.md | 16 + examples/qmp6988/default/main/CMakeLists.txt | 2 + .../qmp6988/default/main/Kconfig.projbuild | 43 +++ examples/qmp6988/default/main/component.mk | 1 + examples/qmp6988/default/main/main.c | 116 +++++++ .../default/sdkconfig.defaults.esp8266 | 1 + 16 files changed, 781 insertions(+), 1 deletion(-) create mode 100644 components/qmp6988/.eil.yml create mode 100644 components/qmp6988/CMakeLists.txt create mode 100644 components/qmp6988/LICENSE create mode 100644 components/qmp6988/component.mk create mode 100644 components/qmp6988/qmp6988.c create mode 100644 components/qmp6988/qmp6988.h create mode 100644 examples/qmp6988/default/CMakeLists.txt create mode 100644 examples/qmp6988/default/Makefile create mode 100644 examples/qmp6988/default/README.md create mode 100644 examples/qmp6988/default/main/CMakeLists.txt create mode 100644 examples/qmp6988/default/main/Kconfig.projbuild create mode 100644 examples/qmp6988/default/main/component.mk create mode 100644 examples/qmp6988/default/main/main.c create mode 100644 examples/qmp6988/default/sdkconfig.defaults.esp8266 diff --git a/README.md b/README.md index a2e85999..38e12bfb 100644 --- a/README.md +++ b/README.md @@ -252,6 +252,7 @@ or [GitLab examples](https://gitlab.com/UncleRus/esp-idf-lib/tree/master/example | **bmp280** | Driver for BMP280/BME280 digital pressure sensor | MIT | esp32, esp8266, esp32s2, esp32c3 | yes | | **dps310** | Driver for DPS310 barometric pressure sensor | ISC | esp32, esp8266, esp32s2, esp32c3 | yes | | **ms5611** | Driver for barometic pressure sensor MS5611-01BA03 | BSD-3-Clause | esp32, esp8266, esp32s2, esp32c3 | yes | +| **qmp6988** | Driver for QMP6988 digital temperature and pressure sensor | BSD-3-Clause | esp32, esp8266, esp32s2, esp32c3 | yes | ### Real-time clocks @@ -286,6 +287,7 @@ or [GitLab examples](https://gitlab.com/UncleRus/esp-idf-lib/tree/master/example | **mcp960x** | Driver for MCP9600/MCP9601, thermocouple EMF to temperature converter | BSD-3-Clause | esp32, esp8266, esp32s2, esp32c3 | yes | | **mcp9808** | Driver for MCP9808 digital temperature sensor | BSD-3-Clause | esp32, esp8266, esp32s2, esp32c3 | yes | | **ms5611** | Driver for barometic pressure sensor MS5611-01BA03 | BSD-3-Clause | esp32, esp8266, esp32s2, esp32c3 | yes | +| **qmp6988** | Driver for QMP6988 digital temperature and pressure sensor | BSD-3-Clause | esp32, esp8266, esp32s2, esp32c3 | yes | | **sfa3x** | Driver for SFA30 formaldehyde detection module (I2C) | BSD-3-Clause | esp32, esp8266, esp32s2, esp32c3 | yes | | **sht3x** | Driver for Sensirion SHT30/SHT31/SHT35 digital temperature and humidity sensor | BSD-3-Clause | esp32, esp8266, esp32s2, esp32c3 | yes | | **sht4x** | Driver for Sensirion SHT40/SHT41/SHT45 digital temperature and humidity sensor | BSD-3-Clause | esp32, esp8266, esp32s2, esp32c3 | yes | @@ -308,6 +310,7 @@ or [GitLab examples](https://gitlab.com/UncleRus/esp-idf-lib/tree/master/example - [BernhardG](https://gitlab.com/mrnice): `ms5611` - [BhuvanchandraD](https://github.com/bhuvanchandra): `ds3231` - [Brian Schwind](https://github.com/bschwind): `tsl2561` `tsl4531` +- [Cedric von Gunten](https://github.com/vonguced): `qmp6988` - [Christian Skjerning](https://github.com/slimcdk): `sts3x` - [David Douard](https://github.com/douardda): `mhz19b` - [Erriez](https://github.com/Erriez): `mhz19b` @@ -332,7 +335,7 @@ or [GitLab examples](https://gitlab.com/UncleRus/esp-idf-lib/tree/master/example - Pavel Merzlyakov: `ds1302` - [Raghav Jha](https://github.com/horsemann07): `mpu6050` - RichardA: `ds3231` -- [Ruslan V. Uss](https://github.com/UncleRus): `ads111x` `aht` `am2320` `bh1750` `bh1900nux` `bme680` `bmp180` `bmp280` `button` `calibration` `ccs811` `dht` `ds1302` `ds1307` `ds18x20` `ds3231` `ds3502` `encoder` `framebuffer` `hd44780` `hdc1000` `hmc5883l` `hx711` `i2cdev` `ina219` `ina260` `ina3221` `led_strip` `led_strip_spi` `max31725` `max31855` `max31865` `max7219` `mcp23008` `mcp23x17` `mcp342x` `mcp4725` `mcp960x` `mcp9808` `mpu6050` `ms5611` `onewire` `pca9557` `pca9685` `pcf8563` `pcf8574` `pcf8575` `pcf8591` `qmc5883l` `rda5807m` `scd30` `scd4x` `sfa3x` `sgp40` `sht3x` `sht4x` `si7021` `sts21` `sts3x` `tca6424a` `tca9548` `tca95x5` `tda74xx` `tsl2561` `tsl4531` `tsys01` `ultrasonic` `wiegand` +- [Ruslan V. Uss](https://github.com/UncleRus): `ads111x` `aht` `am2320` `bh1750` `bh1900nux` `bme680` `bmp180` `bmp280` `button` `calibration` `ccs811` `dht` `ds1302` `ds1307` `ds18x20` `ds3231` `ds3502` `encoder` `framebuffer` `hd44780` `hdc1000` `hmc5883l` `hx711` `i2cdev` `ina219` `ina260` `ina3221` `led_strip` `led_strip_spi` `max31725` `max31855` `max31865` `max7219` `mcp23008` `mcp23x17` `mcp342x` `mcp4725` `mcp960x` `mcp9808` `mpu6050` `ms5611` `onewire` `pca9557` `pca9685` `pcf8563` `pcf8574` `pcf8575` `pcf8591` `qmc5883l` `qmp6988` `rda5807m` `scd30` `scd4x` `sfa3x` `sgp40` `sht3x` `sht4x` `si7021` `sts21` `sts3x` `tca6424a` `tca9548` `tca95x5` `tda74xx` `tsl2561` `tsl4531` `tsys01` `ultrasonic` `wiegand` - [Sensirion AG](https://github.com/Sensirion): `scd30` `scd4x` `sfa3x` - [sheinz](https://github.com/sheinz): `bmp280` - [Thanh Pham](https://github.com/panoti): `pcf8591` diff --git a/components/qmp6988/.eil.yml b/components/qmp6988/.eil.yml new file mode 100644 index 00000000..210db5b0 --- /dev/null +++ b/components/qmp6988/.eil.yml @@ -0,0 +1,23 @@ +name: qmp6988 +description: Driver for QMP6988 digital temperature and pressure sensor +version: 0.0.1 +groups: + - temperature + - pressure +code_owners: vonguced +depends: + - i2cdev + - log + - esp_idf_lib_helpers +thread_safe: yes +targets: + - esp32 + - esp8266 + - esp32s2 + - esp32c3 +license: BSD-3 +copyrights: + - name: UncleRus + year: 2016 + - name: vonguced + year: 2024 diff --git a/components/qmp6988/CMakeLists.txt b/components/qmp6988/CMakeLists.txt new file mode 100644 index 00000000..2522582a --- /dev/null +++ b/components/qmp6988/CMakeLists.txt @@ -0,0 +1,11 @@ +if(${IDF_VERSION_MAJOR} STREQUAL 4 AND ${IDF_VERSION_MINOR} STREQUAL 1 AND ${IDF_VERSION_PATCH} STREQUAL 3) + set(req i2cdev log esp_idf_lib_helpers) +else() + set(req i2cdev log esp_idf_lib_helpers esp_timer) +endif() + +idf_component_register( + SRCS qmp6988.c + INCLUDE_DIRS . + REQUIRES ${req} +) \ No newline at end of file diff --git a/components/qmp6988/LICENSE b/components/qmp6988/LICENSE new file mode 100644 index 00000000..cc54db00 --- /dev/null +++ b/components/qmp6988/LICENSE @@ -0,0 +1,28 @@ +Copyright (c) 2019 Ruslan V. Uss (https://github.com/UncleRus) +Copyright (c) 2022 m5stack (https://github.com/m5stack) +Copyright (c) 2024 vonguced (https://github.com/vonguced) + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of itscontributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/components/qmp6988/component.mk b/components/qmp6988/component.mk new file mode 100644 index 00000000..4071e351 --- /dev/null +++ b/components/qmp6988/component.mk @@ -0,0 +1,2 @@ +COMPONENT_ADD_INCLUDEDIRS = . +COMPONENT_DEPENDS = i2cdev log esp_idf_lib_helpers \ No newline at end of file diff --git a/components/qmp6988/qmp6988.c b/components/qmp6988/qmp6988.c new file mode 100644 index 00000000..ed90ce0b --- /dev/null +++ b/components/qmp6988/qmp6988.c @@ -0,0 +1,319 @@ +#include +#include +#include +#include +#include +#include +#include "qmp6988.h" + +#define I2C_FREQ_HZ 1000000 // 1MHz + +static const char *TAG = "qmp6988"; + +// due to the fact that ticks can be smaller than portTICK_PERIOD_MS, one and +// a half tick period added to the duration to be sure that waiting time for +// the results is long enough +#define TIME_TO_TICKS(ms) (1 + ((ms) + (portTICK_PERIOD_MS - 1) + portTICK_PERIOD_MS / 2) / portTICK_PERIOD_MS) + +#define CHECK(x) \ + do \ + { \ + esp_err_t __; \ + if ((__ = x) != ESP_OK) \ + return __; \ + } \ + while (0) +#define CHECK_ARG(VAL) \ + do \ + { \ + if (!(VAL)) \ + return ESP_ERR_INVALID_ARG; \ + } \ + while (0) + +static esp_err_t write_reg(qmp6988_t *dev, uint8_t out_reg, uint8_t cmd) +{ + I2C_DEV_TAKE_MUTEX(&dev->i2c_dev); + I2C_DEV_CHECK(&dev->i2c_dev, i2c_dev_write(&dev->i2c_dev, &out_reg, sizeof(out_reg), &cmd, sizeof(cmd))); + I2C_DEV_GIVE_MUTEX(&dev->i2c_dev); + + return ESP_OK; +} + +esp_err_t qmp6988_read_reg(qmp6988_t *dev, uint8_t out_reg, qmp6988_raw_data_t *raw_data) +{ + CHECK(i2c_dev_read(&dev->i2c_dev, &out_reg, sizeof(uint8_t), raw_data, sizeof(qmp6988_raw_data_t))); + return ESP_OK; +} + +esp_err_t qmp6988_device_check(qmp6988_t *dev) +{ + qmp6988_raw_data_t chip_id = 0x00; + qmp6988_read_reg(dev, QMP6988_CHIP_ID_REG, &chip_id); + + if (chip_id == QMP6988_CHIP_ID) + { + return ESP_OK; + } + else + { + ESP_LOGE(TAG, "QMP6988 chip id not matching. Expected: 0x%02X got: 0x%02X", QMP6988_CHIP_ID, chip_id); + return ESP_OK; + return ESP_ERR_INVALID_RESPONSE; + } + + return ESP_FAIL; +} + +esp_err_t qmp6988_get_calibration_data(qmp6988_t *dev) +{ + uint8_t a_data_uint8_tr[QMP6988_CALIBRATION_DATA_LENGTH] = { 0 }; + int len; + + for (len = 0; len < QMP6988_CALIBRATION_DATA_LENGTH; len += 1) + { + CHECK(qmp6988_read_reg(dev, QMP6988_CALIBRATION_DATA_START + len, &a_data_uint8_tr[len])); + } + + dev->qmp6988_cali.COE_a0 = (QMP6988_S32_t)(((QMP6988_S32_t)a_data_uint8_tr[18] << SHIFT_LEFT_12_POSITION) | (a_data_uint8_tr[19] << SHIFT_LEFT_4_POSITION) | (a_data_uint8_tr[24] & 0x0f)) << 12; + dev->qmp6988_cali.COE_a0 = dev->qmp6988_cali.COE_a0 >> 12; + + dev->qmp6988_cali.COE_a1 = (QMP6988_S16_t)((a_data_uint8_tr[20] << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[21]); + + dev->qmp6988_cali.COE_a2 = (QMP6988_S16_t)((a_data_uint8_tr[22] << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[23]); + + dev->qmp6988_cali.COE_b00 + = (QMP6988_S32_t)((((QMP6988_S32_t)a_data_uint8_tr[0] << SHIFT_LEFT_12_POSITION) | (a_data_uint8_tr[1] << SHIFT_LEFT_4_POSITION) | ((a_data_uint8_tr[24] & 0xf0) >> SHIFT_RIGHT_4_POSITION)) + << 12); + dev->qmp6988_cali.COE_b00 = dev->qmp6988_cali.COE_b00 >> 12; + + dev->qmp6988_cali.COE_bt1 = (QMP6988_S16_t)((a_data_uint8_tr[2] << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[3]); + + dev->qmp6988_cali.COE_bt2 = (QMP6988_S16_t)((a_data_uint8_tr[4] << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[5]); + + dev->qmp6988_cali.COE_bp1 = (QMP6988_S16_t)((a_data_uint8_tr[6] << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[7]); + + dev->qmp6988_cali.COE_b11 = (QMP6988_S16_t)((a_data_uint8_tr[8] << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[9]); + + dev->qmp6988_cali.COE_bp2 = (QMP6988_S16_t)((a_data_uint8_tr[10] << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[11]); + + dev->qmp6988_cali.COE_b12 = (QMP6988_S16_t)((a_data_uint8_tr[12] << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[13]); + + dev->qmp6988_cali.COE_b21 = (QMP6988_S16_t)((a_data_uint8_tr[14] << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[15]); + + dev->qmp6988_cali.COE_bp3 = (QMP6988_S16_t)((a_data_uint8_tr[16] << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[17]); + + dev->ik.a0 = dev->qmp6988_cali.COE_a0; // 20Q4 + dev->ik.b00 = dev->qmp6988_cali.COE_b00; // 20Q4 + + dev->ik.a1 = 3608L * (QMP6988_S32_t)dev->qmp6988_cali.COE_a1 - 1731677965L; // 31Q23 + dev->ik.a2 = 16889L * (QMP6988_S32_t)dev->qmp6988_cali.COE_a2 - 87619360L; // 30Q47 + + dev->ik.bt1 = 2982L * (QMP6988_S64_t)dev->qmp6988_cali.COE_bt1 + 107370906L; // 28Q15 + dev->ik.bt2 = 329854L * (QMP6988_S64_t)dev->qmp6988_cali.COE_bt2 + 108083093L; // 34Q38 + dev->ik.bp1 = 19923L * (QMP6988_S64_t)dev->qmp6988_cali.COE_bp1 + 1133836764L; // 31Q20 + dev->ik.b11 = 2406L * (QMP6988_S64_t)dev->qmp6988_cali.COE_b11 + 118215883L; // 28Q34 + dev->ik.bp2 = 3079L * (QMP6988_S64_t)dev->qmp6988_cali.COE_bp2 - 181579595L; // 29Q43 + dev->ik.b12 = 6846L * (QMP6988_S64_t)dev->qmp6988_cali.COE_b12 + 85590281L; // 29Q53 + dev->ik.b21 = 13836L * (QMP6988_S64_t)dev->qmp6988_cali.COE_b21 + 79333336L; // 29Q60 + dev->ik.bp3 = 2915L * (QMP6988_S64_t)dev->qmp6988_cali.COE_bp3 + 157155561L; // 28Q65 + return ESP_OK; +} + +esp_err_t qmp6988_setup_powermode(qmp6988_t *dev, qmp6988_power_mode_t power_mode) +{ + uint8_t data = 0x00; + + dev->power_mode = power_mode; + CHECK(qmp6988_read_reg(dev, QMP6988_CTRLMEAS_REG, &data)); + data &= 0xfc; + data |= power_mode; + CHECK(write_reg(dev, QMP6988_CTRLMEAS_REG, data)); + + vTaskDelay(TIME_TO_TICKS(20)); + + return ESP_OK; +} + +esp_err_t qmp6988_set_filter(qmp6988_t *dev, qmp6988_filter_t filter_mode) +{ + dev->filter_mode = filter_mode; + CHECK(write_reg(dev, QMP6988_CONFIG_REG, filter_mode)); + vTaskDelay(TIME_TO_TICKS(20)); + + return ESP_OK; +} + +esp_err_t qmp6988_set_p_oversampling(qmp6988_t *dev, qmp6988_oversampling_t oversampling_p_mode) +{ + qmp6988_raw_data_t data = 0x00; + + dev->oversampling_p_mode = oversampling_p_mode; + CHECK(qmp6988_read_reg(dev, QMP6988_CTRLMEAS_REG, &data)); + data &= 0xe3; + data |= (oversampling_p_mode << 2); + CHECK(write_reg(dev, QMP6988_CTRLMEAS_REG, data)); + vTaskDelay(TIME_TO_TICKS(20)); + + return ESP_OK; +} + +esp_err_t qmp6988_set_t_oversampling(qmp6988_t *dev, qmp6988_oversampling_t oversampling_t_mode) +{ + qmp6988_raw_data_t data = 0x00; + + dev->oversampling_t_mode = oversampling_t_mode; + CHECK(qmp6988_read_reg(dev, QMP6988_CTRLMEAS_REG, &data)); + data &= 0x1f; + data |= (oversampling_t_mode << 5); + CHECK(write_reg(dev, QMP6988_CTRLMEAS_REG, data)); + vTaskDelay(TIME_TO_TICKS(20)); + + return ESP_OK; +} + +QMP6988_S16_t qmp6988_conv_Tx_02e(qmp6988_ik_data_t *ik, QMP6988_S32_t dt) +{ + QMP6988_S16_t ret; + QMP6988_S64_t wk1, wk2; + + // wk1: 60Q4 // bit size + wk1 = ((QMP6988_S64_t)ik->a1 * (QMP6988_S64_t)dt); // 31Q23+24-1=54 (54Q23) + wk2 = ((QMP6988_S64_t)ik->a2 * (QMP6988_S64_t)dt) >> 14; // 30Q47+24-1=53 (39Q33) + wk2 = (wk2 * (QMP6988_S64_t)dt) >> 10; // 39Q33+24-1=62 (52Q23) + wk2 = ((wk1 + wk2) / 32767) >> 19; // 54,52->55Q23 (20Q04) + ret = (QMP6988_S16_t)((ik->a0 + wk2) >> 4); // 21Q4 -> 17Q0 + return ret; +} + +QMP6988_S32_t qmp6988_get_pressure_02e(qmp6988_ik_data_t *ik, QMP6988_S32_t dp, QMP6988_S16_t tx) +{ + QMP6988_S32_t ret; + QMP6988_S64_t wk1, wk2, wk3; + + // wk1 = 48Q16 // bit size + wk1 = ((QMP6988_S64_t)ik->bt1 * (QMP6988_S64_t)tx); // 28Q15+16-1=43 (43Q15) + wk2 = ((QMP6988_S64_t)ik->bp1 * (QMP6988_S64_t)dp) >> 5; // 31Q20+24-1=54 (49Q15) + wk1 += wk2; // 43,49->50Q15 + wk2 = ((QMP6988_S64_t)ik->bt2 * (QMP6988_S64_t)tx) >> 1; // 34Q38+16-1=49 (48Q37) + wk2 = (wk2 * (QMP6988_S64_t)tx) >> 8; // 48Q37+16-1=63 (55Q29) + wk3 = wk2; // 55Q29 + wk2 = ((QMP6988_S64_t)ik->b11 * (QMP6988_S64_t)tx) >> 4; // 28Q34+16-1=43 (39Q30) + wk2 = (wk2 * (QMP6988_S64_t)dp) >> 1; // 39Q30+24-1=62 (61Q29) + wk3 += wk2; // 55,61->62Q29 + wk2 = ((QMP6988_S64_t)ik->bp2 * (QMP6988_S64_t)dp) >> 13; // 29Q43+24-1=52 (39Q30) + wk2 = (wk2 * (QMP6988_S64_t)dp) >> 1; // 39Q30+24-1=62 (61Q29) + wk3 += wk2; // 62,61->63Q29 + wk1 += wk3 >> 14; // Q29 >> 14 -> Q15 + wk2 = ((QMP6988_S64_t)ik->b12 * (QMP6988_S64_t)tx); // 29Q53+16-1=45 (45Q53) + wk2 = (wk2 * (QMP6988_S64_t)tx) >> 22; // 45Q53+16-1=61 (39Q31) + wk2 = (wk2 * (QMP6988_S64_t)dp) >> 1; // 39Q31+24-1=62 (61Q30) + wk3 = wk2; // 61Q30 + wk2 = ((QMP6988_S64_t)ik->b21 * (QMP6988_S64_t)tx) >> 6; // 29Q60+16-1=45 (39Q54) + wk2 = (wk2 * (QMP6988_S64_t)dp) >> 23; // 39Q54+24-1=62 (39Q31) + wk2 = (wk2 * (QMP6988_S64_t)dp) >> 1; // 39Q31+24-1=62 (61Q20) + wk3 += wk2; // 61,61->62Q30 + wk2 = ((QMP6988_S64_t)ik->bp3 * (QMP6988_S64_t)dp) >> 12; // 28Q65+24-1=51 (39Q53) + wk2 = (wk2 * (QMP6988_S64_t)dp) >> 23; // 39Q53+24-1=62 (39Q30) + wk2 = (wk2 * (QMP6988_S64_t)dp); // 39Q30+24-1=62 (62Q30) + wk3 += wk2; // 62,62->63Q30 + wk1 += wk3 >> 15; // Q30 >> 15 = Q15 + wk1 /= 32767L; + wk1 >>= 11; // Q15 >> 7 = Q4 + wk1 += ik->b00; // Q4 + 20Q4 + // wk1 >>= 4; // 28Q4 -> 24Q0 + ret = (QMP6988_S32_t)wk1; + return ret; +} + +float qmp6988_calc_altitude(float pressure, float temp) +{ + float altitude; + + altitude = (pow((101325 / pressure), 1 / 5.257) - 1) * (temp + 273.15) / 0.0065; + ESP_LOGI(TAG, "altitude = %f\r\n", altitude); + return altitude; +} + +float qmp6988_calc_pressure(qmp6988_t *dev) +{ + QMP6988_U32_t P_read, T_read; + QMP6988_S32_t P_raw, T_raw; + uint8_t a_data_uint8_tr[6] = { 0 }; + QMP6988_S32_t T_int, P_int; + int len; + + // press + for (len = 0; len < 3; len += 1) + { + CHECK(qmp6988_read_reg(dev, QMP6988_PRESSURE_MSB_REG + len, &a_data_uint8_tr[len])); + } + P_read = (QMP6988_U32_t)((((QMP6988_U32_t)(a_data_uint8_tr[0])) << SHIFT_LEFT_16_POSITION) | (((QMP6988_U16_t)(a_data_uint8_tr[1])) << SHIFT_LEFT_8_POSITION) | (a_data_uint8_tr[2])); + P_raw = (QMP6988_S32_t)(P_read - SUBTRACTOR); + + // temp + for (len = 3; len < 6; len += 1) + { + CHECK(qmp6988_read_reg(dev, QMP6988_TEMPERATURE_MSB_REG + len - 3, &a_data_uint8_tr[len])); + } + T_read = (QMP6988_U32_t)((((QMP6988_U32_t)(a_data_uint8_tr[3])) << SHIFT_LEFT_16_POSITION) | (((QMP6988_U16_t)(a_data_uint8_tr[4])) << SHIFT_LEFT_8_POSITION) | (a_data_uint8_tr[5])); + T_raw = (QMP6988_S32_t)(T_read - SUBTRACTOR); + + T_int = qmp6988_conv_Tx_02e(&(dev->ik), T_raw); + P_int = qmp6988_get_pressure_02e(&(dev->ik), P_raw, T_int); + dev->temperature = (float)T_int / 256.0f; + dev->pressure = (float)P_int / 16.0f; + + return dev->pressure; +} + +float qmp6988_calc_temperature(qmp6988_t *dev) +{ + qmp6988_calc_pressure(dev); + return dev->temperature; +} + +/////////////////////////////////////////////////////////////////////////// + +esp_err_t qmp6988_init_desc(qmp6988_t *dev, uint8_t addr, i2c_port_t port, gpio_num_t sda_gpio, gpio_num_t scl_gpio) +{ + CHECK_ARG(dev); + + dev->i2c_dev.port = port; + dev->i2c_dev.addr = addr; + dev->i2c_dev.cfg.sda_io_num = sda_gpio; + dev->i2c_dev.cfg.scl_io_num = scl_gpio; +#if HELPER_TARGET_IS_ESP32 + dev->i2c_dev.cfg.master.clk_speed = I2C_FREQ_HZ; +#endif + + return i2c_dev_create_mutex(&dev->i2c_dev); +} + +esp_err_t qmp6988_free_desc(qmp6988_t *dev) +{ + CHECK_ARG(dev); + + return i2c_dev_delete_mutex(&dev->i2c_dev); +} + +esp_err_t qmp6988_init(qmp6988_t *dev) +{ + CHECK_ARG(dev); + + dev->power_mode = QMP6988_SLEEP_MODE; + dev->filter_mode = QMP6988_FILTERCOEFF_4; + dev->oversampling_t_mode = QMP6988_OVERSAMPLING_1X; + dev->oversampling_p_mode = QMP6988_OVERSAMPLING_8X; + + CHECK(qmp6988_device_check(dev)); + + CHECK(write_reg(dev, QMP6988_RESET_REG, 0xe6)); + vTaskDelay(TIME_TO_TICKS(20)); // need to wait a short moment after reset + CHECK(qmp6988_get_calibration_data(dev)); + CHECK(qmp6988_setup_powermode(dev, QMP6988_SLEEP_MODE)); + CHECK(qmp6988_set_filter(dev, QMP6988_FILTERCOEFF_4)); + CHECK(qmp6988_set_p_oversampling(dev, QMP6988_OVERSAMPLING_8X)); + CHECK(qmp6988_set_t_oversampling(dev, QMP6988_OVERSAMPLING_1X)); + return ESP_OK; +} diff --git a/components/qmp6988/qmp6988.h b/components/qmp6988/qmp6988.h new file mode 100644 index 00000000..8012215c --- /dev/null +++ b/components/qmp6988/qmp6988.h @@ -0,0 +1,197 @@ + +#ifndef __QMP6988_H__ +#define __QMP6988_H__ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define QMP6988_U16_t uint16_t +#define QMP6988_S16_t int16_t +#define QMP6988_U32_t uint32_t +#define QMP6988_S32_t int32_t +#define QMP6988_U64_t uint64_t +#define QMP6988_S64_t int64_t + +#define QMP6988_I2C_ADDR_GND 0x70 +#define QMP6988_I2C_ADDR_VDD 0x56 + +#define QMP6988_CHIP_ID 0x5C + +#define QMP6988_CHIP_ID_REG 0xD1 +#define QMP6988_RESET_REG 0xE0 /* Device reset register */ +#define QMP6988_DEVICE_STAT_REG 0xF3 /* Device state register */ +#define QMP6988_CTRLMEAS_REG 0xF4 /* Measurement Condition Control Register */ +#define QMP6988_PRESSURE_MSB_REG 0xF7 /* Pressure MSB Register */ +#define QMP6988_TEMPERATURE_MSB_REG 0xFA /* Temperature MSB Reg */ + +#define SUBTRACTOR 8388608 + +/* compensation calculation */ +#define QMP6988_CALIBRATION_DATA_START 0xA0 /* QMP6988 compensation coefficients */ +#define QMP6988_CALIBRATION_DATA_LENGTH 25 + +#define SHIFT_RIGHT_4_POSITION 4 +#define SHIFT_LEFT_2_POSITION 2 +#define SHIFT_LEFT_4_POSITION 4 +#define SHIFT_LEFT_5_POSITION 5 +#define SHIFT_LEFT_8_POSITION 8 +#define SHIFT_LEFT_12_POSITION 12 +#define SHIFT_LEFT_16_POSITION 16 + +/** + * Possible measurement modes + */ +typedef enum { + QMP6988_SLEEP_MODE = 0x00, // sleep mode + QMP6988_FORCED_MODE = 0x01, // one measurement then sleep again + QMP6988_NORMAL_MODE = 0x03 // power mode +} qmp6988_power_mode_t; + +#define QMP6988_CTRLMEAS_REG_MODE__POS 0 +#define QMP6988_CTRLMEAS_REG_MODE__MSK 0x03 +#define QMP6988_CTRLMEAS_REG_MODE__LEN 2 + +/** + * Possible filter modes + */ +typedef enum { + QMP6988_FILTERCOEFF_OFF = 0x00, + QMP6988_FILTERCOEFF_2 = 0x01, + QMP6988_FILTERCOEFF_4 = 0x02, + QMP6988_FILTERCOEFF_8 = 0x03, + QMP6988_FILTERCOEFF_16 = 0x04, + QMP6988_FILTERCOEFF_32 = 0x05 +} qmp6988_filter_t; + +#define QMP6988_CONFIG_REG 0xF1 /*IIR filter co-efficient setting Register*/ +#define QMP6988_CONFIG_REG_FILTER__POS 0 +#define QMP6988_CONFIG_REG_FILTER__MSK 0x07 +#define QMP6988_CONFIG_REG_FILTER__LEN 3 + +/** + * Possible oversampling modes + */ +typedef enum { + QMP6988_OVERSAMPLING_SKIPPED = 0x00, + QMP6988_OVERSAMPLING_1X = 0x01, + QMP6988_OVERSAMPLING_2X = 0x02, + QMP6988_OVERSAMPLING_4X = 0x03, + QMP6988_OVERSAMPLING_8X = 0x04, + QMP6988_OVERSAMPLING_16X = 0x05, + QMP6988_OVERSAMPLING_32X = 0x06, + QMP6988_OVERSAMPLING_64X = 0x07 +} qmp6988_oversampling_t; + +#define QMP6988_CTRLMEAS_REG_OSRST__POS 5 +#define QMP6988_CTRLMEAS_REG_OSRST__MSK 0xE0 +#define QMP6988_CTRLMEAS_REG_OSRST__LEN 3 + +#define QMP6988_CTRLMEAS_REG_OSRSP__POS 2 +#define QMP6988_CTRLMEAS_REG_OSRSP__MSK 0x1C +#define QMP6988_CTRLMEAS_REG_OSRSP__LEN 3 + +// #define QMP6988_RAW_DATA_SIZE 8 +typedef uint8_t qmp6988_raw_data_t; + +typedef struct _qmp6988_cali_data +{ + QMP6988_S32_t COE_a0; + QMP6988_S16_t COE_a1; + QMP6988_S16_t COE_a2; + QMP6988_S32_t COE_b00; + QMP6988_S16_t COE_bt1; + QMP6988_S16_t COE_bt2; + QMP6988_S16_t COE_bp1; + QMP6988_S16_t COE_b11; + QMP6988_S16_t COE_bp2; + QMP6988_S16_t COE_b12; + QMP6988_S16_t COE_b21; + QMP6988_S16_t COE_bp3; +} qmp6988_cali_data_t; + +typedef struct _qmp6988_fk_data +{ + float a0, b00; + float a1, a2, bt1, bt2, bp1, b11, bp2, b12, b21, bp3; +} qmp6988_fk_data_t; + +typedef struct _qmp6988_ik_data +{ + QMP6988_S32_t a0, b00; + QMP6988_S32_t a1, a2; + QMP6988_S64_t bt1, bt2, bp1, b11, bp2, b12, b21, bp3; +} qmp6988_ik_data_t; + +/** + * Device descriptor + */ +typedef struct +{ + i2c_dev_t i2c_dev; //!< I2C device descriptor + + qmp6988_power_mode_t power_mode; //!< used power mode + qmp6988_filter_t filter_mode; //!< used filter mode + qmp6988_oversampling_t oversampling_t_mode; //!< used oversampling temp mode + qmp6988_oversampling_t oversampling_p_mode; //!< used oversampling pressure mode + + qmp6988_cali_data_t qmp6988_cali; + qmp6988_ik_data_t ik; + + float temperature; + float pressure; + + // bool meas_started; //!< indicates whether measurement started + // uint64_t meas_start_time; //!< measurement start time in us + // bool meas_first; //!< first measurement in periodic mode +} qmp6988_t; + +/** + * @brief Initialize device descriptor + * + * @param dev Device descriptor + * @param port I2C port + * @param addr Device address + * @param sda_gpio SDA GPIO + * @param scl_gpio SCL GPIO + * @return `ESP_OK` on success + */ +esp_err_t qmp6988_init_desc(qmp6988_t *dev, uint8_t addr, i2c_port_t port, gpio_num_t sda_gpio, gpio_num_t scl_gpio); + +/** + * @brief Free device descriptor + * + * @param dev Device descriptor + * @return `ESP_OK` on success + */ +esp_err_t qmp6988_free_desc(qmp6988_t *dev); + +/** + * @brief Initialize sensor + * + * @param dev Device descriptor + * @return `ESP_OK` on success + */ +esp_err_t qmp6988_init(qmp6988_t *dev); + +esp_err_t qmp6988_setup_powermode(qmp6988_t *dev, qmp6988_power_mode_t power_mode); + +esp_err_t qmp6988_set_filter(qmp6988_t *dev, qmp6988_filter_t filter_mode); + +esp_err_t qmp6988_set_p_oversampling(qmp6988_t *dev, qmp6988_oversampling_t oversampling_p_mode); + +esp_err_t qmp6988_set_t_oversampling(qmp6988_t *dev, qmp6988_oversampling_t oversampling_t_mode); + +float qmp6988_calc_pressure(qmp6988_t *dev); + +float qmp6988_calc_temperature(qmp6988_t *dev); + +#ifdef __cplusplus +} +#endif + +#endif /* __QMP6988_H__ */ diff --git a/devtools/persons.yml b/devtools/persons.yml index 9e8c3989..ff3c7773 100644 --- a/devtools/persons.yml +++ b/devtools/persons.yml @@ -160,3 +160,7 @@ - name: mmarkwort full_name: Manuel Markwort gh_id: mmarkwort + +- name: vonguced + full_name: Cedric von Gunten + gh_id: vonguced diff --git a/examples/qmp6988/default/CMakeLists.txt b/examples/qmp6988/default/CMakeLists.txt new file mode 100644 index 00000000..cc8d7c9d --- /dev/null +++ b/examples/qmp6988/default/CMakeLists.txt @@ -0,0 +1,8 @@ +# The following lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.5) + +set(EXTRA_COMPONENT_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/../../../components) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(example-qmp6988) diff --git a/examples/qmp6988/default/Makefile b/examples/qmp6988/default/Makefile new file mode 100644 index 00000000..13be8b39 --- /dev/null +++ b/examples/qmp6988/default/Makefile @@ -0,0 +1,6 @@ +#V := 1 +PROJECT_NAME := example-qmp6988 + +EXTRA_COMPONENT_DIRS := $(CURDIR)/../../../components + +include $(IDF_PATH)/make/project.mk diff --git a/examples/qmp6988/default/README.md b/examples/qmp6988/default/README.md new file mode 100644 index 00000000..50eaa10c --- /dev/null +++ b/examples/qmp6988/default/README.md @@ -0,0 +1,16 @@ +# Example for `qmp6988` driver + +## What it does + +The example configures a `qmp6988` device. + +## Wiring + + +Connect `SCL` and `SDA` pins to the following pins with appropriate pull-up +resistors. + +| Name | Description | Defaults | +|------|-------------|----------| +| `CONFIG_EXAMPLE_I2C_MASTER_SCL` | GPIO number for `SCL` | "5" for `esp8266`, "6" for `esp32c3`, "19" for `esp32`, `esp32s2`, and `esp32s3` | +| `CONFIG_EXAMPLE_I2C_MASTER_SDA` | GPIO number for `SDA` | "4" for `esp8266`, "5" for `esp32c3`, "18" for `esp32`, `esp32s2`, and `esp32s3` | diff --git a/examples/qmp6988/default/main/CMakeLists.txt b/examples/qmp6988/default/main/CMakeLists.txt new file mode 100644 index 00000000..cf2c455c --- /dev/null +++ b/examples/qmp6988/default/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "main.c" + INCLUDE_DIRS ".") diff --git a/examples/qmp6988/default/main/Kconfig.projbuild b/examples/qmp6988/default/main/Kconfig.projbuild new file mode 100644 index 00000000..35e335cc --- /dev/null +++ b/examples/qmp6988/default/main/Kconfig.projbuild @@ -0,0 +1,43 @@ +menu "Example configuration" + choice EXAMPLE_SHT3X_DEMO + prompt "Demo mode" + default EXAMPLE_QMP6988_DEMO_NORMAL + help + Choose how to masure values from the sensor. See the main.c for + details. + + config EXAMPLE_QMP6988_DEMO_FORCED + bool "Forced mode" + help + In this example the qmp6988 makes a single measurement before entering + sleep mode again. + + config EXAMPLE_SHT3X_DEMO_NORMAL + bool "Normal mode" + help + In this example the qmp6988 makes continuous measurements. + + endchoice + + config EXAMPLE_QMP6988_ADDR + hex "I2C address of QMP6988" + default 0x70 + help + I2C address of QMP6988, default 0x70. + + config EXAMPLE_I2C_MASTER_SCL + int "SCL GPIO Number" + default 5 if IDF_TARGET_ESP8266 + default 6 if IDF_TARGET_ESP32C3 + default 19 if IDF_TARGET_ESP32 || IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3 + help + GPIO number for I2C Master clock line. + + config EXAMPLE_I2C_MASTER_SDA + int "SDA GPIO Number" + default 4 if IDF_TARGET_ESP8266 + default 5 if IDF_TARGET_ESP32C3 + default 18 if IDF_TARGET_ESP32 || IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3 + help + GPIO number for I2C Master data line. +endmenu diff --git a/examples/qmp6988/default/main/component.mk b/examples/qmp6988/default/main/component.mk new file mode 100644 index 00000000..7700ea99 --- /dev/null +++ b/examples/qmp6988/default/main/component.mk @@ -0,0 +1 @@ +COMPONENT_ADD_INCLUDEDIRS = . include/ diff --git a/examples/qmp6988/default/main/main.c b/examples/qmp6988/default/main/main.c new file mode 100644 index 00000000..3d8187c9 --- /dev/null +++ b/examples/qmp6988/default/main/main.c @@ -0,0 +1,116 @@ +/** + * Simple example with QMP6988 sensor. + * + * It shows different user task implementations in *forced mode* and + * *normal mode*. + */ + +#include +#include +#include +#include +#include +#include +#include + +/* float is used in printf(). you need non-default configuration in + * sdkconfig for ESP8266, which is enabled by default for this + * example. see sdkconfig.defaults.esp8266 + */ + +#ifndef APP_CPU_NUM +#define APP_CPU_NUM PRO_CPU_NUM +#endif + +static qmp6988_t dev; + +#if defined(CONFIG_EXAMPLE_QMP6988_DEMO_FORCED) + +/* + * User task that triggers a measurement every 5 seconds. Due to power + * efficiency reasons it uses *Forced* mode. + */ +void task(void *pvParameters) +{ + float temperature; + float pressure; + + TickType_t last_wakeup = xTaskGetTickCount(); + + /* We can lower the standard filter and oversampling to use less power + and in low accuracy examples e.g. a weather station */ + + ESP_ERROR_CHECK(qmp6988_set_filter(&dev, QMP6988_FILTERCOEFF_OFF)); + ESP_ERROR_CHECK(qmp6988_set_p_oversampling(&dev, QMP6988_OVERSAMPLING_2X)); + ESP_ERROR_CHECK(qmp6988_set_t_oversampling(&dev, QMP6988_OVERSAMPLING_1X)); + + while (1) + { + /*Set forced mode for qmp6988 (need to set this each time as it falls + back to sleep mode automatically after a single measurement). */ + if (qmp6988_setup_powermode(&dev, QMP6988_FORCED_MODE) == ESP_OK) + printf("Power mode set to forced mode\n"); + else + printf("Sensor error\n"); + + /* Wait until forced measurement is ready (constant time of at least 5.5 ms + according to the modified oversampling and filter modes.*/ + vTaskDelay(1); + + /*Calculate pressure values (this includes temperature as well, + as temp is needed to calc pressure)*/ + pressure = qmp6988_calc_pressure(&dev); + temperature = dev.temperature; + printf("QMP6988 Sensor: %.2f °C, %.2f Pa\n", temperature, pressure); + + // Wait until 5 seconds (cycle time) are over. + vTaskDelayUntil(&last_wakeup, pdMS_TO_TICKS(5000)); + } +} + +#else // CONFIG_QMP6988_DEMO_NORMAL +/* + * User task that fetches latest measurement results of sensor every 2 + * seconds. It starts the QMP6988 in normal (periodic) mode. + */ +void task(void *pvParameters) +{ + float temperature; + float pressure; + + // Set normal mode for qmp6988. + if (qmp6988_setup_powermode(&dev, QMP6988_NORMAL_MODE) == ESP_OK) + printf("Power mode set to normal mode\n"); + else + printf("Sensor error\n"); + + /* Wait until first measurement is ready (constant time of at least 10.6 ms + according to the default oversampling and filter modes.*/ + vTaskDelay(2); + + TickType_t last_wakeup = xTaskGetTickCount(); + + while (1) + { + /*Calculate pressure values (this includes temperature as well, + as temp is needed to calc pressure)*/ + pressure = qmp6988_calc_pressure(&dev); + temperature = dev.temperature; + printf("QMP6988 Sensor: %.2f °C, %.2f Pa\n", temperature, pressure); + + // Wait until 2 seconds (cycle time) are over. + vTaskDelayUntil(&last_wakeup, pdMS_TO_TICKS(2000)); + } +} + +#endif + +void app_main() +{ + ESP_ERROR_CHECK(i2cdev_init()); + + ESP_ERROR_CHECK(qmp6988_init_desc(&dev, CONFIG_EXAMPLE_QMP6988_ADDR, 0, CONFIG_EXAMPLE_I2C_MASTER_SDA, CONFIG_EXAMPLE_I2C_MASTER_SCL)); + ESP_ERROR_CHECK(qmp6988_init(&dev)); + + xTaskCreatePinnedToCore(task, "qmp6988_test", configMINIMAL_STACK_SIZE * 8, NULL, 5, NULL, APP_CPU_NUM); +} diff --git a/examples/qmp6988/default/sdkconfig.defaults.esp8266 b/examples/qmp6988/default/sdkconfig.defaults.esp8266 new file mode 100644 index 00000000..79a53171 --- /dev/null +++ b/examples/qmp6988/default/sdkconfig.defaults.esp8266 @@ -0,0 +1 @@ +CONFIG_NEWLIB_LIBRARY_LEVEL_NORMAL=y From 561477cebe501c1b951b41fdce3dad486b0693c9 Mon Sep 17 00:00:00 2001 From: Cedric von Gunten Date: Sun, 21 Jan 2024 00:11:52 +0100 Subject: [PATCH 2/3] Update: Addressed feedback --- components/qmp6988/README.md | 5 + components/qmp6988/qmp6988.c | 158 +++++++++++++++++++++++----- components/qmp6988/qmp6988.h | 193 +++++++++++++++++++---------------- 3 files changed, 244 insertions(+), 112 deletions(-) create mode 100644 components/qmp6988/README.md diff --git a/components/qmp6988/README.md b/components/qmp6988/README.md new file mode 100644 index 00000000..b9a1aabe --- /dev/null +++ b/components/qmp6988/README.md @@ -0,0 +1,5 @@ +# Driver for QMP6988 digital temperature and pressure sensor + +This driver is based on code of [original QMP6988 driver](https://github.com/m5stack/M5Unit-ENV) +by m5stack, made to be compatible with the i2cdev library (https://github.com/UncleRus/esp-idf-lib). +To convert the code a lot was reused from the sht3x component of the same "esp-idf-lib" library. \ No newline at end of file diff --git a/components/qmp6988/qmp6988.c b/components/qmp6988/qmp6988.c index ed90ce0b..b25f596d 100644 --- a/components/qmp6988/qmp6988.c +++ b/components/qmp6988/qmp6988.c @@ -1,3 +1,47 @@ +/* + * Copyright (c) 2019 Ruslan V. Uss (https://github.com/UncleRus) + * Copyright (c) 2022 m5stack (https://github.com/m5stack) + * Copyright (c) 2024 vonguced (https://github.com/vonguced) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of itscontributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file qmp6988.c + * + * ESP-IDF driver for QMP6988 digital temperature and pressure sensor + * + * Code based on m5stack \n + * and Ruslan V. Uss + * + * Copyright (c) 2019 Ruslan V. Uss (https://github.com/UncleRus)\n + * Copyright (c) 2022 m5stack (https://github.com/m5stack)\n + * Copyright (c) 2024 vonguced (https://github.com/vonguced)\n + * + * BSD Licensed as described in the file LICENSE + */ + #include #include #include @@ -8,6 +52,67 @@ #define I2C_FREQ_HZ 1000000 // 1MHz +typedef uint8_t qmp6988_raw_data_t; + +#define QMP6988_CHIP_ID 0x5C + +#define QMP6988_CHIP_ID_REG 0xD1 +#define QMP6988_RESET_REG 0xE0 /* Device reset register */ +#define QMP6988_DEVICE_STAT_REG 0xF3 /* Device state register */ +#define QMP6988_CTRLMEAS_REG 0xF4 /* Measurement Condition Control Register */ +#define QMP6988_PRESSURE_MSB_REG 0xF7 /* Pressure MSB Register */ +#define QMP6988_TEMPERATURE_MSB_REG 0xFA /* Temperature MSB Reg */ + +#define SUBTRACTOR 8388608 + +/* compensation calculation */ +#define QMP6988_CALIBRATION_DATA_START 0xA0 /* QMP6988 compensation coefficients */ +#define QMP6988_CALIBRATION_DATA_LENGTH 25 + +#define SHIFT_RIGHT_4_POSITION 4 +#define SHIFT_LEFT_2_POSITION 2 +#define SHIFT_LEFT_4_POSITION 4 +#define SHIFT_LEFT_5_POSITION 5 +#define SHIFT_LEFT_8_POSITION 8 +#define SHIFT_LEFT_12_POSITION 12 +#define SHIFT_LEFT_16_POSITION 16 + +#define QMP6988_CTRLMEAS_REG_MODE__POS 0 +#define QMP6988_CTRLMEAS_REG_MODE__MSK 0x03 +#define QMP6988_CTRLMEAS_REG_MODE__LEN 2 + +#define QMP6988_CTRLMEAS_REG_OSRST__POS 5 +#define QMP6988_CTRLMEAS_REG_OSRST__MSK 0xE0 +#define QMP6988_CTRLMEAS_REG_OSRST__LEN 3 + +#define QMP6988_CTRLMEAS_REG_OSRSP__POS 2 +#define QMP6988_CTRLMEAS_REG_OSRSP__MSK 0x1C +#define QMP6988_CTRLMEAS_REG_OSRSP__LEN 3 + +#define QMP6988_CONFIG_REG 0xF1 /*IIR filter co-efficient setting Register*/ +#define QMP6988_CONFIG_REG_FILTER__POS 0 +#define QMP6988_CONFIG_REG_FILTER__MSK 0x07 +#define QMP6988_CONFIG_REG_FILTER__LEN 3 + +/** + * Structure holding raw calibration data for QMP6988. + */ +typedef struct _qmp6988_cali_data +{ + QMP6988_S32_t COE_a0; + QMP6988_S16_t COE_a1; + QMP6988_S16_t COE_a2; + QMP6988_S32_t COE_b00; + QMP6988_S16_t COE_bt1; + QMP6988_S16_t COE_bt2; + QMP6988_S16_t COE_bp1; + QMP6988_S16_t COE_b11; + QMP6988_S16_t COE_bp2; + QMP6988_S16_t COE_b12; + QMP6988_S16_t COE_b21; + QMP6988_S16_t COE_bp3; +} qmp6988_cali_data_t; + static const char *TAG = "qmp6988"; // due to the fact that ticks can be smaller than portTICK_PERIOD_MS, one and @@ -68,6 +173,7 @@ esp_err_t qmp6988_device_check(qmp6988_t *dev) esp_err_t qmp6988_get_calibration_data(qmp6988_t *dev) { uint8_t a_data_uint8_tr[QMP6988_CALIBRATION_DATA_LENGTH] = { 0 }; + qmp6988_cali_data_t qmp6988_cali; int len; for (len = 0; len < QMP6988_CALIBRATION_DATA_LENGTH; len += 1) @@ -75,48 +181,48 @@ esp_err_t qmp6988_get_calibration_data(qmp6988_t *dev) CHECK(qmp6988_read_reg(dev, QMP6988_CALIBRATION_DATA_START + len, &a_data_uint8_tr[len])); } - dev->qmp6988_cali.COE_a0 = (QMP6988_S32_t)(((QMP6988_S32_t)a_data_uint8_tr[18] << SHIFT_LEFT_12_POSITION) | (a_data_uint8_tr[19] << SHIFT_LEFT_4_POSITION) | (a_data_uint8_tr[24] & 0x0f)) << 12; - dev->qmp6988_cali.COE_a0 = dev->qmp6988_cali.COE_a0 >> 12; + qmp6988_cali.COE_a0 = (QMP6988_S32_t)(((QMP6988_S32_t)a_data_uint8_tr[18] << SHIFT_LEFT_12_POSITION) | (a_data_uint8_tr[19] << SHIFT_LEFT_4_POSITION) | (a_data_uint8_tr[24] & 0x0f)) << 12; + qmp6988_cali.COE_a0 = qmp6988_cali.COE_a0 >> 12; - dev->qmp6988_cali.COE_a1 = (QMP6988_S16_t)((a_data_uint8_tr[20] << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[21]); + qmp6988_cali.COE_a1 = (QMP6988_S16_t)((a_data_uint8_tr[20] << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[21]); - dev->qmp6988_cali.COE_a2 = (QMP6988_S16_t)((a_data_uint8_tr[22] << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[23]); + qmp6988_cali.COE_a2 = (QMP6988_S16_t)((a_data_uint8_tr[22] << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[23]); - dev->qmp6988_cali.COE_b00 + qmp6988_cali.COE_b00 = (QMP6988_S32_t)((((QMP6988_S32_t)a_data_uint8_tr[0] << SHIFT_LEFT_12_POSITION) | (a_data_uint8_tr[1] << SHIFT_LEFT_4_POSITION) | ((a_data_uint8_tr[24] & 0xf0) >> SHIFT_RIGHT_4_POSITION)) << 12); - dev->qmp6988_cali.COE_b00 = dev->qmp6988_cali.COE_b00 >> 12; + qmp6988_cali.COE_b00 = qmp6988_cali.COE_b00 >> 12; - dev->qmp6988_cali.COE_bt1 = (QMP6988_S16_t)((a_data_uint8_tr[2] << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[3]); + qmp6988_cali.COE_bt1 = (QMP6988_S16_t)((a_data_uint8_tr[2] << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[3]); - dev->qmp6988_cali.COE_bt2 = (QMP6988_S16_t)((a_data_uint8_tr[4] << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[5]); + qmp6988_cali.COE_bt2 = (QMP6988_S16_t)((a_data_uint8_tr[4] << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[5]); - dev->qmp6988_cali.COE_bp1 = (QMP6988_S16_t)((a_data_uint8_tr[6] << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[7]); + qmp6988_cali.COE_bp1 = (QMP6988_S16_t)((a_data_uint8_tr[6] << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[7]); - dev->qmp6988_cali.COE_b11 = (QMP6988_S16_t)((a_data_uint8_tr[8] << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[9]); + qmp6988_cali.COE_b11 = (QMP6988_S16_t)((a_data_uint8_tr[8] << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[9]); - dev->qmp6988_cali.COE_bp2 = (QMP6988_S16_t)((a_data_uint8_tr[10] << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[11]); + qmp6988_cali.COE_bp2 = (QMP6988_S16_t)((a_data_uint8_tr[10] << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[11]); - dev->qmp6988_cali.COE_b12 = (QMP6988_S16_t)((a_data_uint8_tr[12] << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[13]); + qmp6988_cali.COE_b12 = (QMP6988_S16_t)((a_data_uint8_tr[12] << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[13]); - dev->qmp6988_cali.COE_b21 = (QMP6988_S16_t)((a_data_uint8_tr[14] << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[15]); + qmp6988_cali.COE_b21 = (QMP6988_S16_t)((a_data_uint8_tr[14] << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[15]); - dev->qmp6988_cali.COE_bp3 = (QMP6988_S16_t)((a_data_uint8_tr[16] << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[17]); + qmp6988_cali.COE_bp3 = (QMP6988_S16_t)((a_data_uint8_tr[16] << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[17]); - dev->ik.a0 = dev->qmp6988_cali.COE_a0; // 20Q4 - dev->ik.b00 = dev->qmp6988_cali.COE_b00; // 20Q4 + dev->ik.a0 = qmp6988_cali.COE_a0; // 20Q4 + dev->ik.b00 = qmp6988_cali.COE_b00; // 20Q4 - dev->ik.a1 = 3608L * (QMP6988_S32_t)dev->qmp6988_cali.COE_a1 - 1731677965L; // 31Q23 - dev->ik.a2 = 16889L * (QMP6988_S32_t)dev->qmp6988_cali.COE_a2 - 87619360L; // 30Q47 + dev->ik.a1 = 3608L * (QMP6988_S32_t)qmp6988_cali.COE_a1 - 1731677965L; // 31Q23 + dev->ik.a2 = 16889L * (QMP6988_S32_t)qmp6988_cali.COE_a2 - 87619360L; // 30Q47 - dev->ik.bt1 = 2982L * (QMP6988_S64_t)dev->qmp6988_cali.COE_bt1 + 107370906L; // 28Q15 - dev->ik.bt2 = 329854L * (QMP6988_S64_t)dev->qmp6988_cali.COE_bt2 + 108083093L; // 34Q38 - dev->ik.bp1 = 19923L * (QMP6988_S64_t)dev->qmp6988_cali.COE_bp1 + 1133836764L; // 31Q20 - dev->ik.b11 = 2406L * (QMP6988_S64_t)dev->qmp6988_cali.COE_b11 + 118215883L; // 28Q34 - dev->ik.bp2 = 3079L * (QMP6988_S64_t)dev->qmp6988_cali.COE_bp2 - 181579595L; // 29Q43 - dev->ik.b12 = 6846L * (QMP6988_S64_t)dev->qmp6988_cali.COE_b12 + 85590281L; // 29Q53 - dev->ik.b21 = 13836L * (QMP6988_S64_t)dev->qmp6988_cali.COE_b21 + 79333336L; // 29Q60 - dev->ik.bp3 = 2915L * (QMP6988_S64_t)dev->qmp6988_cali.COE_bp3 + 157155561L; // 28Q65 + dev->ik.bt1 = 2982L * (QMP6988_S64_t)qmp6988_cali.COE_bt1 + 107370906L; // 28Q15 + dev->ik.bt2 = 329854L * (QMP6988_S64_t)qmp6988_cali.COE_bt2 + 108083093L; // 34Q38 + dev->ik.bp1 = 19923L * (QMP6988_S64_t)qmp6988_cali.COE_bp1 + 1133836764L; // 31Q20 + dev->ik.b11 = 2406L * (QMP6988_S64_t)qmp6988_cali.COE_b11 + 118215883L; // 28Q34 + dev->ik.bp2 = 3079L * (QMP6988_S64_t)qmp6988_cali.COE_bp2 - 181579595L; // 29Q43 + dev->ik.b12 = 6846L * (QMP6988_S64_t)qmp6988_cali.COE_b12 + 85590281L; // 29Q53 + dev->ik.b21 = 13836L * (QMP6988_S64_t)qmp6988_cali.COE_b21 + 79333336L; // 29Q60 + dev->ik.bp3 = 2915L * (QMP6988_S64_t)qmp6988_cali.COE_bp3 + 157155561L; // 28Q65 return ESP_OK; } diff --git a/components/qmp6988/qmp6988.h b/components/qmp6988/qmp6988.h index 8012215c..0b774cc0 100644 --- a/components/qmp6988/qmp6988.h +++ b/components/qmp6988/qmp6988.h @@ -1,8 +1,54 @@ +/* + * Copyright (c) 2019 Ruslan V. Uss (https://github.com/UncleRus) + * Copyright (c) 2022 m5stack (https://github.com/m5stack) + * Copyright (c) 2024 vonguced (https://github.com/vonguced) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of itscontributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file qmp6988.h + * @defgroup qmp6988 qmp6988 + * @{ + * + * ESP-IDF driver for QMP6988 digital temperature and pressure sensor + * + * Code based on m5stack \n + * and Ruslan V. Uss + * + * Copyright (c) 2019 Ruslan V. Uss (https://github.com/UncleRus)\n + * Copyright (c) 2022 m5stack (https://github.com/m5stack)\n + * Copyright (c) 2024 vonguced (https://github.com/vonguced)\n + * + * BSD Licensed as described in the file LICENSE + */ #ifndef __QMP6988_H__ #define __QMP6988_H__ #include +#include #include #include @@ -10,39 +56,16 @@ extern "C" { #endif -#define QMP6988_U16_t uint16_t -#define QMP6988_S16_t int16_t -#define QMP6988_U32_t uint32_t -#define QMP6988_S32_t int32_t -#define QMP6988_U64_t uint64_t -#define QMP6988_S64_t int64_t +typedef uint16_t QMP6988_U16_t; +typedef int16_t QMP6988_S16_t; +typedef uint32_t QMP6988_U32_t; +typedef int32_t QMP6988_S32_t; +typedef uint64_t QMP6988_U64_t; +typedef int64_t QMP6988_S64_t; #define QMP6988_I2C_ADDR_GND 0x70 #define QMP6988_I2C_ADDR_VDD 0x56 -#define QMP6988_CHIP_ID 0x5C - -#define QMP6988_CHIP_ID_REG 0xD1 -#define QMP6988_RESET_REG 0xE0 /* Device reset register */ -#define QMP6988_DEVICE_STAT_REG 0xF3 /* Device state register */ -#define QMP6988_CTRLMEAS_REG 0xF4 /* Measurement Condition Control Register */ -#define QMP6988_PRESSURE_MSB_REG 0xF7 /* Pressure MSB Register */ -#define QMP6988_TEMPERATURE_MSB_REG 0xFA /* Temperature MSB Reg */ - -#define SUBTRACTOR 8388608 - -/* compensation calculation */ -#define QMP6988_CALIBRATION_DATA_START 0xA0 /* QMP6988 compensation coefficients */ -#define QMP6988_CALIBRATION_DATA_LENGTH 25 - -#define SHIFT_RIGHT_4_POSITION 4 -#define SHIFT_LEFT_2_POSITION 2 -#define SHIFT_LEFT_4_POSITION 4 -#define SHIFT_LEFT_5_POSITION 5 -#define SHIFT_LEFT_8_POSITION 8 -#define SHIFT_LEFT_12_POSITION 12 -#define SHIFT_LEFT_16_POSITION 16 - /** * Possible measurement modes */ @@ -52,10 +75,6 @@ typedef enum { QMP6988_NORMAL_MODE = 0x03 // power mode } qmp6988_power_mode_t; -#define QMP6988_CTRLMEAS_REG_MODE__POS 0 -#define QMP6988_CTRLMEAS_REG_MODE__MSK 0x03 -#define QMP6988_CTRLMEAS_REG_MODE__LEN 2 - /** * Possible filter modes */ @@ -68,11 +87,6 @@ typedef enum { QMP6988_FILTERCOEFF_32 = 0x05 } qmp6988_filter_t; -#define QMP6988_CONFIG_REG 0xF1 /*IIR filter co-efficient setting Register*/ -#define QMP6988_CONFIG_REG_FILTER__POS 0 -#define QMP6988_CONFIG_REG_FILTER__MSK 0x07 -#define QMP6988_CONFIG_REG_FILTER__LEN 3 - /** * Possible oversampling modes */ @@ -87,39 +101,9 @@ typedef enum { QMP6988_OVERSAMPLING_64X = 0x07 } qmp6988_oversampling_t; -#define QMP6988_CTRLMEAS_REG_OSRST__POS 5 -#define QMP6988_CTRLMEAS_REG_OSRST__MSK 0xE0 -#define QMP6988_CTRLMEAS_REG_OSRST__LEN 3 - -#define QMP6988_CTRLMEAS_REG_OSRSP__POS 2 -#define QMP6988_CTRLMEAS_REG_OSRSP__MSK 0x1C -#define QMP6988_CTRLMEAS_REG_OSRSP__LEN 3 - -// #define QMP6988_RAW_DATA_SIZE 8 -typedef uint8_t qmp6988_raw_data_t; - -typedef struct _qmp6988_cali_data -{ - QMP6988_S32_t COE_a0; - QMP6988_S16_t COE_a1; - QMP6988_S16_t COE_a2; - QMP6988_S32_t COE_b00; - QMP6988_S16_t COE_bt1; - QMP6988_S16_t COE_bt2; - QMP6988_S16_t COE_bp1; - QMP6988_S16_t COE_b11; - QMP6988_S16_t COE_bp2; - QMP6988_S16_t COE_b12; - QMP6988_S16_t COE_b21; - QMP6988_S16_t COE_bp3; -} qmp6988_cali_data_t; - -typedef struct _qmp6988_fk_data -{ - float a0, b00; - float a1, a2, bt1, bt2, bp1, b11, bp2, b12, b21, bp3; -} qmp6988_fk_data_t; - +/** + * Structure holding calibration data for QMP6988. + */ typedef struct _qmp6988_ik_data { QMP6988_S32_t a0, b00; @@ -139,26 +123,21 @@ typedef struct qmp6988_oversampling_t oversampling_t_mode; //!< used oversampling temp mode qmp6988_oversampling_t oversampling_p_mode; //!< used oversampling pressure mode - qmp6988_cali_data_t qmp6988_cali; - qmp6988_ik_data_t ik; - - float temperature; - float pressure; + qmp6988_ik_data_t ik; //!< used calibration data - // bool meas_started; //!< indicates whether measurement started - // uint64_t meas_start_time; //!< measurement start time in us - // bool meas_first; //!< first measurement in periodic mode + float temperature; //!< measured temperature + float pressure; //!< measured pressure } qmp6988_t; /** - * @brief Initialize device descriptor + * @brief Initialize device descriptor. * - * @param dev Device descriptor - * @param port I2C port - * @param addr Device address - * @param sda_gpio SDA GPIO - * @param scl_gpio SCL GPIO - * @return `ESP_OK` on success + * @param dev Device descriptor. + * @param addr Device address. + * @param port I2C port. + * @param sda_gpio SDA GPIO. + * @param scl_gpio SCL GPIO. + * @return `ESP_OK` on success. */ esp_err_t qmp6988_init_desc(qmp6988_t *dev, uint8_t addr, i2c_port_t port, gpio_num_t sda_gpio, gpio_num_t scl_gpio); @@ -178,20 +157,62 @@ esp_err_t qmp6988_free_desc(qmp6988_t *dev); */ esp_err_t qmp6988_init(qmp6988_t *dev); +/** + * @brief Set up power mode for QMP6988. + * + * @param dev Device descriptor. + * @param power_mode Power mode to be set. + * @return `ESP_OK` on success. + */ esp_err_t qmp6988_setup_powermode(qmp6988_t *dev, qmp6988_power_mode_t power_mode); +/** + * @brief Set up filter mode for QMP6988. + * + * @param dev Device descriptor. + * @param filter_mode Filter mode to be set. + * @return `ESP_OK` on success. + */ esp_err_t qmp6988_set_filter(qmp6988_t *dev, qmp6988_filter_t filter_mode); +/** + * @brief Set up pressure oversampling mode for QMP6988. + * + * @param dev Device descriptor. + * @param oversampling_p_mode Oversampling mode for pressure to be set. + * @return `ESP_OK` on success. + */ esp_err_t qmp6988_set_p_oversampling(qmp6988_t *dev, qmp6988_oversampling_t oversampling_p_mode); +/** + * @brief Set up temperature oversampling mode for QMP6988. + * + * @param dev Device descriptor. + * @param oversampling_t_mode Oversampling mode for temperature to be set. + * @return `ESP_OK` on success. + */ esp_err_t qmp6988_set_t_oversampling(qmp6988_t *dev, qmp6988_oversampling_t oversampling_t_mode); +/** + * @brief Calculate pressure based on QMP6988 sensor data. + * + * @param dev Device descriptor. + * @return Calculated pressure in Pascals (Pa). + */ float qmp6988_calc_pressure(qmp6988_t *dev); +/** + * @brief Calculate temperature based on QMP6988 sensor data. + * + * @param dev Device descriptor. + * @return Calculated temperature in degrees Celsius (°C). + */ float qmp6988_calc_temperature(qmp6988_t *dev); #ifdef __cplusplus } #endif +/**@}*/ + #endif /* __QMP6988_H__ */ From e04b261520ad51c802d8e01255050b725b6b9e57 Mon Sep 17 00:00:00 2001 From: UncleRus Date: Sun, 4 Feb 2024 02:43:37 +0500 Subject: [PATCH 3/3] fix: bring qmp6988 driver to library standards, fix small errors, add doc --- components/qmp6988/qmp6988.c | 312 +++++++++--------- components/qmp6988/qmp6988.h | 31 +- docs/source/groups/qmp6988.rst | 8 + docs/source/index.rst | 1 + .../qmp6988/default/main/Kconfig.projbuild | 4 +- examples/qmp6988/default/main/main.c | 4 +- 6 files changed, 185 insertions(+), 175 deletions(-) create mode 100644 docs/source/groups/qmp6988.rst diff --git a/components/qmp6988/qmp6988.c b/components/qmp6988/qmp6988.c index b25f596d..032b34f0 100644 --- a/components/qmp6988/qmp6988.c +++ b/components/qmp6988/qmp6988.c @@ -99,18 +99,18 @@ typedef uint8_t qmp6988_raw_data_t; */ typedef struct _qmp6988_cali_data { - QMP6988_S32_t COE_a0; - QMP6988_S16_t COE_a1; - QMP6988_S16_t COE_a2; - QMP6988_S32_t COE_b00; - QMP6988_S16_t COE_bt1; - QMP6988_S16_t COE_bt2; - QMP6988_S16_t COE_bp1; - QMP6988_S16_t COE_b11; - QMP6988_S16_t COE_bp2; - QMP6988_S16_t COE_b12; - QMP6988_S16_t COE_b21; - QMP6988_S16_t COE_bp3; + int32_t COE_a0; + int16_t COE_a1; + int16_t COE_a2; + int32_t COE_b00; + int16_t COE_bt1; + int16_t COE_bt2; + int16_t COE_bp1; + int16_t COE_b11; + int16_t COE_bp2; + int16_t COE_b12; + int16_t COE_b21; + int16_t COE_bp3; } qmp6988_cali_data_t; static const char *TAG = "qmp6988"; @@ -163,11 +163,8 @@ esp_err_t qmp6988_device_check(qmp6988_t *dev) else { ESP_LOGE(TAG, "QMP6988 chip id not matching. Expected: 0x%02X got: 0x%02X", QMP6988_CHIP_ID, chip_id); - return ESP_OK; return ESP_ERR_INVALID_RESPONSE; } - - return ESP_FAIL; } esp_err_t qmp6988_get_calibration_data(qmp6988_t *dev) @@ -181,53 +178,155 @@ esp_err_t qmp6988_get_calibration_data(qmp6988_t *dev) CHECK(qmp6988_read_reg(dev, QMP6988_CALIBRATION_DATA_START + len, &a_data_uint8_tr[len])); } - qmp6988_cali.COE_a0 = (QMP6988_S32_t)(((QMP6988_S32_t)a_data_uint8_tr[18] << SHIFT_LEFT_12_POSITION) | (a_data_uint8_tr[19] << SHIFT_LEFT_4_POSITION) | (a_data_uint8_tr[24] & 0x0f)) << 12; + qmp6988_cali.COE_a0 = (int32_t)(((int32_t)a_data_uint8_tr[18] << SHIFT_LEFT_12_POSITION) | (a_data_uint8_tr[19] << SHIFT_LEFT_4_POSITION) | (a_data_uint8_tr[24] & 0x0f)) << 12; qmp6988_cali.COE_a0 = qmp6988_cali.COE_a0 >> 12; - qmp6988_cali.COE_a1 = (QMP6988_S16_t)((a_data_uint8_tr[20] << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[21]); + qmp6988_cali.COE_a1 = (int16_t)((a_data_uint8_tr[20] << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[21]); - qmp6988_cali.COE_a2 = (QMP6988_S16_t)((a_data_uint8_tr[22] << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[23]); + qmp6988_cali.COE_a2 = (int16_t)((a_data_uint8_tr[22] << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[23]); qmp6988_cali.COE_b00 - = (QMP6988_S32_t)((((QMP6988_S32_t)a_data_uint8_tr[0] << SHIFT_LEFT_12_POSITION) | (a_data_uint8_tr[1] << SHIFT_LEFT_4_POSITION) | ((a_data_uint8_tr[24] & 0xf0) >> SHIFT_RIGHT_4_POSITION)) + = (int32_t)((((int32_t)a_data_uint8_tr[0] << SHIFT_LEFT_12_POSITION) | (a_data_uint8_tr[1] << SHIFT_LEFT_4_POSITION) | ((a_data_uint8_tr[24] & 0xf0) >> SHIFT_RIGHT_4_POSITION)) << 12); qmp6988_cali.COE_b00 = qmp6988_cali.COE_b00 >> 12; - qmp6988_cali.COE_bt1 = (QMP6988_S16_t)((a_data_uint8_tr[2] << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[3]); + qmp6988_cali.COE_bt1 = (int16_t)((a_data_uint8_tr[2] << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[3]); - qmp6988_cali.COE_bt2 = (QMP6988_S16_t)((a_data_uint8_tr[4] << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[5]); + qmp6988_cali.COE_bt2 = (int16_t)((a_data_uint8_tr[4] << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[5]); - qmp6988_cali.COE_bp1 = (QMP6988_S16_t)((a_data_uint8_tr[6] << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[7]); + qmp6988_cali.COE_bp1 = (int16_t)((a_data_uint8_tr[6] << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[7]); - qmp6988_cali.COE_b11 = (QMP6988_S16_t)((a_data_uint8_tr[8] << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[9]); + qmp6988_cali.COE_b11 = (int16_t)((a_data_uint8_tr[8] << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[9]); - qmp6988_cali.COE_bp2 = (QMP6988_S16_t)((a_data_uint8_tr[10] << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[11]); + qmp6988_cali.COE_bp2 = (int16_t)((a_data_uint8_tr[10] << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[11]); - qmp6988_cali.COE_b12 = (QMP6988_S16_t)((a_data_uint8_tr[12] << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[13]); + qmp6988_cali.COE_b12 = (int16_t)((a_data_uint8_tr[12] << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[13]); - qmp6988_cali.COE_b21 = (QMP6988_S16_t)((a_data_uint8_tr[14] << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[15]); + qmp6988_cali.COE_b21 = (int16_t)((a_data_uint8_tr[14] << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[15]); - qmp6988_cali.COE_bp3 = (QMP6988_S16_t)((a_data_uint8_tr[16] << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[17]); + qmp6988_cali.COE_bp3 = (int16_t)((a_data_uint8_tr[16] << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[17]); dev->ik.a0 = qmp6988_cali.COE_a0; // 20Q4 dev->ik.b00 = qmp6988_cali.COE_b00; // 20Q4 - dev->ik.a1 = 3608L * (QMP6988_S32_t)qmp6988_cali.COE_a1 - 1731677965L; // 31Q23 - dev->ik.a2 = 16889L * (QMP6988_S32_t)qmp6988_cali.COE_a2 - 87619360L; // 30Q47 - - dev->ik.bt1 = 2982L * (QMP6988_S64_t)qmp6988_cali.COE_bt1 + 107370906L; // 28Q15 - dev->ik.bt2 = 329854L * (QMP6988_S64_t)qmp6988_cali.COE_bt2 + 108083093L; // 34Q38 - dev->ik.bp1 = 19923L * (QMP6988_S64_t)qmp6988_cali.COE_bp1 + 1133836764L; // 31Q20 - dev->ik.b11 = 2406L * (QMP6988_S64_t)qmp6988_cali.COE_b11 + 118215883L; // 28Q34 - dev->ik.bp2 = 3079L * (QMP6988_S64_t)qmp6988_cali.COE_bp2 - 181579595L; // 29Q43 - dev->ik.b12 = 6846L * (QMP6988_S64_t)qmp6988_cali.COE_b12 + 85590281L; // 29Q53 - dev->ik.b21 = 13836L * (QMP6988_S64_t)qmp6988_cali.COE_b21 + 79333336L; // 29Q60 - dev->ik.bp3 = 2915L * (QMP6988_S64_t)qmp6988_cali.COE_bp3 + 157155561L; // 28Q65 + dev->ik.a1 = 3608L * (int32_t)qmp6988_cali.COE_a1 - 1731677965L; // 31Q23 + dev->ik.a2 = 16889L * (int32_t)qmp6988_cali.COE_a2 - 87619360L; // 30Q47 + + dev->ik.bt1 = 2982L * (int64_t)qmp6988_cali.COE_bt1 + 107370906L; // 28Q15 + dev->ik.bt2 = 329854L * (int64_t)qmp6988_cali.COE_bt2 + 108083093L; // 34Q38 + dev->ik.bp1 = 19923L * (int64_t)qmp6988_cali.COE_bp1 + 1133836764L; // 31Q20 + dev->ik.b11 = 2406L * (int64_t)qmp6988_cali.COE_b11 + 118215883L; // 28Q34 + dev->ik.bp2 = 3079L * (int64_t)qmp6988_cali.COE_bp2 - 181579595L; // 29Q43 + dev->ik.b12 = 6846L * (int64_t)qmp6988_cali.COE_b12 + 85590281L; // 29Q53 + dev->ik.b21 = 13836L * (int64_t)qmp6988_cali.COE_b21 + 79333336L; // 29Q60 + dev->ik.bp3 = 2915L * (int64_t)qmp6988_cali.COE_bp3 + 157155561L; // 28Q65 + return ESP_OK; +} + +int16_t qmp6988_conv_Tx_02e(qmp6988_ik_data_t *ik, int32_t dt) +{ + int16_t ret; + int64_t wk1, wk2; + + // wk1: 60Q4 // bit size + wk1 = ((int64_t)ik->a1 * (int64_t)dt); // 31Q23+24-1=54 (54Q23) + wk2 = ((int64_t)ik->a2 * (int64_t)dt) >> 14; // 30Q47+24-1=53 (39Q33) + wk2 = (wk2 * (int64_t)dt) >> 10; // 39Q33+24-1=62 (52Q23) + wk2 = ((wk1 + wk2) / 32767) >> 19; // 54,52->55Q23 (20Q04) + ret = (int16_t)((ik->a0 + wk2) >> 4); // 21Q4 -> 17Q0 + return ret; +} + +int32_t qmp6988_get_pressure_02e(qmp6988_ik_data_t *ik, int32_t dp, int16_t tx) +{ + int32_t ret; + int64_t wk1, wk2, wk3; + + // wk1 = 48Q16 // bit size + wk1 = ((int64_t)ik->bt1 * (int64_t)tx); // 28Q15+16-1=43 (43Q15) + wk2 = ((int64_t)ik->bp1 * (int64_t)dp) >> 5; // 31Q20+24-1=54 (49Q15) + wk1 += wk2; // 43,49->50Q15 + wk2 = ((int64_t)ik->bt2 * (int64_t)tx) >> 1; // 34Q38+16-1=49 (48Q37) + wk2 = (wk2 * (int64_t)tx) >> 8; // 48Q37+16-1=63 (55Q29) + wk3 = wk2; // 55Q29 + wk2 = ((int64_t)ik->b11 * (int64_t)tx) >> 4; // 28Q34+16-1=43 (39Q30) + wk2 = (wk2 * (int64_t)dp) >> 1; // 39Q30+24-1=62 (61Q29) + wk3 += wk2; // 55,61->62Q29 + wk2 = ((int64_t)ik->bp2 * (int64_t)dp) >> 13; // 29Q43+24-1=52 (39Q30) + wk2 = (wk2 * (int64_t)dp) >> 1; // 39Q30+24-1=62 (61Q29) + wk3 += wk2; // 62,61->63Q29 + wk1 += wk3 >> 14; // Q29 >> 14 -> Q15 + wk2 = ((int64_t)ik->b12 * (int64_t)tx); // 29Q53+16-1=45 (45Q53) + wk2 = (wk2 * (int64_t)tx) >> 22; // 45Q53+16-1=61 (39Q31) + wk2 = (wk2 * (int64_t)dp) >> 1; // 39Q31+24-1=62 (61Q30) + wk3 = wk2; // 61Q30 + wk2 = ((int64_t)ik->b21 * (int64_t)tx) >> 6; // 29Q60+16-1=45 (39Q54) + wk2 = (wk2 * (int64_t)dp) >> 23; // 39Q54+24-1=62 (39Q31) + wk2 = (wk2 * (int64_t)dp) >> 1; // 39Q31+24-1=62 (61Q20) + wk3 += wk2; // 61,61->62Q30 + wk2 = ((int64_t)ik->bp3 * (int64_t)dp) >> 12; // 28Q65+24-1=51 (39Q53) + wk2 = (wk2 * (int64_t)dp) >> 23; // 39Q53+24-1=62 (39Q30) + wk2 = (wk2 * (int64_t)dp); // 39Q30+24-1=62 (62Q30) + wk3 += wk2; // 62,62->63Q30 + wk1 += wk3 >> 15; // Q30 >> 15 = Q15 + wk1 /= 32767L; + wk1 >>= 11; // Q15 >> 7 = Q4 + wk1 += ik->b00; // Q4 + 20Q4 + // wk1 >>= 4; // 28Q4 -> 24Q0 + ret = (int32_t)wk1; + return ret; +} + +/////////////////////////////////////////////////////////////////////////// + +esp_err_t qmp6988_init_desc(qmp6988_t *dev, uint8_t addr, i2c_port_t port, gpio_num_t sda_gpio, gpio_num_t scl_gpio) +{ + CHECK_ARG(dev); + + dev->i2c_dev.port = port; + dev->i2c_dev.addr = addr; + dev->i2c_dev.cfg.sda_io_num = sda_gpio; + dev->i2c_dev.cfg.scl_io_num = scl_gpio; +#if HELPER_TARGET_IS_ESP32 + dev->i2c_dev.cfg.master.clk_speed = I2C_FREQ_HZ; +#endif + + return i2c_dev_create_mutex(&dev->i2c_dev); +} + +esp_err_t qmp6988_free_desc(qmp6988_t *dev) +{ + CHECK_ARG(dev); + + return i2c_dev_delete_mutex(&dev->i2c_dev); +} + +esp_err_t qmp6988_init(qmp6988_t *dev) +{ + CHECK_ARG(dev); + + dev->power_mode = QMP6988_SLEEP_MODE; + dev->filter_mode = QMP6988_FILTERCOEFF_4; + dev->oversampling_t_mode = QMP6988_OVERSAMPLING_1X; + dev->oversampling_p_mode = QMP6988_OVERSAMPLING_8X; + + CHECK(qmp6988_device_check(dev)); + + CHECK(write_reg(dev, QMP6988_RESET_REG, 0xe6)); + vTaskDelay(TIME_TO_TICKS(20)); // need to wait a short moment after reset + CHECK(qmp6988_get_calibration_data(dev)); + CHECK(qmp6988_setup_powermode(dev, QMP6988_SLEEP_MODE)); + CHECK(qmp6988_set_filter(dev, QMP6988_FILTERCOEFF_4)); + CHECK(qmp6988_set_p_oversampling(dev, QMP6988_OVERSAMPLING_8X)); + CHECK(qmp6988_set_t_oversampling(dev, QMP6988_OVERSAMPLING_1X)); + return ESP_OK; } esp_err_t qmp6988_setup_powermode(qmp6988_t *dev, qmp6988_power_mode_t power_mode) { + CHECK_ARG(dev); + uint8_t data = 0x00; dev->power_mode = power_mode; @@ -243,6 +342,8 @@ esp_err_t qmp6988_setup_powermode(qmp6988_t *dev, qmp6988_power_mode_t power_mod esp_err_t qmp6988_set_filter(qmp6988_t *dev, qmp6988_filter_t filter_mode) { + CHECK_ARG(dev); + dev->filter_mode = filter_mode; CHECK(write_reg(dev, QMP6988_CONFIG_REG, filter_mode)); vTaskDelay(TIME_TO_TICKS(20)); @@ -252,6 +353,8 @@ esp_err_t qmp6988_set_filter(qmp6988_t *dev, qmp6988_filter_t filter_mode) esp_err_t qmp6988_set_p_oversampling(qmp6988_t *dev, qmp6988_oversampling_t oversampling_p_mode) { + CHECK_ARG(dev); + qmp6988_raw_data_t data = 0x00; dev->oversampling_p_mode = oversampling_p_mode; @@ -266,6 +369,8 @@ esp_err_t qmp6988_set_p_oversampling(qmp6988_t *dev, qmp6988_oversampling_t over esp_err_t qmp6988_set_t_oversampling(qmp6988_t *dev, qmp6988_oversampling_t oversampling_t_mode) { + CHECK_ARG(dev); + qmp6988_raw_data_t data = 0x00; dev->oversampling_t_mode = oversampling_t_mode; @@ -278,75 +383,14 @@ esp_err_t qmp6988_set_t_oversampling(qmp6988_t *dev, qmp6988_oversampling_t over return ESP_OK; } -QMP6988_S16_t qmp6988_conv_Tx_02e(qmp6988_ik_data_t *ik, QMP6988_S32_t dt) -{ - QMP6988_S16_t ret; - QMP6988_S64_t wk1, wk2; - - // wk1: 60Q4 // bit size - wk1 = ((QMP6988_S64_t)ik->a1 * (QMP6988_S64_t)dt); // 31Q23+24-1=54 (54Q23) - wk2 = ((QMP6988_S64_t)ik->a2 * (QMP6988_S64_t)dt) >> 14; // 30Q47+24-1=53 (39Q33) - wk2 = (wk2 * (QMP6988_S64_t)dt) >> 10; // 39Q33+24-1=62 (52Q23) - wk2 = ((wk1 + wk2) / 32767) >> 19; // 54,52->55Q23 (20Q04) - ret = (QMP6988_S16_t)((ik->a0 + wk2) >> 4); // 21Q4 -> 17Q0 - return ret; -} - -QMP6988_S32_t qmp6988_get_pressure_02e(qmp6988_ik_data_t *ik, QMP6988_S32_t dp, QMP6988_S16_t tx) -{ - QMP6988_S32_t ret; - QMP6988_S64_t wk1, wk2, wk3; - - // wk1 = 48Q16 // bit size - wk1 = ((QMP6988_S64_t)ik->bt1 * (QMP6988_S64_t)tx); // 28Q15+16-1=43 (43Q15) - wk2 = ((QMP6988_S64_t)ik->bp1 * (QMP6988_S64_t)dp) >> 5; // 31Q20+24-1=54 (49Q15) - wk1 += wk2; // 43,49->50Q15 - wk2 = ((QMP6988_S64_t)ik->bt2 * (QMP6988_S64_t)tx) >> 1; // 34Q38+16-1=49 (48Q37) - wk2 = (wk2 * (QMP6988_S64_t)tx) >> 8; // 48Q37+16-1=63 (55Q29) - wk3 = wk2; // 55Q29 - wk2 = ((QMP6988_S64_t)ik->b11 * (QMP6988_S64_t)tx) >> 4; // 28Q34+16-1=43 (39Q30) - wk2 = (wk2 * (QMP6988_S64_t)dp) >> 1; // 39Q30+24-1=62 (61Q29) - wk3 += wk2; // 55,61->62Q29 - wk2 = ((QMP6988_S64_t)ik->bp2 * (QMP6988_S64_t)dp) >> 13; // 29Q43+24-1=52 (39Q30) - wk2 = (wk2 * (QMP6988_S64_t)dp) >> 1; // 39Q30+24-1=62 (61Q29) - wk3 += wk2; // 62,61->63Q29 - wk1 += wk3 >> 14; // Q29 >> 14 -> Q15 - wk2 = ((QMP6988_S64_t)ik->b12 * (QMP6988_S64_t)tx); // 29Q53+16-1=45 (45Q53) - wk2 = (wk2 * (QMP6988_S64_t)tx) >> 22; // 45Q53+16-1=61 (39Q31) - wk2 = (wk2 * (QMP6988_S64_t)dp) >> 1; // 39Q31+24-1=62 (61Q30) - wk3 = wk2; // 61Q30 - wk2 = ((QMP6988_S64_t)ik->b21 * (QMP6988_S64_t)tx) >> 6; // 29Q60+16-1=45 (39Q54) - wk2 = (wk2 * (QMP6988_S64_t)dp) >> 23; // 39Q54+24-1=62 (39Q31) - wk2 = (wk2 * (QMP6988_S64_t)dp) >> 1; // 39Q31+24-1=62 (61Q20) - wk3 += wk2; // 61,61->62Q30 - wk2 = ((QMP6988_S64_t)ik->bp3 * (QMP6988_S64_t)dp) >> 12; // 28Q65+24-1=51 (39Q53) - wk2 = (wk2 * (QMP6988_S64_t)dp) >> 23; // 39Q53+24-1=62 (39Q30) - wk2 = (wk2 * (QMP6988_S64_t)dp); // 39Q30+24-1=62 (62Q30) - wk3 += wk2; // 62,62->63Q30 - wk1 += wk3 >> 15; // Q30 >> 15 = Q15 - wk1 /= 32767L; - wk1 >>= 11; // Q15 >> 7 = Q4 - wk1 += ik->b00; // Q4 + 20Q4 - // wk1 >>= 4; // 28Q4 -> 24Q0 - ret = (QMP6988_S32_t)wk1; - return ret; -} - -float qmp6988_calc_altitude(float pressure, float temp) +esp_err_t qmp6988_calc_pressure(qmp6988_t *dev, float *p) { - float altitude; + CHECK_ARG(dev && p); - altitude = (pow((101325 / pressure), 1 / 5.257) - 1) * (temp + 273.15) / 0.0065; - ESP_LOGI(TAG, "altitude = %f\r\n", altitude); - return altitude; -} - -float qmp6988_calc_pressure(qmp6988_t *dev) -{ - QMP6988_U32_t P_read, T_read; - QMP6988_S32_t P_raw, T_raw; + uint32_t P_read, T_read; + int32_t P_raw, T_raw; uint8_t a_data_uint8_tr[6] = { 0 }; - QMP6988_S32_t T_int, P_int; + int32_t T_int, P_int; int len; // press @@ -354,72 +398,34 @@ float qmp6988_calc_pressure(qmp6988_t *dev) { CHECK(qmp6988_read_reg(dev, QMP6988_PRESSURE_MSB_REG + len, &a_data_uint8_tr[len])); } - P_read = (QMP6988_U32_t)((((QMP6988_U32_t)(a_data_uint8_tr[0])) << SHIFT_LEFT_16_POSITION) | (((QMP6988_U16_t)(a_data_uint8_tr[1])) << SHIFT_LEFT_8_POSITION) | (a_data_uint8_tr[2])); - P_raw = (QMP6988_S32_t)(P_read - SUBTRACTOR); + P_read = (uint32_t)((((uint32_t)(a_data_uint8_tr[0])) << SHIFT_LEFT_16_POSITION) | (((uint16_t)(a_data_uint8_tr[1])) << SHIFT_LEFT_8_POSITION) | (a_data_uint8_tr[2])); + P_raw = (int32_t)(P_read - SUBTRACTOR); // temp for (len = 3; len < 6; len += 1) { CHECK(qmp6988_read_reg(dev, QMP6988_TEMPERATURE_MSB_REG + len - 3, &a_data_uint8_tr[len])); } - T_read = (QMP6988_U32_t)((((QMP6988_U32_t)(a_data_uint8_tr[3])) << SHIFT_LEFT_16_POSITION) | (((QMP6988_U16_t)(a_data_uint8_tr[4])) << SHIFT_LEFT_8_POSITION) | (a_data_uint8_tr[5])); - T_raw = (QMP6988_S32_t)(T_read - SUBTRACTOR); + T_read = (uint32_t)((((uint32_t)(a_data_uint8_tr[3])) << SHIFT_LEFT_16_POSITION) | (((uint16_t)(a_data_uint8_tr[4])) << SHIFT_LEFT_8_POSITION) | (a_data_uint8_tr[5])); + T_raw = (int32_t)(T_read - SUBTRACTOR); T_int = qmp6988_conv_Tx_02e(&(dev->ik), T_raw); P_int = qmp6988_get_pressure_02e(&(dev->ik), P_raw, T_int); dev->temperature = (float)T_int / 256.0f; dev->pressure = (float)P_int / 16.0f; - return dev->pressure; -} - -float qmp6988_calc_temperature(qmp6988_t *dev) -{ - qmp6988_calc_pressure(dev); - return dev->temperature; -} - -/////////////////////////////////////////////////////////////////////////// - -esp_err_t qmp6988_init_desc(qmp6988_t *dev, uint8_t addr, i2c_port_t port, gpio_num_t sda_gpio, gpio_num_t scl_gpio) -{ - CHECK_ARG(dev); - - dev->i2c_dev.port = port; - dev->i2c_dev.addr = addr; - dev->i2c_dev.cfg.sda_io_num = sda_gpio; - dev->i2c_dev.cfg.scl_io_num = scl_gpio; -#if HELPER_TARGET_IS_ESP32 - dev->i2c_dev.cfg.master.clk_speed = I2C_FREQ_HZ; -#endif - - return i2c_dev_create_mutex(&dev->i2c_dev); -} - -esp_err_t qmp6988_free_desc(qmp6988_t *dev) -{ - CHECK_ARG(dev); + *p = dev->pressure; - return i2c_dev_delete_mutex(&dev->i2c_dev); + return ESP_OK; } -esp_err_t qmp6988_init(qmp6988_t *dev) +esp_err_t qmp6988_calc_temperature(qmp6988_t *dev, float *t) { - CHECK_ARG(dev); + CHECK_ARG(t); - dev->power_mode = QMP6988_SLEEP_MODE; - dev->filter_mode = QMP6988_FILTERCOEFF_4; - dev->oversampling_t_mode = QMP6988_OVERSAMPLING_1X; - dev->oversampling_p_mode = QMP6988_OVERSAMPLING_8X; + float dummy; + CHECK(qmp6988_calc_pressure(dev, &dummy)); + *t = dev->temperature; - CHECK(qmp6988_device_check(dev)); - - CHECK(write_reg(dev, QMP6988_RESET_REG, 0xe6)); - vTaskDelay(TIME_TO_TICKS(20)); // need to wait a short moment after reset - CHECK(qmp6988_get_calibration_data(dev)); - CHECK(qmp6988_setup_powermode(dev, QMP6988_SLEEP_MODE)); - CHECK(qmp6988_set_filter(dev, QMP6988_FILTERCOEFF_4)); - CHECK(qmp6988_set_p_oversampling(dev, QMP6988_OVERSAMPLING_8X)); - CHECK(qmp6988_set_t_oversampling(dev, QMP6988_OVERSAMPLING_1X)); return ESP_OK; } diff --git a/components/qmp6988/qmp6988.h b/components/qmp6988/qmp6988.h index 0b774cc0..639bc407 100644 --- a/components/qmp6988/qmp6988.h +++ b/components/qmp6988/qmp6988.h @@ -56,13 +56,6 @@ extern "C" { #endif -typedef uint16_t QMP6988_U16_t; -typedef int16_t QMP6988_S16_t; -typedef uint32_t QMP6988_U32_t; -typedef int32_t QMP6988_S32_t; -typedef uint64_t QMP6988_U64_t; -typedef int64_t QMP6988_S64_t; - #define QMP6988_I2C_ADDR_GND 0x70 #define QMP6988_I2C_ADDR_VDD 0x56 @@ -70,9 +63,9 @@ typedef int64_t QMP6988_S64_t; * Possible measurement modes */ typedef enum { - QMP6988_SLEEP_MODE = 0x00, // sleep mode - QMP6988_FORCED_MODE = 0x01, // one measurement then sleep again - QMP6988_NORMAL_MODE = 0x03 // power mode + QMP6988_SLEEP_MODE = 0x00, //!< sleep mode + QMP6988_FORCED_MODE = 0x01, //!< one measurement then sleep again + QMP6988_NORMAL_MODE = 0x03 //!< power mode } qmp6988_power_mode_t; /** @@ -104,11 +97,11 @@ typedef enum { /** * Structure holding calibration data for QMP6988. */ -typedef struct _qmp6988_ik_data +typedef struct { - QMP6988_S32_t a0, b00; - QMP6988_S32_t a1, a2; - QMP6988_S64_t bt1, bt2, bp1, b11, bp2, b12, b21, bp3; + int32_t a0, b00; + int32_t a1, a2; + int64_t bt1, bt2, bp1, b11, bp2, b12, b21, bp3; } qmp6988_ik_data_t; /** @@ -197,17 +190,19 @@ esp_err_t qmp6988_set_t_oversampling(qmp6988_t *dev, qmp6988_oversampling_t over * @brief Calculate pressure based on QMP6988 sensor data. * * @param dev Device descriptor. - * @return Calculated pressure in Pascals (Pa). + * @param[out] p Calculated pressure in Pascals (Pa). + * @return `ESP_OK` on success. */ -float qmp6988_calc_pressure(qmp6988_t *dev); +esp_err_t qmp6988_calc_pressure(qmp6988_t *dev, float *p); /** * @brief Calculate temperature based on QMP6988 sensor data. * * @param dev Device descriptor. - * @return Calculated temperature in degrees Celsius (°C). + * @param[out] t Calculated temperature in degrees Celsius (°C). + * @return `ESP_OK` on success. */ -float qmp6988_calc_temperature(qmp6988_t *dev); +esp_err_t qmp6988_calc_temperature(qmp6988_t *dev, float *t); #ifdef __cplusplus } diff --git a/docs/source/groups/qmp6988.rst b/docs/source/groups/qmp6988.rst new file mode 100644 index 00000000..42a42ec7 --- /dev/null +++ b/docs/source/groups/qmp6988.rst @@ -0,0 +1,8 @@ +.. _qmp6988: + +qmp6988 - Driver for QMP6988 digital temperature and pressure sensor +==================================================================== + +.. doxygengroup:: qmp6988 + :members: + diff --git a/docs/source/index.rst b/docs/source/index.rst index 3e63c149..b135cd4b 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -132,6 +132,7 @@ Pressure sensors groups/bme680 groups/dps310 groups/ms5611 + groups/qmp6988 Air quality/Gas sensors ======================= diff --git a/examples/qmp6988/default/main/Kconfig.projbuild b/examples/qmp6988/default/main/Kconfig.projbuild index 35e335cc..35646959 100644 --- a/examples/qmp6988/default/main/Kconfig.projbuild +++ b/examples/qmp6988/default/main/Kconfig.projbuild @@ -1,5 +1,5 @@ menu "Example configuration" - choice EXAMPLE_SHT3X_DEMO + choice EXAMPLE_QMP6988_DEMO prompt "Demo mode" default EXAMPLE_QMP6988_DEMO_NORMAL help @@ -12,7 +12,7 @@ menu "Example configuration" In this example the qmp6988 makes a single measurement before entering sleep mode again. - config EXAMPLE_SHT3X_DEMO_NORMAL + config EXAMPLE_QMP6988_DEMO_NORMAL bool "Normal mode" help In this example the qmp6988 makes continuous measurements. diff --git a/examples/qmp6988/default/main/main.c b/examples/qmp6988/default/main/main.c index 3d8187c9..b380d246 100644 --- a/examples/qmp6988/default/main/main.c +++ b/examples/qmp6988/default/main/main.c @@ -59,7 +59,7 @@ void task(void *pvParameters) /*Calculate pressure values (this includes temperature as well, as temp is needed to calc pressure)*/ - pressure = qmp6988_calc_pressure(&dev); + ESP_ERROR_CHECK(qmp6988_calc_pressure(&dev, &pressure)); temperature = dev.temperature; printf("QMP6988 Sensor: %.2f °C, %.2f Pa\n", temperature, pressure); @@ -94,7 +94,7 @@ void task(void *pvParameters) { /*Calculate pressure values (this includes temperature as well, as temp is needed to calc pressure)*/ - pressure = qmp6988_calc_pressure(&dev); + ESP_ERROR_CHECK(qmp6988_calc_pressure(&dev, &pressure)); temperature = dev.temperature; printf("QMP6988 Sensor: %.2f °C, %.2f Pa\n", temperature, pressure);