embedded_drivers/
bmp180.rs

1//! BMP180 Digital pressure sensor.
2//!
3
4use embedded_hal::blocking::delay::DelayMs;
5use embedded_hal::blocking::i2c::{Read, Write, WriteRead};
6use num_traits::Pow;
7
8// BMP180, BMP085 address.
9const BMP180_I2CADDR: u8 = 0x77;
10
11const BMP180_CAL_AC1: u8 = 0xAA; // R   Calibration data (16 bits)
12const BMP180_CAL_AC2: u8 = 0xAC; // R   Calibration data (16 bits)
13const BMP180_CAL_AC3: u8 = 0xAE; // R   Calibration data (16 bits)
14const BMP180_CAL_AC4: u8 = 0xB0; // R   Calibration data (16 bits)
15const BMP180_CAL_AC5: u8 = 0xB2; // R   Calibration data (16 bits)
16const BMP180_CAL_AC6: u8 = 0xB4; // R   Calibration data (16 bits)
17const BMP180_CAL_B1: u8 = 0xB6; // R   Calibration data (16 bits)
18const BMP180_CAL_B2: u8 = 0xB8; // R   Calibration data (16 bits)
19const BMP180_CAL_MB: u8 = 0xBA; // R   Calibration data (16 bits)
20const BMP180_CAL_MC: u8 = 0xBC; // R   Calibration data (16 bits)
21const BMP180_CAL_MD: u8 = 0xBE; // R   Calibration data (16 bits)
22
23const BMP180_CONTROL: u8 = 0xF4;
24const BMP180_TEMPDATA: u8 = 0xF6;
25const BMP180_PRESSUREDATA: u8 = 0xF6;
26
27const BMP180_READTEMPCMD: u8 = 0x2E;
28const BMP180_READPRESSURECMD: u8 = 0x34;
29
30/// Hardware pressure sampling accuracy modes.
31#[repr(u8)]
32#[derive(Copy, Clone)]
33pub enum Mode {
34    UltraLowPower = 0,
35    Standard,
36    HighResolution,
37    UltraHighResolution,
38}
39
40impl Mode {
41    fn oversampling_settings(&self) -> u8 {
42        *self as u8
43    }
44
45    fn wait_conversion<D: DelayMs<u8>>(&self, delay: &mut D) {
46        let ms = match self {
47            Mode::UltraLowPower => 5,
48            Mode::Standard => 8,
49            Mode::HighResolution => 14,
50            Mode::UltraHighResolution => 26,
51        };
52        delay.delay_ms(ms);
53    }
54}
55
56/// BMP180, or BMP085.
57pub struct BMP180<I> {
58    device: I,
59    mode: Mode,
60    ac1: i16,
61    ac2: i16,
62    ac3: i16,
63    ac4: u16,
64    ac5: u16,
65    ac6: u16,
66    b1: i16,
67    b2: i16,
68    mb: i16,
69    mc: i16,
70    md: i16,
71}
72
73impl<I: Write + WriteRead + Read> BMP180<I> {
74    /// Create device driver instance.
75    pub fn new(i2c: I) -> Self {
76        BMP180 {
77            device: i2c,
78            mode: Mode::UltraHighResolution,
79            ac1: 408,
80            ac2: -72,
81            ac3: -14383,
82            ac4: 32741,
83            ac5: 32757,
84            ac6: 23153,
85            b1: 6190,
86            b2: 4,
87            mb: -32767,
88            mc: -8711,
89            md: 2868,
90        }
91    }
92
93    /// Read calibration data from the EEPROM of BMP180.
94    pub fn init(&mut self) {
95        self.ac1 = self.read_i16(BMP180_CAL_AC1);
96        self.ac2 = self.read_i16(BMP180_CAL_AC2);
97        self.ac3 = self.read_i16(BMP180_CAL_AC3);
98
99        self.ac4 = self.read_u16(BMP180_CAL_AC4);
100        self.ac5 = self.read_u16(BMP180_CAL_AC5);
101        self.ac6 = self.read_u16(BMP180_CAL_AC6);
102
103        self.b1 = self.read_i16(BMP180_CAL_B1);
104        self.b2 = self.read_i16(BMP180_CAL_B2);
105        self.mb = self.read_i16(BMP180_CAL_MB);
106        self.mc = self.read_i16(BMP180_CAL_MC);
107        self.md = self.read_i16(BMP180_CAL_MD);
108    }
109
110    /// read uncompensated temperature value
111    #[inline]
112    fn get_ut<D: DelayMs<u8>>(&mut self, delay: &mut D) -> i32 {
113        self.write(&[BMP180_CONTROL, BMP180_READTEMPCMD]);
114        delay.delay_ms(5);
115        self.read_i16(BMP180_TEMPDATA) as i32
116    }
117
118    /// read uncompensated pressure value
119    #[inline]
120    fn get_up<D: DelayMs<u8>>(&mut self, delay: &mut D) -> i32 {
121        let oss = self.mode.oversampling_settings();
122        self.write(&[BMP180_CONTROL, BMP180_READPRESSURECMD + (oss << 6)]);
123        self.mode.wait_conversion(delay);
124
125        let msb = self.read_u8(BMP180_PRESSUREDATA) as i32;
126        let lsb = self.read_u8(BMP180_PRESSUREDATA + 1) as i32;
127        let xlsb = self.read_u8(BMP180_PRESSUREDATA + 2) as i32;
128
129        ((msb << 16) + (lsb << 8) + xlsb) >> (8 - oss)
130    }
131
132    /// Calculate true temperature, resolution is 0.1C
133    pub fn get_temperature<D: DelayMs<u8>>(&mut self, delay: &mut D) -> f32 {
134        let ut = self.get_ut(delay);
135
136        let x1 = ((ut - self.ac6 as i32) * self.ac5 as i32) >> 15;
137        let x2 = ((self.mc as i32) << 11) / (x1 + self.md as i32);
138        let b5 = x1 + x2;
139        ((b5 + 8) >> 4) as f32 / 10.0
140    }
141
142    /// Calculate true pressure, in Pa
143    pub fn get_pressure<D: DelayMs<u8>>(&mut self, delay: &mut D) -> i32 {
144        let oss = self.mode.oversampling_settings();
145
146        let ut = self.get_ut(delay);
147        let up = self.get_up(delay);
148
149        let x1 = ((ut - self.ac6 as i32) * self.ac5 as i32) >> 15;
150        let x2 = ((self.mc as i32) << 11) / (x1 + self.md as i32);
151        let b5 = x1 + x2;
152
153        let b6 = b5 - 4000;
154        let x1 = ((self.b2 as i32) * ((b6 * b6) >> 12)) >> 11;
155        let x2 = ((self.ac2 as i32) * b6) >> 11;
156        let x3 = x1 + x2;
157        // NOTE: must use i64 type
158        let b3: i64 = ((((self.ac1 as i64) * 4 + x3 as i64) << oss) + 2) / 4;
159
160        let x1 = ((self.ac3 as i32) * b6) >> 13;
161        let x2 = ((self.b1 as i32) * ((b6 * b6) >> 12)) >> 16;
162        let x3 = ((x1 + x2) + 2) >> 2;
163        let b4: u32 = (self.ac4 as u32) * ((x3 + 32768) as u32) >> 15;
164
165        let b7 = (up as i64 - b3 as i64) * (50000 >> oss);
166
167        let p = if b7 < 0x80000000 {
168            (b7 * 2) / (b4 as i64)
169        } else {
170            (b7 / (b4 as i64)) * 2
171        };
172
173        let x1 = (p >> 8) * (p >> 8);
174        let x1 = (x1 * 3038) >> 16;
175        let x2 = (-7357 * p) >> 16;
176        let p = p + ((x1 + x2 + 3791) >> 4);
177
178        p as i32
179    }
180
181    /// Calculate absolute altitude
182    pub fn calculate_altitude<D: DelayMs<u8>>(&mut self, delay: &mut D, sealevel_pa: f32) -> f32 {
183        let pa = self.get_pressure(delay) as f32;
184        44330.0 * (1.0 - (pa / sealevel_pa).pow(1.0 / 5.255))
185    }
186
187    /// Calculate pressure at sea level
188    pub fn calculate_sealevel_pressure<D: DelayMs<u8>>(
189        &mut self,
190        delay: &mut D,
191        altitude_m: f32,
192    ) -> u32 {
193        let pressure = self.get_pressure(delay) as f32;
194        let p0 = pressure / (1.0 - altitude_m / 44330.0).pow(5.255);
195        p0 as u32
196    }
197
198    pub fn release(self) -> I {
199        self.device
200    }
201
202    fn write(&mut self, data: &[u8]) {
203        let _ = self.device.write(BMP180_I2CADDR, data);
204    }
205
206    fn read_u8(&mut self, reg: u8) -> u8 {
207        let mut buf = [0u8];
208        let _ = self.device.write_read(BMP180_I2CADDR, &[reg], &mut buf[..]);
209        buf[0]
210    }
211
212    fn read_i16(&mut self, reg: u8) -> i16 {
213        let mut buf = [0u8; 2];
214        // buf[0] = self.read_u8(reg);
215        // buf[1] = self.read_u8(reg + 1);
216        let _ = self.device.write_read(BMP180_I2CADDR, &[reg], &mut buf[..]);
217        i16::from_be_bytes(buf)
218    }
219
220    fn read_u16(&mut self, reg: u8) -> u16 {
221        let mut buf = [0u8; 2];
222        // buf[0] = self.read_u8(reg);
223        // buf[1] = self.read_u8(reg + 1);
224        let _ = self.device.write_read(BMP180_I2CADDR, &[reg], &mut buf[..]);
225        u16::from_be_bytes(buf)
226    }
227}