1#![no_main]
2#![no_std]
3
4mod calc;
17
18use core::marker::PhantomData;
19use embedded_hal::{self, delay::DelayNs, i2c};
20
21mod calib_mem {
23 pub const ADDR: [u8; 2] = [0x89, 0xE1];
24 pub const SIZES: [usize; 2] = [25, 16];
25 pub const TOTAL_SIZE: usize = 25 + 16;
26}
27
28mod raw_data_mem {
30 pub const ADDR: u8 = 0x1F;
31 pub const SIZE: usize = 12;
32}
33
34pub struct Idle;
37pub struct Uninitialized;
39pub struct Ready;
41
42pub mod error {
44 #[derive(Debug, Clone, Copy)]
46 pub enum Bme680Error<E> {
47 I2CError(E),
49 InvalidWaitTime,
51 InvalidProfileIndex,
53 Timeout,
55 HeaterNotStable,
57 GasDataNotReady,
59 }
60
61 pub type Result<T, E> = core::result::Result<T, Bme680Error<E>>;
63}
64
65#[derive(Debug, Clone, Copy)]
69#[repr(u8)]
70pub enum Oversampling {
71 Skipped = 0,
73 X1 = 1,
75 X2 = 2,
77 X4 = 3,
79 X8 = 4,
81 X16 = 5,
83}
84
85#[derive(Debug, Clone, Copy)]
89#[repr(u8)]
90pub enum IIRFilter {
91 IIR0 = 0,
92 IIR1 = 1,
93 IIR3 = 2,
94 IIR7 = 3,
95 IIR15 = 4,
96 IIR31 = 5,
97 IIR63 = 6,
98 IIR127 = 7,
99}
100
101#[derive(Debug, Clone, Copy)]
103#[repr(u8)]
104pub enum GasProfileIndex {
105 Profile0 = 0,
106 Profile1 = 1,
107 Profile2 = 2,
108 Profile3 = 3,
109 Profile4 = 4,
110 Profile5 = 5,
111 Profile6 = 6,
112 Profile7 = 7,
113 Profile8 = 8,
114 Profile9 = 9,
115}
116
117#[derive(Clone, Copy)]
120pub struct Celsius(pub i32);
121
122#[derive(Debug, Clone, Copy)]
124pub struct Milliseconds(pub u32);
125
126#[derive(Clone, Copy)]
128pub struct GasProfile {
129 pub index: GasProfileIndex,
131 pub target_temp: Celsius,
133 pub wait_time: Milliseconds,
135}
136
137pub struct OversamplingConfig {
139 pub temp_osrs: Oversampling,
140 pub hum_osrs: Oversampling,
141 pub pres_osrs: Oversampling,
142}
143
144pub struct Config {
146 pub osrs_config: OversamplingConfig,
147 pub iir_filter: IIRFilter,
148 pub gas_profile: GasProfile,
149 pub ambient_temp: Celsius,
151}
152
153#[derive(Debug, Default, Copy, Clone)]
156pub struct CalibData {
157 pub par_h1: u16,
158 pub par_h2: u16,
159 pub par_h3: i8,
160 pub par_h4: i8,
161 pub par_h5: i8,
162 pub par_h6: u8,
163 pub par_h7: i8,
164 pub par_g1: i8,
165 pub par_g2: i16,
166 pub par_g3: i8,
167 pub par_t1: u16,
168 pub par_t2: i16,
169 pub par_t3: i8,
170 pub par_p1: u16,
171 pub par_p2: i16,
172 pub par_p3: i8,
173 pub par_p4: i16,
174 pub par_p5: i16,
175 pub par_p6: i8,
176 pub par_p7: i8,
177 pub par_p8: i16,
178 pub par_p9: i16,
179 pub par_p10: u8,
180 pub res_heat_range: u8,
181 pub res_heat_val: u8,
182 pub range_sw_err: i8,
183}
184
185#[derive(Debug, Copy, Clone)]
187pub struct RawData {
188 pub(crate) temp_adc: u32,
189 pub(crate) hum_adc: u16,
190 pub(crate) press_adc: u32,
191 pub(crate) gas_adc: u16,
192 pub(crate) gas_range: u8,
193 pub(crate) gas_valid_r: bool,
194 pub(crate) heat_stab_r: bool,
195}
196
197#[derive(Debug, Copy, Clone)]
199pub struct CalcTempData {
200 pub(crate) temp_fine: i32,
201 pub(crate) temp_comp: i32,
202}
203
204#[derive(Debug, Copy, Clone)]
211pub struct Temperature(pub i32);
212
213impl Temperature {
214 pub fn split(&self) -> (i32, i32) {
225 (self.0 / 100, self.0 % 100)
226 }
227}
228
229#[derive(Debug, Copy, Clone)]
234pub struct Humidity(pub i32);
235
236impl Humidity {
237 pub fn split(&self) -> (i32, i32) {
248 (self.0 / 1000, self.0 % 1000)
249 }
250}
251
252#[derive(Debug, Copy, Clone)]
257pub struct Pressure(pub u32);
258
259impl Pressure {
260 pub fn as_hpa(&self) -> (u32, u32) {
273 (self.0 / 100, self.0 % 100)
274 }
275}
276
277#[derive(Debug, Copy, Clone)]
279pub struct Gas(pub u32);
280
281#[derive(Debug, Copy, Clone)]
285pub struct Measurement {
286 pub temp: Temperature,
288 pub hum: Humidity,
290 pub pres: Pressure,
292 pub gas: Gas,
294}
295
296#[derive(Debug, Copy, Clone)]
300pub struct Bme680<I2C, STATE> {
301 i2c: I2C,
302 address: u8,
303 pub(crate) calib_data: CalibData,
304 current_wait_time: Milliseconds,
305 _state: PhantomData<STATE>,
306}
307
308impl<I2C, E> Bme680<I2C, Idle>
309where
310 I2C: i2c::I2c<Error = E>,
311{
312 pub fn new(i2c: I2C, address: u8) -> Bme680<I2C, Uninitialized> {
314 Bme680 {
315 i2c,
316 address,
317 calib_data: CalibData::default(),
318 current_wait_time: Milliseconds(0),
319 _state: PhantomData,
320 }
321 }
322}
323impl<I2C, STATE, E> Bme680<I2C, STATE>
324where
325 I2C: i2c::I2c<Error = E>,
326{
327 fn reset(&mut self, delay: &mut impl DelayNs) -> error::Result<(), E> {
332 self.i2c
333 .write(self.address, &[0xE0, 0xB6])
334 .map_err(|e| error::Bme680Error::I2CError(e))?;
335
336 delay.delay_ms(2);
337
338 Ok(())
339 }
340
341 fn read_into(&mut self, reg_address: u8, buffer: &mut [u8]) -> error::Result<(), E> {
343 self.i2c
344 .write_read(self.address, &[reg_address], buffer)
345 .map_err(|e| error::Bme680Error::I2CError(e))
346 }
347
348 fn read_reg_byte(&mut self, reg_address: u8) -> error::Result<u8, E> {
350 let mut buffer = [0];
351
352 self.i2c
353 .write_read(self.address, &[reg_address], &mut buffer)
354 .map_err(|e| error::Bme680Error::I2CError(e))?;
355
356 Ok(buffer[0])
357 }
358
359 fn write_reg(&mut self, data: &[u8]) -> error::Result<(), E> {
361 self.i2c
362 .write(self.address, data)
363 .map_err(|e| error::Bme680Error::I2CError(e))?;
364 Ok(())
365 }
366}
367
368impl<I2C, E> Bme680<I2C, Uninitialized>
369where
370 I2C: i2c::I2c<Error = E>,
371{
372 pub fn init(mut self, delay: &mut impl DelayNs) -> error::Result<Bme680<I2C, Ready>, E> {
376 delay.delay_ms(2);
377
378 self.reset(delay)?;
379
380 let calib_data = self.get_calib_data()?;
381
382 Ok(Bme680 {
383 i2c: self.i2c,
384 address: self.address,
385 calib_data: calib_data,
386 current_wait_time: Milliseconds(0),
387 _state: PhantomData,
388 })
389 }
390
391 fn get_calib_data(&mut self) -> error::Result<CalibData, E> {
393 let mut calib_data = CalibData::default();
394 let mut buffer = [0u8; calib_mem::TOTAL_SIZE];
395
396 self.read_into(calib_mem::ADDR[0], &mut buffer[0..calib_mem::SIZES[0]])?;
398 self.read_into(calib_mem::ADDR[1], &mut buffer[calib_mem::SIZES[0]..])?;
399
400 calib_data.par_t1 = ((buffer[33] as i32) | ((buffer[34] as i32) << 8)) as u16;
402 calib_data.par_t2 = ((buffer[1] as i32) | ((buffer[2] as i32) << 8)) as i16;
403 calib_data.par_t3 = buffer[3] as i8;
404 calib_data.par_p1 = ((buffer[5] as i32) | ((buffer[6] as i32) << 8)) as u16;
405 calib_data.par_p2 = ((buffer[7] as i32) | ((buffer[8] as i32) << 8)) as i16;
406 calib_data.par_p3 = buffer[9] as i8;
407 calib_data.par_p4 = ((buffer[11] as i32) | ((buffer[12] as i32) << 8)) as i16;
408 calib_data.par_p5 = ((buffer[14] as i32) | ((buffer[13] as i32) << 8)) as i16;
409 calib_data.par_p6 = buffer[16] as i8;
410 calib_data.par_p7 = buffer[15] as i8;
411 calib_data.par_p8 = ((buffer[19] as i32) | ((buffer[20] as i32) << 8)) as i16;
412 calib_data.par_p9 = ((buffer[21] as i32) | ((buffer[22] as i32) << 8)) as i16;
413 calib_data.par_p10 = buffer[23];
414 calib_data.par_h1 = (((buffer[26] & 0x0F) as i32) | ((buffer[27] as i32) << 4)) as u16;
415 calib_data.par_h2 = (((buffer[26] >> 4) as i32) | ((buffer[25] as i32) << 4)) as u16;
416 calib_data.par_h3 = buffer[28] as i8;
417 calib_data.par_h4 = buffer[29] as i8;
418 calib_data.par_h5 = buffer[30] as i8;
419 calib_data.par_h6 = buffer[31];
420 calib_data.par_h7 = buffer[32] as i8;
421 calib_data.par_g1 = buffer[37] as i8;
422 calib_data.par_g2 = ((buffer[35] as i32) | ((buffer[36] as i32) << 8)) as i16;
423 calib_data.par_g3 = buffer[38] as i8;
424
425 calib_data.res_heat_val = self.read_reg_byte(0x00)?;
427 calib_data.res_heat_range = (self.read_reg_byte(0x02)? >> 4) & 0x03;
428 calib_data.range_sw_err = (self.read_reg_byte(0x04)? as i8) >> 4;
429
430 Ok(calib_data)
431 }
432}
433
434impl<I2C, E> Bme680<I2C, Ready>
435where
436 I2C: i2c::I2c<Error = E>,
437{
438 pub fn configure_sensor(&mut self, config: &mut Config) -> error::Result<(), E> {
440 self.config_oversampling(&config.osrs_config)?;
441 self.config_iir_filter(config.iir_filter)?;
442 self.enable_gas_measurement()?;
443 self.select_gas_profile(&config.gas_profile)?;
444 self.set_gas_heater_profile(config.gas_profile, config.ambient_temp)?;
445
446 Ok(())
447 }
448
449 pub fn set_gas_heater_profile(
451 &mut self,
452 config: GasProfile,
453 amb_temp: Celsius,
454 ) -> error::Result<(), E> {
455 self.config_heater_on_time(config.wait_time, config.index)?;
456 self.config_target_resistance(config.target_temp, amb_temp, config.index)?;
457
458 Ok(())
459 }
460
461 pub fn read_new_data(&mut self, delay: &mut impl DelayNs) -> error::Result<Measurement, E> {
463 self.activate_forced_mode()?;
464
465 delay.delay_ms(self.current_wait_time.0);
467
468 let raw_data = self.get_raw_data(delay)?;
469
470 let temp = self.calc_temp(raw_data.temp_adc);
472 let hum = self.calc_hum(temp.temp_comp, raw_data.hum_adc);
473 let pres = self.calc_pres(temp.temp_fine, raw_data.press_adc);
474
475 if !raw_data.gas_valid_r {
476 return Err(error::Bme680Error::GasDataNotReady);
477 } else if !raw_data.heat_stab_r {
478 return Err(error::Bme680Error::HeaterNotStable);
479 }
480
481 let gas = self.calc_gas(raw_data.gas_adc, raw_data.gas_range);
482
483 Ok(Measurement {
484 temp: Temperature(temp.temp_comp),
485 hum: Humidity(hum),
486 pres: Pressure(pres),
487 gas: Gas(gas),
488 })
489 }
490
491 pub fn read_chip_id(&mut self) -> error::Result<u8, E> {
493 Ok(self.read_reg_byte(0xD0)?)
494 }
495
496 fn get_raw_data(&mut self, delay: &mut impl DelayNs) -> error::Result<RawData, E> {
498 let mut new_data = false;
499 let mut timeout_us = 5000; while !new_data {
502 if timeout_us <= 0 {
503 return Err(error::Bme680Error::Timeout);
504 }
505 new_data = (self.read_reg_byte(0x1D)? >> 7) != 0;
507
508 delay.delay_us(500);
509 timeout_us -= 500;
510 }
511
512 let mut buffer = [0u8; raw_data_mem::SIZE + 1];
513
514 self.i2c
515 .write_read(self.address, &[raw_data_mem::ADDR], &mut buffer)
516 .map_err(|e| error::Bme680Error::I2CError(e))?;
517
518 let press_adc =
520 ((buffer[2] as u32) >> 4) | ((buffer[1] as u32) << 4) | ((buffer[0] as u32) << 12);
521 let temp_adc =
522 ((buffer[5] as u32) >> 4) | ((buffer[4] as u32) << 4) | ((buffer[3] as u32) << 12);
523 let hum_adc = ((buffer[7] as u32) | ((buffer[6] as u32) << 8)) as u16;
524 let gas_adc = (((buffer[12] as u32) >> 6) | ((buffer[11] as u32) << 2)) as u16;
525 let gas_range = buffer[12] & 0x0F;
526
527 let gas_valid_r = ((buffer[12] >> 5) & 0x1) != 0;
528 let heat_stab_r = ((buffer[12] >> 4) & 0x1) != 0;
529
530 Ok(RawData {
531 temp_adc,
532 hum_adc,
533 press_adc,
534 gas_adc,
535 gas_range,
536 gas_valid_r,
537 heat_stab_r,
538 })
539 }
540
541 fn config_oversampling(&mut self, osrs_config: &OversamplingConfig) -> error::Result<(), E> {
543 let register = self.read_reg_byte(0x72)?;
545 let mut new_reg_val = (register & 0xF8) | osrs_config.hum_osrs as u8;
546 self.write_reg(&[0x72, new_reg_val])?;
547
548 let register = self.read_reg_byte(0x74)?;
550 let temp_pres_combined =
551 ((osrs_config.temp_osrs as u8) << 0x5) | ((osrs_config.pres_osrs as u8) << 0x2);
552 new_reg_val = (register & 0x03) | temp_pres_combined;
553 self.write_reg(&[0x74, new_reg_val])?;
554
555 Ok(())
556 }
557
558 fn config_iir_filter(&mut self, iir_filter: IIRFilter) -> error::Result<(), E> {
560 let register = self.read_reg_byte(0x75)?;
561 let new_reg_val = (register & 0xE3) | ((iir_filter as u8) << 0x2);
562 self.write_reg(&[0x75, new_reg_val])?;
563 Ok(())
564 }
565
566 fn enable_gas_measurement(&mut self) -> error::Result<(), E> {
568 let register = self.read_reg_byte(0x71)?;
569 self.write_reg(&[0x71, (register & 0xEF) | (0b1 << 0x4)])?;
570 Ok(())
571 }
572
573 pub fn select_gas_profile(&mut self, profile: &GasProfile) -> error::Result<(), E> {
575 self.current_wait_time = profile.wait_time;
576 let register = self.read_reg_byte(0x71)?;
577 self.write_reg(&[0x71, (register & 0xF0) | (profile.index as u8)])?;
578 Ok(())
579 }
580
581 fn activate_forced_mode(&mut self) -> error::Result<(), E> {
583 let register = self.read_reg_byte(0x74)?;
584 self.write_reg(&[0x74, (register & 0xFC) | 0b01])?;
585 Ok(())
586 }
587}