1use core::marker::PhantomData;
10use embedded_hal::blocking::delay::DelayMs;
11use embedded_hal::blocking::i2c::{Read, Write, WriteRead};
12
13#[cfg(feature = "serde")]
14use serde::Serialize;
15
16const BME280_I2C_ADDR_PRIMARY: u8 = 0x76;
17const BME280_I2C_ADDR_SECONDARY: u8 = 0x77;
18
19const BME280_PWR_CTRL_ADDR: u8 = 0xF4;
20const BME280_CTRL_HUM_ADDR: u8 = 0xF2;
21const BME280_CTRL_MEAS_ADDR: u8 = 0xF4;
22const BME280_CONFIG_ADDR: u8 = 0xF5;
23
24const BME280_RESET_ADDR: u8 = 0xE0;
25const BME280_SOFT_RESET_CMD: u8 = 0xB6;
26
27const BME280_CHIP_ID: u8 = 0x60;
28const BMP280_CHIP_ID: u8 = 0x58;
29const BME280_CHIP_ID_ADDR: u8 = 0xD0;
30
31const BME280_DATA_ADDR: u8 = 0xF7;
32const BME280_P_T_H_DATA_LEN: usize = 8;
33
34const BME280_P_T_CALIB_DATA_ADDR: u8 = 0x88;
35const BME280_P_T_CALIB_DATA_LEN: usize = 26;
36
37const BME280_H_CALIB_DATA_ADDR: u8 = 0xE1;
38const BME280_H_CALIB_DATA_LEN: usize = 7;
39
40const BME280_TEMP_MIN: f32 = -40.0;
41const BME280_TEMP_MAX: f32 = 85.0;
42
43const BME280_PRESSURE_MIN: f32 = 30000.0;
44const BME280_PRESSURE_MAX: f32 = 110000.0;
45
46const BME280_HUMIDITY_MIN: f32 = 0.0;
47const BME280_HUMIDITY_MAX: f32 = 100.0;
48
49const BME280_SLEEP_MODE: u8 = 0x00;
50const BME280_FORCED_MODE: u8 = 0x01;
51const BME280_NORMAL_MODE: u8 = 0x03;
52
53const BME280_SENSOR_MODE_MSK: u8 = 0x03;
54
55const BME280_CTRL_HUM_MSK: u8 = 0x07;
56
57const BME280_CTRL_PRESS_MSK: u8 = 0x1C;
58const BME280_CTRL_PRESS_POS: u8 = 0x02;
59
60const BME280_CTRL_TEMP_MSK: u8 = 0xE0;
61const BME280_CTRL_TEMP_POS: u8 = 0x05;
62
63const BME280_FILTER_MSK: u8 = 0x1C;
64const BME280_FILTER_POS: u8 = 0x02;
65const BME280_FILTER_COEFF_16: u8 = 0x04;
66
67const BME280_OVERSAMPLING_1X: u8 = 0x01;
68const BME280_OVERSAMPLING_2X: u8 = 0x02;
69const BME280_OVERSAMPLING_16X: u8 = 0x05;
70
71macro_rules! concat_bytes {
72 ($msb:expr, $lsb:expr) => {
73 (($msb as u16) << 8) | ($lsb as u16)
74 };
75}
76
77macro_rules! set_bits {
78 ($reg_data:expr, $mask:expr, $pos:expr, $data:expr) => {
79 ($reg_data & !$mask) | (($data << $pos) & $mask)
80 };
81}
82
83#[derive(Debug)]
85pub enum Error<E> {
86 CompensationFailed,
88 I2c(E),
90 InvalidData,
92 NoCalibrationData,
94 UnsupportedChip,
96}
97
98#[derive(Debug, Copy, Clone)]
100pub enum SensorMode {
101 Sleep,
103 Forced,
105 Normal,
107}
108
109#[derive(Debug)]
110struct CalibrationData {
111 dig_t1: u16,
112 dig_t2: i16,
113 dig_t3: i16,
114 dig_p1: u16,
115 dig_p2: i16,
116 dig_p3: i16,
117 dig_p4: i16,
118 dig_p5: i16,
119 dig_p6: i16,
120 dig_p7: i16,
121 dig_p8: i16,
122 dig_p9: i16,
123 dig_h1: u8,
124 dig_h2: i16,
125 dig_h3: u8,
126 dig_h4: i16,
127 dig_h5: i16,
128 dig_h6: i8,
129 t_fine: i32,
130}
131
132#[cfg_attr(feature = "serde", derive(Serialize))]
134#[cfg_attr(feature = "defmt", derive(defmt::Format))]
135pub struct Measurements {
136 pub temperature: f32,
138 pub pressure: f32,
140 pub humidity: f32,
142}
143
144impl Measurements {
145 fn parse<E>(
146 data: [u8; BME280_P_T_H_DATA_LEN],
147 calibration: &mut CalibrationData,
148 ) -> Result<Self, Error<E>> {
149 let data_msb: u32 = (data[0] as u32) << 12;
150 let data_lsb: u32 = (data[1] as u32) << 4;
151 let data_xlsb: u32 = (data[2] as u32) >> 4;
152 let pressure = data_msb | data_lsb | data_xlsb;
153
154 let data_msb: u32 = (data[3] as u32) << 12;
155 let data_lsb: u32 = (data[4] as u32) << 4;
156 let data_xlsb: u32 = (data[5] as u32) >> 4;
157 let temperature = data_msb | data_lsb | data_xlsb;
158
159 let data_msb: u32 = (data[6] as u32) << 8;
160 let data_lsb: u32 = data[7] as u32;
161 let humidity = data_msb | data_lsb;
162
163 let temperature = Measurements::compensate_temperature(temperature, calibration)?;
164 let pressure = Measurements::compensate_pressure(pressure, calibration)?;
165 let humidity = Measurements::compensate_humidity(humidity, calibration)?;
166
167 Ok(Measurements {
168 temperature,
169 pressure,
170 humidity,
171 })
172 }
173
174 fn compensate_temperature<E>(
175 uncompensated: u32,
176 calibration: &mut CalibrationData,
177 ) -> Result<f32, Error<E>> {
178 let var1: f32 = uncompensated as f32 / 16384.0 - calibration.dig_t1 as f32 / 1024.0;
179 let var1 = var1 * calibration.dig_t2 as f32;
180 let var2 = uncompensated as f32 / 131072.0 - calibration.dig_t1 as f32 / 8192.0;
181 let var2 = var2 * var2 * calibration.dig_t3 as f32;
182
183 calibration.t_fine = (var1 + var2) as i32;
184
185 let temperature = (var1 + var2) / 5120.0;
186 let temperature = if temperature < BME280_TEMP_MIN {
187 BME280_TEMP_MIN
188 } else if temperature > BME280_TEMP_MAX {
189 BME280_TEMP_MAX
190 } else {
191 temperature
192 };
193 Ok(temperature)
194 }
195
196 fn compensate_pressure<E>(
197 uncompensated: u32,
198 calibration: &mut CalibrationData,
199 ) -> Result<f32, Error<E>> {
200 let var1: f32 = calibration.t_fine as f32 / 2.0 - 64000.0;
201 let var2: f32 = var1 * var1 * calibration.dig_p6 as f32 / 32768.0;
202 let var2: f32 = var2 + var1 * calibration.dig_p5 as f32 * 2.0;
203 let var2: f32 = var2 / 4.0 + calibration.dig_p4 as f32 * 65536.0;
204 let var3: f32 = calibration.dig_p3 as f32 * var1 * var1 / 524288.0;
205 let var1: f32 = (var3 + calibration.dig_p2 as f32 * var1) / 524288.0;
206 let var1: f32 = (1.0 + var1 / 32768.0) * calibration.dig_p1 as f32;
207
208 let pressure = if var1 > 0.0 {
209 let pressure: f32 = 1048576.0 - uncompensated as f32;
210 let pressure: f32 = (pressure - (var2 / 4096.0)) * 6250.0 / var1;
211 let var1: f32 = calibration.dig_p9 as f32 * pressure * pressure / 2147483648.0;
212 let var2: f32 = pressure * calibration.dig_p8 as f32 / 32768.0;
213 let pressure: f32 = pressure + (var1 + var2 + calibration.dig_p7 as f32) / 16.0;
214 if pressure < BME280_PRESSURE_MIN {
215 BME280_PRESSURE_MIN
216 } else if pressure > BME280_PRESSURE_MAX {
217 BME280_PRESSURE_MAX
218 } else {
219 pressure
220 }
221 } else {
222 return Err(Error::InvalidData);
223 };
224 Ok(pressure)
225 }
226
227 fn compensate_humidity<E>(
228 uncompensated: u32,
229 calibration: &mut CalibrationData,
230 ) -> Result<f32, Error<E>> {
231 let var1: f32 = calibration.t_fine as f32 - 76800.0;
232 let var2: f32 =
233 calibration.dig_h4 as f32 * 64.0 + (calibration.dig_h5 as f32 / 16384.0) * var1;
234 let var3: f32 = uncompensated as f32 - var2;
235 let var4: f32 = calibration.dig_h2 as f32 / 65536.0;
236 let var5: f32 = 1.0 + (calibration.dig_h3 as f32 / 67108864.0) * var1;
237 let var6: f32 = 1.0 + (calibration.dig_h6 as f32 / 67108864.0) * var1 * var5;
238 let var6: f32 = var3 * var4 * (var5 * var6);
239
240 let humidity: f32 = var6 * (1.0 - calibration.dig_h1 as f32 * var6 / 524288.0);
241 let humidity = if humidity < BME280_HUMIDITY_MIN {
242 BME280_HUMIDITY_MIN
243 } else if humidity > BME280_HUMIDITY_MAX {
244 BME280_HUMIDITY_MAX
245 } else {
246 humidity
247 };
248 Ok(humidity)
249 }
250}
251
252#[derive(Debug, Default)]
254pub struct BME280<I2C> {
255 i2c: I2C,
257 address: u8,
259 calibration: Option<CalibrationData>,
261}
262
263impl<I2C, E> BME280<I2C>
264where
265 I2C: Read<Error = E> + Write<Error = E> + WriteRead<Error = E>,
266{
267 pub fn new_primary(i2c: I2C) -> Self {
269 Self::new(i2c, BME280_I2C_ADDR_PRIMARY)
270 }
271
272 pub fn new_secondary(i2c: I2C) -> Self {
274 Self::new(i2c, BME280_I2C_ADDR_SECONDARY)
275 }
276
277 pub fn new(i2c: I2C, address: u8) -> Self {
279 BME280 {
280 i2c,
281 address,
282 calibration: None,
283 }
284 }
285
286 pub fn init<D: DelayMs<u8>>(&mut self, delay: &mut D) -> Result<(), Error<E>> {
288 self.verify_chip_id()?;
289 self.soft_reset(delay)?;
290 self.calibrate()?;
291 self.configure(delay)
292 }
293
294 pub fn release(self) -> I2C {
295 self.i2c
296 }
297
298 fn verify_chip_id(&mut self) -> Result<(), Error<E>> {
299 let chip_id = self.read_register(BME280_CHIP_ID_ADDR)?;
300 if chip_id == BME280_CHIP_ID || chip_id == BMP280_CHIP_ID {
301 Ok(())
302 } else {
303 Err(Error::UnsupportedChip)
304 }
305 }
306
307 fn soft_reset<D: DelayMs<u8>>(&mut self, delay: &mut D) -> Result<(), Error<E>> {
308 self.write_register(BME280_RESET_ADDR, BME280_SOFT_RESET_CMD)?;
309 delay.delay_ms(2); Ok(())
311 }
312
313 fn calibrate(&mut self) -> Result<(), Error<E>> {
314 let pt_calib_data = self.read_pt_calib_data(BME280_P_T_CALIB_DATA_ADDR)?;
315 let h_calib_data = self.read_h_calib_data(BME280_H_CALIB_DATA_ADDR)?;
316 self.calibration = Some(parse_calib_data(&pt_calib_data, &h_calib_data));
317 Ok(())
318 }
319
320 fn configure<D: DelayMs<u8>>(&mut self, delay: &mut D) -> Result<(), Error<E>> {
321 match self.mode()? {
322 SensorMode::Sleep => {}
323 _ => self.soft_reset(delay)?,
324 };
325
326 self.write_register(
327 BME280_CTRL_HUM_ADDR,
328 BME280_OVERSAMPLING_1X & BME280_CTRL_HUM_MSK,
329 )?;
330 let ctrl_meas = self.read_register(BME280_CTRL_MEAS_ADDR)?;
331 self.write_register(BME280_CTRL_MEAS_ADDR, ctrl_meas)?;
332
333 let data = self.read_register(BME280_CTRL_MEAS_ADDR)?;
334 let data = set_bits!(
335 data,
336 BME280_CTRL_PRESS_MSK,
337 BME280_CTRL_PRESS_POS,
338 BME280_OVERSAMPLING_16X
339 );
340 let data = set_bits!(
341 data,
342 BME280_CTRL_TEMP_MSK,
343 BME280_CTRL_TEMP_POS,
344 BME280_OVERSAMPLING_2X
345 );
346 self.write_register(BME280_CTRL_MEAS_ADDR, data)?;
347
348 let data = self.read_register(BME280_CONFIG_ADDR)?;
349 let data = set_bits!(
350 data,
351 BME280_FILTER_MSK,
352 BME280_FILTER_POS,
353 BME280_FILTER_COEFF_16
354 );
355 self.write_register(BME280_CONFIG_ADDR, data)
356 }
357
358 fn mode(&mut self) -> Result<SensorMode, Error<E>> {
359 let mut data: [u8; 1] = [0];
360 self.i2c
361 .write_read(self.address, &[BME280_PWR_CTRL_ADDR], &mut data)
362 .map_err(Error::I2c)?;
363 match data[0] & BME280_SENSOR_MODE_MSK {
364 BME280_SLEEP_MODE => Ok(SensorMode::Sleep),
365 BME280_FORCED_MODE => Ok(SensorMode::Forced),
366 BME280_NORMAL_MODE => Ok(SensorMode::Normal),
367 _ => Err(Error::InvalidData),
368 }
369 }
370
371 fn forced<D: DelayMs<u8>>(&mut self, delay: &mut D) -> Result<(), Error<E>> {
372 self.set_mode(BME280_FORCED_MODE, delay)
373 }
374
375 fn set_mode<D: DelayMs<u8>>(&mut self, mode: u8, delay: &mut D) -> Result<(), Error<E>> {
376 match self.mode()? {
377 SensorMode::Sleep => {}
378 _ => self.soft_reset(delay)?,
379 };
380 let data = self.read_register(BME280_PWR_CTRL_ADDR)?;
381 let data = set_bits!(data, BME280_SENSOR_MODE_MSK, 0, mode);
382 self.write_register(BME280_PWR_CTRL_ADDR, data)
383 }
384
385 pub fn measure<D: DelayMs<u8>>(&mut self, delay: &mut D) -> Result<Measurements, Error<E>> {
387 self.forced(delay)?;
388 delay.delay_ms(40); let measurements = self.read_data(BME280_DATA_ADDR)?;
390 match self.calibration.as_mut() {
391 Some(calibration) => {
392 let measurements = Measurements::parse(measurements, &mut *calibration)?;
393 Ok(measurements)
394 }
395 None => Err(Error::NoCalibrationData),
396 }
397 }
398
399 fn read_register(&mut self, register: u8) -> Result<u8, Error<E>> {
400 let mut data: [u8; 1] = [0];
401 self.i2c
402 .write_read(self.address, &[register], &mut data)
403 .map_err(Error::I2c)?;
404 Ok(data[0])
405 }
406
407 fn read_data(&mut self, register: u8) -> Result<[u8; BME280_P_T_H_DATA_LEN], Error<E>> {
408 let mut data: [u8; BME280_P_T_H_DATA_LEN] = [0; BME280_P_T_H_DATA_LEN];
409 self.i2c
410 .write_read(self.address, &[register], &mut data)
411 .map_err(Error::I2c)?;
412 Ok(data)
413 }
414
415 fn read_pt_calib_data(
416 &mut self,
417 register: u8,
418 ) -> Result<[u8; BME280_P_T_CALIB_DATA_LEN], Error<E>> {
419 let mut data: [u8; BME280_P_T_CALIB_DATA_LEN] = [0; BME280_P_T_CALIB_DATA_LEN];
420 self.i2c
421 .write_read(self.address, &[register], &mut data)
422 .map_err(Error::I2c)?;
423 Ok(data)
424 }
425
426 fn read_h_calib_data(
427 &mut self,
428 register: u8,
429 ) -> Result<[u8; BME280_H_CALIB_DATA_LEN], Error<E>> {
430 let mut data: [u8; BME280_H_CALIB_DATA_LEN] = [0; BME280_H_CALIB_DATA_LEN];
431 self.i2c
432 .write_read(self.address, &[register], &mut data)
433 .map_err(Error::I2c)?;
434 Ok(data)
435 }
436
437 fn write_register(&mut self, register: u8, payload: u8) -> Result<(), Error<E>> {
438 self.i2c
439 .write(self.address, &[register, payload])
440 .map_err(Error::I2c)
441 }
442}
443
444fn parse_calib_data(
445 pt_data: &[u8; BME280_P_T_CALIB_DATA_LEN],
446 h_data: &[u8; BME280_H_CALIB_DATA_LEN],
447) -> CalibrationData {
448 let dig_t1 = concat_bytes!(pt_data[1], pt_data[0]);
449 let dig_t2 = concat_bytes!(pt_data[3], pt_data[2]) as i16;
450 let dig_t3 = concat_bytes!(pt_data[5], pt_data[4]) as i16;
451 let dig_p1 = concat_bytes!(pt_data[7], pt_data[6]);
452 let dig_p2 = concat_bytes!(pt_data[9], pt_data[8]) as i16;
453 let dig_p3 = concat_bytes!(pt_data[11], pt_data[10]) as i16;
454 let dig_p4 = concat_bytes!(pt_data[13], pt_data[12]) as i16;
455 let dig_p5 = concat_bytes!(pt_data[15], pt_data[14]) as i16;
456 let dig_p6 = concat_bytes!(pt_data[17], pt_data[16]) as i16;
457 let dig_p7 = concat_bytes!(pt_data[19], pt_data[18]) as i16;
458 let dig_p8 = concat_bytes!(pt_data[21], pt_data[20]) as i16;
459 let dig_p9 = concat_bytes!(pt_data[23], pt_data[22]) as i16;
460 let dig_h1 = pt_data[25];
461 let dig_h2 = concat_bytes!(h_data[1], h_data[0]) as i16;
462 let dig_h3 = h_data[2];
463 let dig_h4 = (h_data[3] as i16 * 16) | ((h_data[4] as i16) & 0x0F);
464 let dig_h5 = (h_data[5] as i16 * 16) | ((h_data[4] as i16) >> 4);
465 let dig_h6 = h_data[6] as i8;
466
467 CalibrationData {
468 dig_t1,
469 dig_t2,
470 dig_t3,
471 dig_p1,
472 dig_p2,
473 dig_p3,
474 dig_p4,
475 dig_p5,
476 dig_p6,
477 dig_p7,
478 dig_p8,
479 dig_p9,
480 dig_h1,
481 dig_h2,
482 dig_h3,
483 dig_h4,
484 dig_h5,
485 dig_h6,
486 t_fine: 0,
487 }
488}