bmp280_driver/
lib.rs

1//! A platform agnostic driver to interface with the BMP280 (pressure sensor)
2//!
3//! This driver is built using [`embedded-hal`] traits.
4
5#![deny(missing_docs)]
6#![deny(warnings)]
7#![no_std]
8
9extern crate embedded_hal as ehal;
10
11use core::fmt;
12
13/// The default address for the BMP280
14pub const DEFAULT_ADDRESS: u8 = 0x76;
15
16/// BMP280 driver
17pub struct BMP280<I2C: ehal::blocking::i2c::WriteRead> {
18    com: I2C,
19    addr: u8,
20    // Temperature compensation
21    dig_t1: u16,
22    dig_t2: i16,
23    dig_t3: i16,
24    t_fine: i32,
25    // Pressure calibration
26    dig_p1: u16,
27    dig_p2: i16,
28    dig_p3: i16,
29    dig_p4: i16,
30    dig_p5: i16,
31    dig_p6: i16,
32    dig_p7: i16,
33    dig_p8: i16,
34    dig_p9: i16,
35}
36
37impl<I2C: ehal::blocking::i2c::WriteRead> BMP280<I2C> {
38    /// Creates new BMP280 driver
39    pub fn new<E>(i2c: I2C, addr: u8) -> Result<BMP280<I2C>, E>
40    where
41        I2C: ehal::blocking::i2c::WriteRead<Error = E>,
42    {
43        let mut chip = BMP280 {
44            com: i2c,
45            addr,
46            dig_t1: 0,
47            dig_t2: 0,
48            dig_t3: 0,
49            t_fine: 0,
50            dig_p1: 0,
51            dig_p2: 0,
52            dig_p3: 0,
53            dig_p4: 0,
54            dig_p5: 0,
55            dig_p6: 0,
56            dig_p7: 0,
57            dig_p8: 0,
58            dig_p9: 0,
59        };
60
61        if chip.id() == 0x58 {
62            chip.read_calibration();
63        }
64
65        Ok(chip)
66    }
67}
68
69impl<I2C: ehal::blocking::i2c::WriteRead> BMP280<I2C> {
70    fn read_calibration(&mut self) {
71        let mut data: [u8; 24] = [0; 24];
72        let _ = self
73            .com
74            .write_read(self.addr, &[Register::calib00 as u8], &mut data);
75
76        self.dig_t1 = ((data[1] as u16) << 8) | (data[0] as u16);
77        self.dig_t2 = ((data[3] as i16) << 8) | (data[2] as i16);
78        self.dig_t3 = ((data[5] as i16) << 8) | (data[4] as i16);
79
80        self.dig_p1 = ((data[7] as u16) << 8) | (data[6] as u16);
81        self.dig_p2 = ((data[9] as i16) << 8) | (data[8] as i16);
82        self.dig_p3 = ((data[11] as i16) << 8) | (data[10] as i16);
83        self.dig_p4 = ((data[13] as i16) << 8) | (data[12] as i16);
84        self.dig_p5 = ((data[15] as i16) << 8) | (data[14] as i16);
85        self.dig_p6 = ((data[17] as i16) << 8) | (data[16] as i16);
86        self.dig_p7 = ((data[19] as i16) << 8) | (data[18] as i16);
87        self.dig_p8 = ((data[21] as i16) << 8) | (data[20] as i16);
88        self.dig_p9 = ((data[23] as i16) << 8) | (data[22] as i16);
89    }
90
91    /// Reads and returns pressure
92    pub fn pressure(&mut self) -> f64 {
93        let mut data: [u8; 6] = [0, 0, 0, 0, 0, 0];
94        let _ = self
95            .com
96            .write_read(self.addr, &[Register::press as u8], &mut data);
97        let press = (data[0] as u32) << 12 | (data[1] as u32) << 4 | (data[2] as u32) >> 4;
98
99        let mut var1 = ((self.t_fine as f64) / 2.0) - 64000.0;
100        let mut var2 = var1 * var1 * (self.dig_p6 as f64) / 32768.0;
101        var2 += var1 * (self.dig_p5 as f64) * 2.0;
102        var2 = (var2 / 4.0) + ((self.dig_p4 as f64) * 65536.0);
103        var1 = ((self.dig_p3 as f64) * var1 * var1 / 524288.0 + (self.dig_p2 as f64) * var1)
104            / 524288.0;
105        var1 = (1.0 + var1 / 32768.0) * (self.dig_p1 as f64);
106        let mut pressure = 1048576.0 - (press as f64);
107        if var1 != 0.0 {
108            pressure = (pressure - (var2 / 4096.0)) * 6250.0 / var1;
109            var1 = (self.dig_p9 as f64) * pressure * pressure / 2147483648.0;
110            var2 = pressure * (self.dig_p8 as f64) / 32768.0;
111            pressure += (var1 + var2 + (self.dig_p7 as f64)) / 16.0;
112        }
113        pressure
114    }
115
116    /// Reads and returns pressure and resets con
117    pub fn pressure_one_shot(&mut self) -> f64 {
118        let pressure = self.pressure();
119        self.set_control(Control {
120            osrs_t: Oversampling::x2,
121            osrs_p: Oversampling::x16,
122            mode: PowerMode::Forced,
123        });
124
125        pressure
126    }
127
128    /// Reads and returns temperature
129    pub fn temp(&mut self) -> f64 {
130        let mut data: [u8; 6] = [0, 0, 0, 0, 0, 0];
131        let _ = self
132            .com
133            .write_read(self.addr, &[Register::press as u8], &mut data);
134        let _pres = (data[0] as u32) << 12 | (data[1] as u32) << 4 | (data[2] as u32) >> 4;
135        let temp = (data[3] as u32) << 12 | (data[4] as u32) << 4 | (data[5] as u32) >> 4;
136
137        let v1 = ((temp as f64) / 16384.0 - (self.dig_t1 as f64) / 1024.0) * (self.dig_t2 as f64);
138        let v2 = (((temp as f64) / 131072.0 - (self.dig_t1 as f64) / 8192.0)
139            * ((temp as f64) / 131072.0 - (self.dig_t1 as f64) / 8192.0))
140            * (self.dig_t3 as f64);
141        self.t_fine = (v1 + v2) as i32;
142
143        (v1 + v2) / 5120.0
144    }
145
146    /// Returns current config
147    pub fn config(&mut self) -> Config {
148        let config = self.read_byte(Register::config);
149        let t_sb = match (config & (0b111 << 5)) >> 5 {
150            x if x == Standby::ms0_5 as u8 => Standby::ms0_5,
151            x if x == Standby::ms62_5 as u8 => Standby::ms62_5,
152            x if x == Standby::ms125 as u8 => Standby::ms125,
153            x if x == Standby::ms250 as u8 => Standby::ms250,
154            x if x == Standby::ms500 as u8 => Standby::ms500,
155            x if x == Standby::ms1000 as u8 => Standby::ms1000,
156            x if x == Standby::ms2000 as u8 => Standby::ms2000,
157            x if x == Standby::ms4000 as u8 => Standby::ms4000,
158            _ => Standby::unknown,
159        };
160        let filter = match (config & (0b111 << 2)) >> 2 {
161            x if x == Filter::off as u8 => Filter::off,
162            x if x == Filter::c2 as u8 => Filter::c2,
163            x if x == Filter::c4 as u8 => Filter::c4,
164            x if x == Filter::c8 as u8 => Filter::c8,
165            x if x == Filter::c16 as u8 => Filter::c16,
166            _ => Filter::unknown,
167        };
168        Config {
169            t_sb,
170            filter,
171        }
172    }
173
174    /// Sets configuration
175    pub fn set_config(&mut self, new: Config) {
176        let config: u8 = 0x00;
177        let t_sb = (new.t_sb as u8) << 5;
178        let filter = (new.filter as u8) << 2;
179        self.write_byte(Register::config, config | t_sb | filter);
180    }
181
182    /// Sets control
183    pub fn set_control(&mut self, new: Control) {
184        let osrs_t: u8 = (new.osrs_t as u8) << 5;
185        let osrs_p: u8 = (new.osrs_p as u8) << 2;
186        let control: u8 = osrs_t | osrs_p | (new.mode as u8);
187        self.write_byte(Register::ctrl_meas, control);
188    }
189
190    /// Returns control
191    pub fn control(&mut self) -> Control {
192        let config = self.read_byte(Register::ctrl_meas);
193        let osrs_t = match (config & (0b111 << 5)) >> 5 {
194            x if x == Oversampling::skipped as u8 => Oversampling::skipped,
195            x if x == Oversampling::x1 as u8 => Oversampling::x1,
196            x if x == Oversampling::x2 as u8 => Oversampling::x2,
197            x if x == Oversampling::x4 as u8 => Oversampling::x4,
198            x if x == Oversampling::x8 as u8 => Oversampling::x8,
199            _ => Oversampling::x16,
200        };
201        let osrs_p = match (config & (0b111 << 2)) >> 2 {
202            x if x == Oversampling::skipped as u8 => Oversampling::skipped,
203            x if x == Oversampling::x1 as u8 => Oversampling::x1,
204            x if x == Oversampling::x2 as u8 => Oversampling::x2,
205            x if x == Oversampling::x4 as u8 => Oversampling::x4,
206            x if x == Oversampling::x8 as u8 => Oversampling::x8,
207            _ => Oversampling::x16,
208        };
209        let mode = match config & 0b11 {
210            x if x == PowerMode::Sleep as u8 => PowerMode::Sleep,
211            x if x == PowerMode::Forced as u8 => PowerMode::Forced,
212            x if x == PowerMode::Normal as u8 => PowerMode::Normal,
213            _ => PowerMode::Forced,
214        };
215
216        Control {
217            osrs_t,
218            osrs_p,
219            mode,
220        }
221    }
222
223    /// Returns device status
224    pub fn status(&mut self) -> Status {
225        let status = self.read_byte(Register::status);
226        Status {
227            measuring: 0 != (status & 0b00001000),
228            im_update: 0 != (status & 0b00000001),
229        }
230    }
231
232    /// Returns device id
233    pub fn id(&mut self) -> u8 {
234        self.read_byte(Register::id)
235    }
236
237    /// Software reset, emulates POR
238    pub fn reset(&mut self) {
239        self.write_byte(Register::reset, 0xB6); // Magic from documentation
240    }
241
242    fn write_byte(&mut self, reg: Register, byte: u8) {
243        let mut buffer = [0];
244        let _ = self
245            .com
246            .write_read(self.addr, &[reg as u8, byte], &mut buffer);
247    }
248
249    fn read_byte(&mut self, reg: Register) -> u8 {
250        let mut data: [u8; 1] = [0];
251        let _ = self.com.write_read(self.addr, &[reg as u8], &mut data);
252        data[0]
253    }
254}
255
256#[derive(Debug, Copy, Clone)]
257/// Control
258pub struct Control {
259    /// Temperature oversampling
260    pub osrs_t: Oversampling,
261    /// Pressure oversampling
262    pub osrs_p: Oversampling,
263    /// Powermode
264    pub mode: PowerMode,
265}
266
267#[derive(Debug, Copy, Clone)]
268#[allow(non_camel_case_types)]
269/// Standby time in ms
270pub enum Standby {
271    /// ms0_5
272    ms0_5 = 0b000,
273    /// ms62_5
274    ms62_5 = 0b001,
275    /// ms125_5
276    ms125 = 0b010,
277    /// ms250
278    ms250 = 0b011,
279    /// ms500
280    ms500 = 0b100,
281    /// ms1000
282    ms1000 = 0b101,
283    /// ms2000
284    ms2000 = 0b110,
285    /// ms4000
286    ms4000 = 0b111,
287    /// unknown
288    unknown,
289}
290
291#[derive(Debug, Copy, Clone)]
292#[allow(non_camel_case_types)]
293/// The time constant of IIR filter
294pub enum Filter {
295    /// off
296    off = 0x00,
297    /// c2
298    c2 = 0x01,
299    /// c4
300    c4 = 0x02,
301    /// c8
302    c8 = 0x03,
303    /// c16
304    c16 = 0x04,
305    /// unknown
306    unknown,
307}
308
309/// Configuration register, sets the rate, filter and interface options
310/// of the device. Note that writing to this register while device in normal
311/// mode may be ignored. Writes in sleep mode are not ignored.
312///
313/// spi3w_en is intentionally left out of this implementation.
314#[derive(Debug, Copy, Clone)]
315pub struct Config {
316    /// Controls inactive duration in normal mode
317    pub t_sb: Standby,
318    /// Controls the time constant of IIR filter
319    pub filter: Filter,
320}
321
322/// Status
323#[derive(Debug, Copy, Clone)]
324pub struct Status {
325    /// measuring
326    measuring: bool,
327    /// im update
328    im_update: bool,
329}
330
331impl fmt::Display for Status {
332    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
333        write!(
334            f,
335            "conversion is running: {}, NVM data being copied: {}",
336            self.measuring, self.im_update
337        )
338    }
339}
340
341#[derive(Debug, Copy, Clone)]
342#[allow(non_camel_case_types)]
343/// Oversampling
344pub enum Oversampling {
345    /// skipped
346    skipped = 0b000,
347    /// x1
348    x1 = 0b001,
349    /// x2
350    x2 = 0b010,
351    /// x4
352    x4 = 0b011,
353    /// x8
354    x8 = 0b100,
355    /// x16
356    x16 = 0b101,
357}
358
359#[derive(Debug, Copy, Clone)]
360/// PowerMode
361pub enum PowerMode {
362    /// Sleep
363    Sleep = 0b00,
364    /// Forced
365    Forced = 0b01,
366    /// Normal
367    Normal = 0b11,
368}
369
370#[allow(non_camel_case_types)]
371enum Register {
372    id = 0xD0,
373    reset = 0xE0,
374    status = 0xF3,
375    ctrl_meas = 0xF4,
376    config = 0xF5,
377    press = 0xF7,
378    calib00 = 0x88,
379}