ESPHome 2026.5.0-dev
Loading...
Searching...
No Matches
qmp6988.cpp
Go to the documentation of this file.
1#include "qmp6988.h"
2
3#include <cinttypes>
4#include <cmath>
5
6namespace esphome {
7namespace qmp6988 {
8
9static const uint8_t QMP6988_CHIP_ID = 0x5C;
10
11static const uint8_t QMP6988_CHIP_ID_REG = 0xD1; /* Chip ID confirmation Register */
12static const uint8_t QMP6988_RESET_REG = 0xE0; /* Device reset register */
13static const uint8_t QMP6988_DEVICE_STAT_REG = 0xF3; /* Device state register */
14static const uint8_t QMP6988_CTRLMEAS_REG = 0xF4; /* Measurement Condition Control Register */
15/* data */
16static const uint8_t QMP6988_PRESSURE_MSB_REG = 0xF7; /* Pressure MSB Register */
17static const uint8_t QMP6988_TEMPERATURE_MSB_REG = 0xFA; /* Temperature MSB Reg */
18
19/* compensation calculation */
20static const uint8_t QMP6988_CALIBRATION_DATA_START = 0xA0; /* QMP6988 compensation coefficients */
21static const uint8_t QMP6988_CALIBRATION_DATA_LENGTH = 25;
22
23/* power mode */
24static const uint8_t QMP6988_SLEEP_MODE = 0x00;
25static const uint8_t QMP6988_FORCED_MODE = 0x01;
26static const uint8_t QMP6988_NORMAL_MODE = 0x03;
27
28static const uint8_t QMP6988_CTRLMEAS_REG_MODE_POS = 0;
29static const uint8_t QMP6988_CTRLMEAS_REG_MODE_MSK = 0x03;
30static const uint8_t QMP6988_CTRLMEAS_REG_MODE_LEN = 2;
31
32static const uint8_t QMP6988_CTRLMEAS_REG_OSRST_POS = 5;
33static const uint8_t QMP6988_CTRLMEAS_REG_OSRST_MSK = 0xE0;
34static const uint8_t QMP6988_CTRLMEAS_REG_OSRST_LEN = 3;
35
36static const uint8_t QMP6988_CTRLMEAS_REG_OSRSP_POS = 2;
37static const uint8_t QMP6988_CTRLMEAS_REG_OSRSP_MSK = 0x1C;
38static const uint8_t QMP6988_CTRLMEAS_REG_OSRSP_LEN = 3;
39
40static const uint8_t QMP6988_CONFIG_REG = 0xF1; /*IIR filter co-efficient setting Register*/
41static const uint8_t QMP6988_CONFIG_REG_FILTER_POS = 0;
42static const uint8_t QMP6988_CONFIG_REG_FILTER_MSK = 0x07;
43static const uint8_t QMP6988_CONFIG_REG_FILTER_LEN = 3;
44
45static const uint32_t SUBTRACTOR = 8388608;
46
47static const char *const TAG = "qmp6988";
48
49static const char *oversampling_to_str(QMP6988Oversampling oversampling) {
50 switch (oversampling) {
52 return "None";
54 return "1x";
56 return "2x";
58 return "4x";
60 return "8x";
62 return "16x";
64 return "32x";
66 return "64x";
67 default:
68 return "UNKNOWN";
69 }
70}
71
72static const char *iir_filter_to_str(QMP6988IIRFilter filter) {
73 switch (filter) {
75 return "OFF";
77 return "2x";
79 return "4x";
81 return "8x";
83 return "16x";
85 return "32x";
86 default:
87 return "UNKNOWN";
88 }
89}
90
92 if (this->read_register(QMP6988_CHIP_ID_REG, &(qmp6988_data_.chip_id), 1) != i2c::ERROR_OK) {
93 ESP_LOGE(TAG, "Read chip ID (0xD1) failed");
94 return false;
95 }
96 ESP_LOGV(TAG, "Read chip ID = 0x%x", qmp6988_data_.chip_id);
97
98 return qmp6988_data_.chip_id == QMP6988_CHIP_ID;
99}
100
102 // BITFIELDS temp_COE;
103 uint8_t a_data_uint8_tr[QMP6988_CALIBRATION_DATA_LENGTH] = {0};
104
105 for (uint8_t len = 0; len < QMP6988_CALIBRATION_DATA_LENGTH; len += 1) {
106 if (this->read_register(QMP6988_CALIBRATION_DATA_START + len, &a_data_uint8_tr[len], 1) != i2c::ERROR_OK) {
107 ESP_LOGE(TAG, "Read calibration data (0xA0) error");
108 return false;
109 }
110 }
111
112 qmp6988_data_.qmp6988_cali.COE_a0 =
113 (int32_t) encode_uint32(a_data_uint8_tr[18], a_data_uint8_tr[19], (a_data_uint8_tr[24] & 0x0f) << 4, 0);
114 qmp6988_data_.qmp6988_cali.COE_a0 = qmp6988_data_.qmp6988_cali.COE_a0 >> 12;
115
116 qmp6988_data_.qmp6988_cali.COE_a1 = (int16_t) encode_uint16(a_data_uint8_tr[20], a_data_uint8_tr[21]);
117 qmp6988_data_.qmp6988_cali.COE_a2 = (int16_t) encode_uint16(a_data_uint8_tr[22], a_data_uint8_tr[23]);
118
119 qmp6988_data_.qmp6988_cali.COE_b00 =
120 (int32_t) encode_uint32(a_data_uint8_tr[0], a_data_uint8_tr[1], a_data_uint8_tr[24] & 0xf0, 0);
121 qmp6988_data_.qmp6988_cali.COE_b00 = qmp6988_data_.qmp6988_cali.COE_b00 >> 12;
122
123 qmp6988_data_.qmp6988_cali.COE_bt1 = (int16_t) encode_uint16(a_data_uint8_tr[2], a_data_uint8_tr[3]);
124 qmp6988_data_.qmp6988_cali.COE_bt2 = (int16_t) encode_uint16(a_data_uint8_tr[4], a_data_uint8_tr[5]);
125 qmp6988_data_.qmp6988_cali.COE_bp1 = (int16_t) encode_uint16(a_data_uint8_tr[6], a_data_uint8_tr[7]);
126 qmp6988_data_.qmp6988_cali.COE_b11 = (int16_t) encode_uint16(a_data_uint8_tr[8], a_data_uint8_tr[9]);
127 qmp6988_data_.qmp6988_cali.COE_bp2 = (int16_t) encode_uint16(a_data_uint8_tr[10], a_data_uint8_tr[11]);
128 qmp6988_data_.qmp6988_cali.COE_b12 = (int16_t) encode_uint16(a_data_uint8_tr[12], a_data_uint8_tr[13]);
129 qmp6988_data_.qmp6988_cali.COE_b21 = (int16_t) encode_uint16(a_data_uint8_tr[14], a_data_uint8_tr[15]);
130 qmp6988_data_.qmp6988_cali.COE_bp3 = (int16_t) encode_uint16(a_data_uint8_tr[16], a_data_uint8_tr[17]);
131
132 ESP_LOGV(TAG,
133 "Calibration data:\n"
134 " COE_a0[%" PRId32 "] COE_a1[%d] COE_a2[%d] COE_b00[%" PRId32 "]\n"
135 " COE_bt1[%d] COE_bt2[%d] COE_bp1[%d] COE_b11[%d]\n"
136 " COE_bp2[%d] COE_b12[%d] COE_b21[%d] COE_bp3[%d]",
137 qmp6988_data_.qmp6988_cali.COE_a0, qmp6988_data_.qmp6988_cali.COE_a1, qmp6988_data_.qmp6988_cali.COE_a2,
138 qmp6988_data_.qmp6988_cali.COE_b00, qmp6988_data_.qmp6988_cali.COE_bt1, qmp6988_data_.qmp6988_cali.COE_bt2,
139 qmp6988_data_.qmp6988_cali.COE_bp1, qmp6988_data_.qmp6988_cali.COE_b11, qmp6988_data_.qmp6988_cali.COE_bp2,
140 qmp6988_data_.qmp6988_cali.COE_b12, qmp6988_data_.qmp6988_cali.COE_b21, qmp6988_data_.qmp6988_cali.COE_bp3);
141
142 qmp6988_data_.ik.a0 = qmp6988_data_.qmp6988_cali.COE_a0; // 20Q4
143 qmp6988_data_.ik.b00 = qmp6988_data_.qmp6988_cali.COE_b00; // 20Q4
144
145 qmp6988_data_.ik.a1 = 3608L * (int32_t) qmp6988_data_.qmp6988_cali.COE_a1 - 1731677965L; // 31Q23
146 qmp6988_data_.ik.a2 = 16889L * (int32_t) qmp6988_data_.qmp6988_cali.COE_a2 - 87619360L; // 30Q47
147
148 qmp6988_data_.ik.bt1 = 2982L * (int64_t) qmp6988_data_.qmp6988_cali.COE_bt1 + 107370906L; // 28Q15
149 qmp6988_data_.ik.bt2 = 329854L * (int64_t) qmp6988_data_.qmp6988_cali.COE_bt2 + 108083093L; // 34Q38
150 qmp6988_data_.ik.bp1 = 19923L * (int64_t) qmp6988_data_.qmp6988_cali.COE_bp1 + 1133836764L; // 31Q20
151 qmp6988_data_.ik.b11 = 2406L * (int64_t) qmp6988_data_.qmp6988_cali.COE_b11 + 118215883L; // 28Q34
152 qmp6988_data_.ik.bp2 = 3079L * (int64_t) qmp6988_data_.qmp6988_cali.COE_bp2 - 181579595L; // 29Q43
153 qmp6988_data_.ik.b12 = 6846L * (int64_t) qmp6988_data_.qmp6988_cali.COE_b12 + 85590281L; // 29Q53
154 qmp6988_data_.ik.b21 = 13836L * (int64_t) qmp6988_data_.qmp6988_cali.COE_b21 + 79333336L; // 29Q60
155 qmp6988_data_.ik.bp3 = 2915L * (int64_t) qmp6988_data_.qmp6988_cali.COE_bp3 + 157155561L; // 28Q65
156 ESP_LOGV(TAG,
157 "Int calibration data:\n"
158 " a0[%" PRId32 "] a1[%" PRId32 "] a2[%" PRId32 "] b00[%" PRId32 "]\n"
159 " bt1[%lld] bt2[%lld] bp1[%lld] b11[%lld]\n"
160 " bp2[%lld] b12[%lld] b21[%lld] bp3[%lld]",
161 qmp6988_data_.ik.a0, qmp6988_data_.ik.a1, qmp6988_data_.ik.a2, qmp6988_data_.ik.b00, qmp6988_data_.ik.bt1,
162 qmp6988_data_.ik.bt2, qmp6988_data_.ik.bp1, qmp6988_data_.ik.b11, qmp6988_data_.ik.bp2, qmp6988_data_.ik.b12,
163 qmp6988_data_.ik.b21, qmp6988_data_.ik.bp3);
164 return true;
165}
166
168 int16_t ret;
169 int64_t wk1, wk2;
170
171 // wk1: 60Q4 // bit size
172 wk1 = ((int64_t) ik->a1 * (int64_t) dt); // 31Q23+24-1=54 (54Q23)
173 wk2 = ((int64_t) ik->a2 * (int64_t) dt) >> 14; // 30Q47+24-1=53 (39Q33)
174 wk2 = (wk2 * (int64_t) dt) >> 10; // 39Q33+24-1=62 (52Q23)
175 wk2 = ((wk1 + wk2) / 32767) >> 19; // 54,52->55Q23 (20Q04)
176 ret = (int16_t) ((ik->a0 + wk2) >> 4); // 21Q4 -> 17Q0
177 return ret;
178}
179
181 int32_t ret;
182 int64_t wk1, wk2, wk3;
183
184 // wk1 = 48Q16 // bit size
185 wk1 = ((int64_t) ik->bt1 * (int64_t) tx); // 28Q15+16-1=43 (43Q15)
186 wk2 = ((int64_t) ik->bp1 * (int64_t) dp) >> 5; // 31Q20+24-1=54 (49Q15)
187 wk1 += wk2; // 43,49->50Q15
188 wk2 = ((int64_t) ik->bt2 * (int64_t) tx) >> 1; // 34Q38+16-1=49 (48Q37)
189 wk2 = (wk2 * (int64_t) tx) >> 8; // 48Q37+16-1=63 (55Q29)
190 wk3 = wk2; // 55Q29
191 wk2 = ((int64_t) ik->b11 * (int64_t) tx) >> 4; // 28Q34+16-1=43 (39Q30)
192 wk2 = (wk2 * (int64_t) dp) >> 1; // 39Q30+24-1=62 (61Q29)
193 wk3 += wk2; // 55,61->62Q29
194 wk2 = ((int64_t) ik->bp2 * (int64_t) dp) >> 13; // 29Q43+24-1=52 (39Q30)
195 wk2 = (wk2 * (int64_t) dp) >> 1; // 39Q30+24-1=62 (61Q29)
196 wk3 += wk2; // 62,61->63Q29
197 wk1 += wk3 >> 14; // Q29 >> 14 -> Q15
198 wk2 = ((int64_t) ik->b12 * (int64_t) tx); // 29Q53+16-1=45 (45Q53)
199 wk2 = (wk2 * (int64_t) tx) >> 22; // 45Q53+16-1=61 (39Q31)
200 wk2 = (wk2 * (int64_t) dp) >> 1; // 39Q31+24-1=62 (61Q30)
201 wk3 = wk2; // 61Q30
202 wk2 = ((int64_t) ik->b21 * (int64_t) tx) >> 6; // 29Q60+16-1=45 (39Q54)
203 wk2 = (wk2 * (int64_t) dp) >> 23; // 39Q54+24-1=62 (39Q31)
204 wk2 = (wk2 * (int64_t) dp) >> 1; // 39Q31+24-1=62 (61Q20)
205 wk3 += wk2; // 61,61->62Q30
206 wk2 = ((int64_t) ik->bp3 * (int64_t) dp) >> 12; // 28Q65+24-1=51 (39Q53)
207 wk2 = (wk2 * (int64_t) dp) >> 23; // 39Q53+24-1=62 (39Q30)
208 wk2 = (wk2 * (int64_t) dp); // 39Q30+24-1=62 (62Q30)
209 wk3 += wk2; // 62,62->63Q30
210 wk1 += wk3 >> 15; // Q30 >> 15 = Q15
211 wk1 /= 32767L;
212 wk1 >>= 11; // Q15 >> 7 = Q4
213 wk1 += ik->b00; // Q4 + 20Q4
214 // wk1 >>= 4; // 28Q4 -> 24Q0
215 ret = (int32_t) wk1;
216 return ret;
217}
218
220 uint8_t ret = 0;
221
222 ret = this->write_byte(QMP6988_RESET_REG, 0xe6);
223 if (ret != i2c::ERROR_OK) {
224 ESP_LOGE(TAG, "Software Reset (0xe6) failed");
225 }
226 delay(10);
227
228 this->write_byte(QMP6988_RESET_REG, 0x00);
229}
230
232 uint8_t data;
233
234 ESP_LOGD(TAG, "Setting Power mode to: %d", power_mode);
235
236 qmp6988_data_.power_mode = power_mode;
237 this->read_register(QMP6988_CTRLMEAS_REG, &data, 1);
238 data = data & 0xfc;
239 if (power_mode == QMP6988_SLEEP_MODE) {
240 data |= 0x00;
241 } else if (power_mode == QMP6988_FORCED_MODE) {
242 data |= 0x01;
243 } else if (power_mode == QMP6988_NORMAL_MODE) {
244 data |= 0x03;
245 }
246 this->write_byte(QMP6988_CTRLMEAS_REG, data);
247
248 ESP_LOGD(TAG, "Set Power mode 0xf4=0x%x \r\n", data);
249
250 delay(10);
251}
252
254 uint8_t data;
255
256 data = (filter & QMP6988_CONFIG_REG_FILTER_MSK);
257 this->write_byte(QMP6988_CONFIG_REG, data);
258 delay(10);
259}
260
262 uint8_t data;
263
264 this->read_register(QMP6988_CTRLMEAS_REG, &data, 1);
265 data &= 0xe3;
266 data |= (oversampling_p << 2);
267 this->write_byte(QMP6988_CTRLMEAS_REG, data);
268 delay(10);
269}
270
272 uint8_t data;
273
274 this->read_register(QMP6988_CTRLMEAS_REG, &data, 1);
275 data &= 0x1f;
276 data |= (oversampling_t << 5);
277 this->write_byte(QMP6988_CTRLMEAS_REG, data);
278 delay(10);
279}
280
282 float altitude;
283 altitude = (pow((101325 / pressure), 1 / 5.257) - 1) * (temp + 273.15) / 0.0065;
284 this->qmp6988_data_.altitude = altitude;
285}
286
288 uint8_t err = 0;
289 uint32_t p_read, t_read;
290 int32_t p_raw, t_raw;
291 uint8_t a_data_uint8_tr[6] = {0};
292 int32_t t_int, p_int;
293 this->qmp6988_data_.temperature = 0;
294 this->qmp6988_data_.pressure = 0;
295
296 err = this->read_register(QMP6988_PRESSURE_MSB_REG, a_data_uint8_tr, 6);
297 if (err != i2c::ERROR_OK) {
298 ESP_LOGE(TAG, "Error reading raw pressure/temp values");
299 return;
300 }
301 p_read = encode_uint24(a_data_uint8_tr[0], a_data_uint8_tr[1], a_data_uint8_tr[2]);
302 p_raw = (int32_t) (p_read - SUBTRACTOR);
303
304 t_read = encode_uint24(a_data_uint8_tr[3], a_data_uint8_tr[4], a_data_uint8_tr[5]);
305 t_raw = (int32_t) (t_read - SUBTRACTOR);
306
307 t_int = this->get_compensated_temperature_(&(qmp6988_data_.ik), t_raw);
308 p_int = this->get_compensated_pressure_(&(qmp6988_data_.ik), p_raw, t_int);
309
310 this->qmp6988_data_.temperature = (float) t_int / 256.0f;
311 this->qmp6988_data_.pressure = (float) p_int / 16.0f;
312}
313
315 if (!this->device_check_()) {
316 this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL));
317 return;
318 }
319
320 this->software_reset_();
321 this->get_calibration_data_();
322 this->set_power_mode_(QMP6988_NORMAL_MODE);
326}
327
329 ESP_LOGCONFIG(TAG, "QMP6988:");
330 LOG_I2C_DEVICE(this);
331 LOG_UPDATE_INTERVAL(this);
332
333 LOG_SENSOR(" ", "Temperature", this->temperature_sensor_);
334 ESP_LOGCONFIG(TAG, " Temperature Oversampling: %s", oversampling_to_str(this->temperature_oversampling_));
335 LOG_SENSOR(" ", "Pressure", this->pressure_sensor_);
336 ESP_LOGCONFIG(TAG,
337 " Pressure Oversampling: %s\n"
338 " IIR Filter: %s",
339 oversampling_to_str(this->pressure_oversampling_), iir_filter_to_str(this->iir_filter_));
340}
341
343 this->calculate_pressure_();
344 float pressurehectopascals = this->qmp6988_data_.pressure / 100;
345 float temperature = this->qmp6988_data_.temperature;
346
347 ESP_LOGD(TAG, "Temperature=%.2f°C, Pressure=%.2fhPa", temperature, pressurehectopascals);
348 if (this->temperature_sensor_ != nullptr)
349 this->temperature_sensor_->publish_state(temperature);
350 if (this->pressure_sensor_ != nullptr)
351 this->pressure_sensor_->publish_state(pressurehectopascals);
352}
353
354} // namespace qmp6988
355} // namespace esphome
void mark_failed()
Mark this component as failed.
bool write_byte(uint8_t a_register, uint8_t data) const
Definition i2c.h:265
ErrorCode read_register(uint8_t a_register, uint8_t *data, size_t len)
reads an array of bytes from a specific register in the I²C device
Definition i2c.cpp:25
void write_filter_(QMP6988IIRFilter filter)
Definition qmp6988.cpp:253
sensor::Sensor * temperature_sensor_
Definition qmp6988.h:88
void calculate_altitude_(float pressure, float temp)
Definition qmp6988.cpp:281
int32_t get_compensated_pressure_(qmp6988_ik_data_t *ik, int32_t dp, int16_t tx)
Definition qmp6988.cpp:180
QMP6988Oversampling pressure_oversampling_
Definition qmp6988.h:92
void write_oversampling_pressure_(QMP6988Oversampling oversampling_p)
Definition qmp6988.cpp:261
sensor::Sensor * pressure_sensor_
Definition qmp6988.h:89
QMP6988Oversampling temperature_oversampling_
Definition qmp6988.h:91
int16_t get_compensated_temperature_(qmp6988_ik_data_t *ik, int32_t dt)
Definition qmp6988.cpp:167
void set_power_mode_(uint8_t power_mode)
Definition qmp6988.cpp:231
void write_oversampling_temperature_(QMP6988Oversampling oversampling_t)
Definition qmp6988.cpp:271
void publish_state(float state)
Publish a new state to the front-end.
Definition sensor.cpp:68
PowerMode power_mode
Definition msa3xx.h:3
@ ERROR_OK
No error found during execution of method.
Definition i2c_bus.h:14
struct Qmp6988IkData { int32_t a0, b00; int32_t a1, a2; int64_t bt1, bt2, bp1, b11, bp2, b12, b21, bp3;} qmp6988_ik_data_t
Definition qmp6988.h:55
@ QMP6988_OVERSAMPLING_8X
Definition qmp6988.h:19
@ QMP6988_OVERSAMPLING_SKIPPED
Definition qmp6988.h:15
@ QMP6988_OVERSAMPLING_16X
Definition qmp6988.h:20
@ QMP6988_OVERSAMPLING_32X
Definition qmp6988.h:21
@ QMP6988_OVERSAMPLING_2X
Definition qmp6988.h:17
@ QMP6988_OVERSAMPLING_64X
Definition qmp6988.h:22
@ QMP6988_OVERSAMPLING_1X
Definition qmp6988.h:16
@ QMP6988_OVERSAMPLING_4X
Definition qmp6988.h:18
@ QMP6988_IIR_FILTER_2X
Definition qmp6988.h:28
@ QMP6988_IIR_FILTER_4X
Definition qmp6988.h:29
@ QMP6988_IIR_FILTER_16X
Definition qmp6988.h:31
@ QMP6988_IIR_FILTER_8X
Definition qmp6988.h:30
@ QMP6988_IIR_FILTER_32X
Definition qmp6988.h:32
@ QMP6988_IIR_FILTER_OFF
Definition qmp6988.h:27
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7
std::string size_t len
Definition helpers.h:1045
constexpr uint32_t encode_uint24(uint8_t byte1, uint8_t byte2, uint8_t byte3)
Encode a 24-bit value given three bytes in most to least significant byte order.
Definition helpers.h:885
constexpr uint32_t encode_uint32(uint8_t byte1, uint8_t byte2, uint8_t byte3, uint8_t byte4)
Encode a 32-bit value given four bytes in most to least significant byte order.
Definition helpers.h:889
constexpr uint16_t encode_uint16(uint8_t msb, uint8_t lsb)
Encode a 16-bit value given the most and least significant byte.
Definition helpers.h:881
void HOT delay(uint32_t ms)
Definition core.cpp:28
static void uint32_t
uint16_t temperature
Definition sun_gtil2.cpp:12
uint8_t pressure
Definition tt21100.cpp:7