1#![doc = include_str!("../README.md")]
2#![deny(unsafe_code, missing_docs)]
3#![no_std]
4
5use embedded_hal::i2c::{Operation, SevenBitAddress};
6#[allow(unused_imports)]
7use micromath::F32Ext;
8
9pub const I2C_ADDRESS_LOGIC_LOW: SevenBitAddress = 0x70;
11pub const I2C_ADDRESS_LOGIC_HIGH: SevenBitAddress = 0x56;
13pub const DEFAULT_I2C_ADDRESS: SevenBitAddress = I2C_ADDRESS_LOGIC_LOW;
15
16const CHIP_ID_REGISTER: &[u8] = &[0xd1];
17const COE_B00_1_REGISTER: &[u8] = &[0xa0];
18const CTRL_MEAS_REGISTER: &[u8] = &[0xf4];
19const IIR_CNT_REGISTER: &[u8] = &[0xf1];
20const PRESS_TXD2: &[u8] = &[0xf7];
21const RESET_REGISTER: &[u8] = &[0xe0];
22
23#[derive(Debug)]
25pub enum Error<I2cE>
26where
27 I2cE: embedded_hal::i2c::Error,
28{
29 I2c(I2cE),
31 ChipNotDetected,
33 BadCrc,
35}
36
37impl<I2cE> From<I2cE> for Error<I2cE>
38where
39 I2cE: embedded_hal::i2c::Error,
40{
41 fn from(value: I2cE) -> Self {
42 Error::I2c(value)
43 }
44}
45
46#[derive(Clone, Copy, Debug, Default)]
51#[repr(u8)]
52pub enum IirFilter {
53 Off = 0x00,
55 Coeff2 = 0x01,
57 #[default]
59 Coeff4 = 0x02,
60 Coeff8 = 0x03,
62 Coeff16 = 0x04,
64 Coeff32 = 0x05,
66}
67
68#[derive(Clone, Copy, Debug, Default)]
74#[repr(u8)]
75pub enum OverSamplingSetting {
76 HighSpeed,
79 LowPower,
82 #[default]
86 Standard,
87 HighAccuracy,
90 UltraHighAccuracy,
93}
94
95#[derive(Clone, Copy, Debug, Default)]
96#[repr(u8)]
97enum PowerMode {
98 #[default]
99 Sleep = 0x00,
100 Forced = 0x01,
101 #[allow(dead_code)]
102 Normal = 0x03,
103}
104
105#[derive(Clone, Copy, Debug, Default)]
106#[repr(u8)]
107enum OverSampling {
108 #[default]
110 X1 = 0x01,
111 X2 = 0x02,
112 X4 = 0x03,
113 X8 = 0x04,
114 X16 = 0x05,
115 X32 = 0x06,
116 }
118
119#[derive(Debug, Default)]
120struct Coe {
121 a0: i32,
122 a1: i16,
123 a2: i16,
124 b00: i32,
125 bt1: i16,
126 bt2: i16,
127 bp1: i16,
128 b11: i16,
129 bp2: i16,
130 b12: i16,
131 b21: i16,
132 bp3: i16,
133}
134
135impl From<&[u8; 25]> for Coe {
136 fn from(value: &[u8; 25]) -> Self {
137 Coe {
138 a0: ((((value[18] as u32) << 12 | (value[19] as u32) << 4 | (value[24] as u32) & 0x0f)
139 << 12) as i32)
140 >> 12,
141 a1: ((value[20] as u16) << 8 | (value[21] as u16)) as i16,
142 a2: ((value[22] as u16) << 8 | (value[23] as u16)) as i16,
143 b00: ((((value[0] as u32) << 12
144 | (value[1] as u32) << 4
145 | ((value[24] as u32) & 0xf0) >> 4)
146 << 12) as i32)
147 >> 12,
148 bt1: ((value[2] as u16) << 8 | (value[3] as u16)) as i16,
149 bt2: ((value[4] as u16) << 8 | (value[5] as u16)) as i16,
150 bp1: ((value[6] as u16) << 8 | (value[7] as u16)) as i16,
151 b11: ((value[8] as u16) << 8 | (value[9] as u16)) as i16,
152 bp2: ((value[10] as u16) << 8 | (value[11] as u16)) as i16,
153 b12: ((value[12] as u16) << 8 | (value[13] as u16)) as i16,
154 b21: ((value[14] as u16) << 8 | (value[15] as u16)) as i16,
155 bp3: ((value[16] as u16) << 8 | (value[17] as u16)) as i16,
156 }
157 }
158}
159
160#[derive(Debug, Default)]
161struct K {
162 a0: f32,
163 a1: f32,
164 a2: f32,
165 b00: f32,
166 bt1: f32,
167 bt2: f32,
168 bp1: f32,
169 b11: f32,
170 bp2: f32,
171 b12: f32,
172 b21: f32,
173 bp3: f32,
174}
175
176impl From<&Coe> for K {
177 fn from(value: &Coe) -> Self {
178 K {
179 a0: value.a0 as f32 / 16.0,
180 a1: -6.30E-03 + ((4.30E-04 * value.a1 as f32) / 32_767.0),
181 a2: -1.90E-11 + ((1.20E-10 * value.a2 as f32) / 32_767.0),
182 b00: value.b00 as f32 / 16.0,
183 bt1: 1.00E-01 + ((9.10E-02 * value.bt1 as f32) / 32_767.0),
184 bt2: 1.20E-08 + ((1.20E-06 * value.bt2 as f32) / 32_767.0),
185 bp1: 3.30E-02 + ((1.90E-02 * value.bp1 as f32) / 32_767.0),
186 b11: 2.10E-07 + ((1.40E-07 * value.b11 as f32) / 32_767.0),
187 bp2: -6.30E-10 + ((3.50E-10 * value.bp2 as f32) / 32_767.0),
188 b12: 2.90E-13 + ((7.60E-13 * value.b12 as f32) / 32_767.0),
189 b21: 2.10E-15 + ((1.20E-14 * value.b21 as f32) / 32_767.0),
190 bp3: 1.30E-16 + ((7.90E-17 * value.bp3 as f32) / 32_767.0),
191 }
192 }
193}
194
195#[derive(Clone, Copy, Debug, Default)]
199pub struct Measurement {
200 pub pressure: f32,
202 pub temperature: f32,
204}
205
206#[derive(Debug)]
208pub struct Qmp6988<I2C, D> {
209 address: SevenBitAddress,
210 coe: Coe,
211 delay: D,
212 filter: IirFilter,
213 i2c: I2C,
214 k: K,
215 oversampling_setting: OverSamplingSetting,
216}
217
218impl<I2C, D> Qmp6988<I2C, D>
219where
220 I2C: embedded_hal::i2c::I2c,
221 D: embedded_hal::delay::DelayNs,
222{
223 pub fn measure(&mut self) -> Result<Measurement, Error<I2C::Error>> {
229 self.apply_power_mode(PowerMode::Forced)?;
230 self.delay.delay_ms(self.get_measurement_duration());
231 let mut dp = [0u8; 3];
232 let mut dt = [0u8; 3];
233 let mut operations = [
234 Operation::Write(PRESS_TXD2),
235 Operation::Read(&mut dp),
236 Operation::Read(&mut dt),
237 ];
238 self.i2c.transaction(self.address, &mut operations)?;
239 let dp = Self::get_i32_value(&dp) - 8_388_608;
240 let dt = Self::get_i32_value(&dt) - 8_388_608;
241 let temperature = self.compensate_temperature(dt);
242 let pressure = self.compensate_pressure(dp, temperature);
243 Ok(Measurement {
244 pressure: pressure / 100.0,
245 temperature: temperature / 256.0,
246 })
247 }
248
249 pub fn new(i2c: I2C, address: SevenBitAddress, delay: D) -> Result<Self, Error<I2C::Error>> {
251 let mut device = Self {
252 address,
253 coe: Coe::default(),
254 delay,
255 filter: IirFilter::default(),
256 i2c,
257 k: K::default(),
258 oversampling_setting: OverSamplingSetting::default(),
259 };
260 device.check_device()?;
261 device.get_calibration_data()?;
262 device.apply_filter()?;
263 device.apply_measure_control_parameters()?;
264 Ok(device)
265 }
266
267 pub fn reset(&mut self) -> Result<(), Error<I2C::Error>> {
269 self.i2c.write(self.address, RESET_REGISTER)?;
270 self.delay.delay_ms(10);
271 Ok(())
272 }
273
274 pub fn set_filter(&mut self, filter: IirFilter) -> Result<(), Error<I2C::Error>> {
277 self.filter = filter;
278 self.apply_filter()
279 }
280
281 pub fn set_oversampling_setting(
283 &mut self,
284 oversampling_setting: OverSamplingSetting,
285 ) -> Result<(), Error<I2C::Error>> {
286 self.oversampling_setting = oversampling_setting;
287 self.apply_measure_control_parameters()
288 }
289
290 fn apply_filter(&mut self) -> Result<(), Error<I2C::Error>> {
291 let filter = [self.filter as u8];
292 let mut operations = [
293 Operation::Write(IIR_CNT_REGISTER),
294 Operation::Write(&filter),
295 ];
296 self.i2c.transaction(self.address, &mut operations)?;
297 self.delay.delay_ms(20);
298 Ok(())
299 }
300
301 fn apply_measure_control_parameters(&mut self) -> Result<(), Error<I2C::Error>> {
302 let (pressure_oversampling, temperature_oversampling) = self.get_oversamplings();
303 let data = [(temperature_oversampling as u8) << 5
304 | (pressure_oversampling as u8) << 2
305 | (PowerMode::Sleep as u8)];
306 let mut operations = [
307 Operation::Write(CTRL_MEAS_REGISTER),
308 Operation::Write(&data),
309 ];
310 self.i2c.transaction(self.address, &mut operations)?;
311 self.delay.delay_ms(20);
312 Ok(())
313 }
314
315 fn apply_power_mode(&mut self, power_mode: PowerMode) -> Result<(), Error<I2C::Error>> {
316 let mut data = [0u8; 1];
317 let mut operations = [
318 Operation::Write(CTRL_MEAS_REGISTER),
319 Operation::Read(&mut data),
320 ];
321 self.i2c.transaction(self.address, &mut operations)?;
322 data[0] = (data[0] & 0xfc) | power_mode as u8;
323 let mut operations = [
324 Operation::Write(CTRL_MEAS_REGISTER),
325 Operation::Write(&data),
326 ];
327 self.i2c.transaction(self.address, &mut operations)?;
328 self.delay.delay_ms(20);
329 Ok(())
330 }
331
332 fn check_device(&mut self) -> Result<(), Error<I2C::Error>> {
333 let mut chip_id = [0u8; 1];
334 let mut operations = [
335 Operation::Write(CHIP_ID_REGISTER),
336 Operation::Read(&mut chip_id),
337 ];
338 self.i2c.transaction(self.address, &mut operations)?;
339 if chip_id[0] == 0x5c {
340 Ok(())
341 } else {
342 Err(Error::ChipNotDetected)
343 }
344 }
345
346 fn compensate_pressure(&self, dp: i32, temperature: f32) -> f32 {
347 let dp = dp as f32;
348 self.k.b00
349 + self.k.bt1 * temperature
350 + self.k.bp1 * dp
351 + self.k.b11 * temperature * dp
352 + self.k.bt2 * temperature.powf(2.0)
353 + self.k.bp2 * dp.powf(2.0)
354 + self.k.b12 * dp * temperature.powf(2.0)
355 + self.k.b21 * dp.powf(2.0) * temperature
356 + self.k.bp3 * dp.powf(3.0)
357 }
358
359 fn compensate_temperature(&self, dt: i32) -> f32 {
360 let dt = dt as f32;
361 self.k.a0 + self.k.a1 * dt + self.k.a2 * dt.powf(2.0)
362 }
363
364 fn get_calibration_data(&mut self) -> Result<(), Error<I2C::Error>> {
365 let mut coe = [0u8; 25];
366 let mut operations = [
367 Operation::Write(COE_B00_1_REGISTER),
368 Operation::Read(&mut coe),
369 ];
370 self.i2c.transaction(self.address, &mut operations)?;
371 self.coe = (&coe).into();
372 self.k = (&self.coe).into();
373 Ok(())
374 }
375
376 fn get_measurement_duration(&self) -> u32 {
377 match self.oversampling_setting {
378 OverSamplingSetting::HighSpeed => 6,
379 OverSamplingSetting::LowPower => 8,
380 OverSamplingSetting::Standard => 11,
381 OverSamplingSetting::HighAccuracy => 19,
382 OverSamplingSetting::UltraHighAccuracy => 34,
383 }
384 }
385
386 fn get_oversamplings(&self) -> (OverSampling, OverSampling) {
387 match self.oversampling_setting {
388 OverSamplingSetting::HighSpeed => (OverSampling::X2, OverSampling::X1),
389 OverSamplingSetting::LowPower => (OverSampling::X4, OverSampling::X1),
390 OverSamplingSetting::Standard => (OverSampling::X8, OverSampling::X1),
391 OverSamplingSetting::HighAccuracy => (OverSampling::X16, OverSampling::X2),
392 OverSamplingSetting::UltraHighAccuracy => (OverSampling::X32, OverSampling::X4),
393 }
394 }
395
396 #[inline]
397 fn get_i32_value(data: &[u8; 3]) -> i32 {
398 ((data[0] as u32) << 16 | (data[1] as u32) << 8 | (data[2] as u32)) as i32
399 }
400}
401
402pub fn calculate_altitude(measurement: Measurement) -> f32 {
404 ((1_013.25 / measurement.pressure).powf(1.0 / 5.257) - 1.0) * (measurement.temperature + 273.15)
405 / 0.0065
406}
407
408#[cfg(test)]
409mod tests {
410 use crate::*;
411 use embedded_hal_mock::eh1::delay::StdSleep as Delay;
412 use embedded_hal_mock::eh1::i2c::{Mock as I2cMock, Transaction as I2cTransaction};
413
414 fn create_device() -> Qmp6988<I2cMock, Delay> {
415 let expectations = [
416 I2cTransaction::transaction_start(DEFAULT_I2C_ADDRESS),
417 I2cTransaction::write(DEFAULT_I2C_ADDRESS, CHIP_ID_REGISTER.to_vec()),
418 I2cTransaction::read(DEFAULT_I2C_ADDRESS, [0x5c].to_vec()),
419 I2cTransaction::transaction_end(DEFAULT_I2C_ADDRESS),
420 I2cTransaction::transaction_start(DEFAULT_I2C_ADDRESS),
421 I2cTransaction::write(DEFAULT_I2C_ADDRESS, COE_B00_1_REGISTER.to_vec()),
422 I2cTransaction::read(
423 DEFAULT_I2C_ADDRESS,
424 [
425 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
426 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
427 ]
428 .to_vec(),
429 ),
430 I2cTransaction::transaction_end(DEFAULT_I2C_ADDRESS),
431 I2cTransaction::transaction_start(DEFAULT_I2C_ADDRESS),
432 I2cTransaction::write(DEFAULT_I2C_ADDRESS, IIR_CNT_REGISTER.to_vec()),
433 I2cTransaction::write(DEFAULT_I2C_ADDRESS, [0x02].to_vec()),
434 I2cTransaction::transaction_end(DEFAULT_I2C_ADDRESS),
435 I2cTransaction::transaction_start(DEFAULT_I2C_ADDRESS),
436 I2cTransaction::write(DEFAULT_I2C_ADDRESS, CTRL_MEAS_REGISTER.to_vec()),
437 I2cTransaction::write(DEFAULT_I2C_ADDRESS, [0x30].to_vec()),
438 I2cTransaction::transaction_end(DEFAULT_I2C_ADDRESS),
439 ];
440 let i2c = I2cMock::new(&expectations);
441 let mut device = Qmp6988::new(i2c, DEFAULT_I2C_ADDRESS, Delay {}).unwrap();
442 device.i2c.done();
443 device
444 }
445
446 #[test]
447 fn calculate_altitude() {
448 assert!(
449 (crate::calculate_altitude(Measurement {
450 pressure: 991.32,
451 temperature: 20.55,
452 }) - 188.46)
453 .abs()
454 < 0.01
455 );
456 assert!(
457 (crate::calculate_altitude(Measurement {
458 pressure: 1013.25,
459 temperature: 17.93,
460 }) - 0.0)
461 .abs()
462 < 0.01
463 );
464 assert!(
465 (crate::calculate_altitude(Measurement {
466 pressure: 1013.25,
467 temperature: 37.5,
468 }) - 0.0)
469 .abs()
470 < 0.01
471 );
472 assert!(
473 (crate::calculate_altitude(Measurement {
474 pressure: 962.81,
475 temperature: 19.37,
476 }) - 439.25)
477 .abs()
478 < 0.01
479 );
480 }
481
482 #[test]
483 fn measure() {
484 let expectations = [
485 I2cTransaction::transaction_start(DEFAULT_I2C_ADDRESS),
486 I2cTransaction::write(DEFAULT_I2C_ADDRESS, CTRL_MEAS_REGISTER.to_vec()),
487 I2cTransaction::read(DEFAULT_I2C_ADDRESS, [0x30].to_vec()),
488 I2cTransaction::transaction_end(DEFAULT_I2C_ADDRESS),
489 I2cTransaction::transaction_start(DEFAULT_I2C_ADDRESS),
490 I2cTransaction::write(DEFAULT_I2C_ADDRESS, CTRL_MEAS_REGISTER.to_vec()),
491 I2cTransaction::write(DEFAULT_I2C_ADDRESS, [0x31].to_vec()),
492 I2cTransaction::transaction_end(DEFAULT_I2C_ADDRESS),
493 I2cTransaction::transaction_start(DEFAULT_I2C_ADDRESS),
494 I2cTransaction::write(DEFAULT_I2C_ADDRESS, PRESS_TXD2.to_vec()),
495 I2cTransaction::read(DEFAULT_I2C_ADDRESS, [0x00, 0x01, 0x02].to_vec()),
496 I2cTransaction::read(DEFAULT_I2C_ADDRESS, [0x00, 0x01, 0x02].to_vec()),
497 I2cTransaction::transaction_end(DEFAULT_I2C_ADDRESS),
498 ];
499 let mut device = create_device();
500 device.i2c.update_expectations(&expectations);
501 device.measure().unwrap();
502 device.i2c.done();
503 }
504
505 #[test]
506 fn reset() {
507 let expectations = [I2cTransaction::write(
508 DEFAULT_I2C_ADDRESS,
509 RESET_REGISTER.to_vec(),
510 )];
511 let mut device = create_device();
512 device.i2c.update_expectations(&expectations);
513 device.reset().unwrap();
514 device.i2c.done();
515 }
516
517 #[test]
518 fn set_filter() {
519 let expectations = [
520 I2cTransaction::transaction_start(DEFAULT_I2C_ADDRESS),
521 I2cTransaction::write(DEFAULT_I2C_ADDRESS, IIR_CNT_REGISTER.to_vec()),
522 I2cTransaction::write(DEFAULT_I2C_ADDRESS, [0x05].to_vec()),
523 I2cTransaction::transaction_end(DEFAULT_I2C_ADDRESS),
524 ];
525 let mut device = create_device();
526 device.i2c.update_expectations(&expectations);
527 device.set_filter(IirFilter::Coeff32).unwrap();
528 device.i2c.done();
529 }
530
531 #[test]
532 fn set_oversampling_setting() {
533 let expectations = [
534 I2cTransaction::transaction_start(DEFAULT_I2C_ADDRESS),
535 I2cTransaction::write(DEFAULT_I2C_ADDRESS, CTRL_MEAS_REGISTER.to_vec()),
536 I2cTransaction::write(DEFAULT_I2C_ADDRESS, [0x28].to_vec()),
537 I2cTransaction::transaction_end(DEFAULT_I2C_ADDRESS),
538 ];
539 let mut device = create_device();
540 device.i2c.update_expectations(&expectations);
541 device
542 .set_oversampling_setting(OverSamplingSetting::HighSpeed)
543 .unwrap();
544 device.i2c.done();
545 }
546}