Created
November 27, 2020 18:07
-
-
Save andelf/08c8ed71822844e5296e0f420cfe8296 to your computer and use it in GitHub Desktop.
BMP085 Rust embedded-hal-driver
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use embedded_hal::blocking::delay::DelayMs; | |
use embedded_hal::blocking::i2c::{Write, WriteRead}; | |
// BMP085 default address. | |
const BMP085_I2CADDR: u8 = 0x77; | |
// Operating Modes | |
pub const BMP085_ULTRALOWPOWER: u8 = 0; | |
pub const BMP085_STANDARD: u8 = 1; | |
pub const BMP085_HIGHRES: u8 = 2; | |
pub const BMP085_ULTRAHIGHRES: u8 = 3; | |
// BMP085 Registers | |
const BMP085_CAL_AC1: u8 = 0xAA; // R Calibration data (16 bits) | |
const BMP085_CAL_AC2: u8 = 0xAC; // R Calibration data (16 bits) | |
const BMP085_CAL_AC3: u8 = 0xAE; // R Calibration data (16 bits) | |
const BMP085_CAL_AC4: u8 = 0xB0; // R Calibration data (16 bits) | |
const BMP085_CAL_AC5: u8 = 0xB2; // R Calibration data (16 bits) | |
const BMP085_CAL_AC6: u8 = 0xB4; // R Calibration data (16 bits) | |
const BMP085_CAL_B1: u8 = 0xB6; // R Calibration data (16 bits) | |
const BMP085_CAL_B2: u8 = 0xB8; // R Calibration data (16 bits) | |
const BMP085_CAL_MB: u8 = 0xBA; // R Calibration data (16 bits) | |
const BMP085_CAL_MC: u8 = 0xBC; // R Calibration data (16 bits) | |
const BMP085_CAL_MD: u8 = 0xBE; // R Calibration data (16 bits) | |
const BMP085_CONTROL: u8 = 0xF4; | |
const BMP085_TEMPDATA: u8 = 0xF6; | |
const BMP085_PRESSUREDATA: u8 = 0xF6; | |
// Commands | |
const BMP085_READTEMPCMD: u8 = 0x2E; | |
const BMP085_READPRESSURECMD: u8 = 0x34; | |
pub struct Bmp085<I> { | |
device: I, | |
ac1: i16, | |
ac2: i16, | |
ac3: i16, | |
ac4: u16, | |
ac5: u16, | |
ac6: u16, | |
b1: i16, | |
b2: i16, | |
mb: i16, | |
mc: i16, | |
md: i16, | |
} | |
impl<I: Write + WriteRead> Bmp085<I> { | |
pub fn new(i2c: I) -> Self { | |
Bmp085 { | |
device: i2c, | |
ac1: 408, | |
ac2: -72, | |
ac3: -14383, | |
ac4: 32741, | |
ac5: 32757, | |
ac6: 23153, | |
b1: 6190, | |
b2: 4, | |
mb: -32767, | |
mc: -8711, | |
md: 2868, | |
} | |
} | |
fn read_raw_temp<D: DelayMs<u16>>(&mut self, delay: &mut D) -> u16 { | |
self.write(&[BMP085_CONTROL, BMP085_READTEMPCMD]); | |
delay.delay_ms(5); | |
self.read_u16(BMP085_TEMPDATA) | |
} | |
pub fn read_temperature<D: DelayMs<u16>>(&mut self, delay: &mut D) -> f32 { | |
let ut = self.read_raw_temp(delay) as i32; | |
let x1 = ((ut as i32 - self.ac6 as i32) * (self.ac5 as i32)) >> 15; | |
let x2 = ((self.mc as i32) << 11) / (x1 as i32 + self.md as i32); | |
let b5 = x1 + x2; | |
(((b5 + 8) >> 4) as f32) / 10.0 | |
} | |
pub fn read_raw_pressure<D: DelayMs<u16>>(&mut self, delay: &mut D) -> u32 { | |
let mode = BMP085_STANDARD; | |
self.write(&[BMP085_CONTROL, BMP085_READPRESSURECMD + (mode << 6)]); | |
delay.delay_ms(26); | |
let msb = self.read_u8(BMP085_PRESSUREDATA) as u32; | |
let lsb = self.read_u8(BMP085_PRESSUREDATA + 1) as u32; | |
let xlsb = self.read_u8(BMP085_PRESSUREDATA + 2) as u32; | |
// 8 - BMP085_ULTRAHIGHRES | |
let raw = ((msb << 16) + (lsb << 8) + xlsb) >> (8 - mode); | |
raw | |
} | |
pub fn read_pressure<D: DelayMs<u16>>(&mut self, delay: &mut D) -> u32 { | |
let mode = BMP085_STANDARD; | |
let ut = self.read_raw_temp(delay) as i64; | |
let up = self.read_raw_pressure(delay) as i64; | |
// Calculations below are taken straight from section 3.5 of the datasheet. | |
// Calculate true temperature coefficient B5. | |
let x1 = ((ut as i64 - self.ac6 as i64) * (self.ac5 as i64)) >> 15; | |
let x2 = ((self.mc as i64) << 11) / (x1 as i64 + self.md as i64); | |
let b5 = x1 + x2; | |
// Pressure Calculations | |
let b6 = b5 - 4000; | |
let x1 = ((self.b2 as i64) * ((b6 * b6) >> 12)) >> 11; | |
let x2 = ((self.ac2 as i64) * b6) >> 11; | |
let x3 = x1 + x2; | |
let b3 = ((((self.ac1 as i64) * 4 + x3) << mode) + 2) / 4; | |
let x1 = ((self.ac3 as i64) * b6) >> 13; | |
let x2 = ((self.b1 as i64) * ((b6 * b6) >> 12)) >> 16; | |
let x3 = ((x1 + x2) + 2) >> 2; | |
let b4 = ((self.ac4 as i64) * (x3 + 32768)) >> 15; | |
let b7 = (up - b3) * (50000 >> mode); | |
let p = if b7 < 0x80000000 { | |
(b7 * 2) / b4 | |
} else { | |
(b7 / b4) * 2 | |
}; | |
let x1 = (p >> 8) * (p >> 8); | |
let x1 = (x1 * 3038) >> 16; | |
let x2 = (-7357 * p) >> 16; | |
let p = p + ((x1 + x2 + 3791) >> 4); | |
p as u32 | |
} | |
fn write(&mut self, data: &[u8]) { | |
let _ = self.device.write(BMP085_I2CADDR, data); | |
} | |
fn read_u8(&mut self, reg: u8) -> u8 { | |
let mut buf = [0u8]; | |
let _ = self.device.write_read(BMP085_I2CADDR, &[reg], &mut buf[..]); | |
buf[0] | |
} | |
fn read_i16(&mut self, reg: u8) -> i16 { | |
let mut buf = [0u8; 2]; | |
let _ = self.device.write_read(BMP085_I2CADDR, &[reg], &mut buf[..]); | |
i16::from_be_bytes(buf.into()) | |
} | |
fn read_u16(&mut self, reg: u8) -> u16 { | |
let mut buf = [0u8; 2]; | |
let _ = self.device.write_read(BMP085_I2CADDR, &[reg], &mut buf[..]); | |
u16::from_be_bytes(buf.into()) | |
} | |
pub fn load_calibration(&mut self) { | |
self.ac1 = self.read_i16(BMP085_CAL_AC1); | |
self.ac2 = self.read_i16(BMP085_CAL_AC2); | |
self.ac3 = self.read_i16(BMP085_CAL_AC3); | |
self.ac4 = self.read_u16(BMP085_CAL_AC4); | |
self.ac5 = self.read_u16(BMP085_CAL_AC5); | |
self.ac6 = self.read_u16(BMP085_CAL_AC6); | |
self.b1 = self.read_i16(BMP085_CAL_B1); | |
self.b2 = self.read_i16(BMP085_CAL_B2); | |
self.mb = self.read_i16(BMP085_CAL_MB); | |
self.mc = self.read_i16(BMP085_CAL_MC); | |
self.md = self.read_i16(BMP085_CAL_MD); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment