Skip to content

Instantly share code, notes, and snippets.

@andelf
Created November 27, 2020 18:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save andelf/08c8ed71822844e5296e0f420cfe8296 to your computer and use it in GitHub Desktop.
Save andelf/08c8ed71822844e5296e0f420cfe8296 to your computer and use it in GitHub Desktop.
BMP085 Rust embedded-hal-driver
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