Skip to content

Rework to make use of embedded-hal and no-std in order to get it working on a MCU #1

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
[package]
name = "ms5611"
version = "1.0.0"
authors = ["Ken Elkabany <[email protected]>"]
authors = ["Ken Elkabany <[email protected]>", "Marius Knaust <[email protected]>"]
license = "MIT"
description = "Library for the MS5611 barometric pressure sensor."
repository = "https://github.com/braincore/ms5611-rs"
keywords = ["ms5611"]
categories = ["embedded", "no-std", "hardware-support"]
keywords = ["ms5611", "embedded-hal"]
edition = "2018"
readme = "README.md"

[dependencies]
byteorder = "1.1.0"
i2cdev = "0.3.1"
embedded-hal = "0.2.2"
byteorder = { version = "1.1.0", default-features = false }

[dev-dependencies]
linux-embedded-hal = "0.2.2"
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# MS5611 Library for Rust [![Latest Version]][crates.io] [![Documentation]][docs.rs]
# MS5611 Library for Rust [![Latest Version]][crates.io] [![Documentation]][docs.rs]

[Latest Version]: https://img.shields.io/crates/v/ms5611.svg
[crates.io]: https://crates.io/crates/ms5611
Expand All @@ -15,7 +15,7 @@ interface (no SPI).

## Usage

See basic test in `lib.rs`.
See basic test in `tests/basic.rs`.

## Testing

Expand Down
129 changes: 44 additions & 85 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,11 @@
//! A library for the MS5611 barometric pressure sensor.

extern crate byteorder;
#![no_std]

use byteorder::{ByteOrder, BigEndian};
extern crate i2cdev;
use i2cdev::core::*;
use i2cdev::linux::{LinuxI2CDevice, LinuxI2CError};
use std::time;
use std::thread;

fn get_i2c_bus_path(i2c_bus: i32) -> String {
format!("/dev/i2c-{}", i2c_bus)
}

use embedded_hal::blocking::delay::DelayMs;
use embedded_hal::blocking::i2c::{Read, Write, WriteRead};

/// Oversampling ratio
/// See datasheet for more information.
Expand All @@ -23,7 +18,7 @@ pub enum Osr {
}

impl Osr {
fn get_delay(&self) -> u64 {
fn get_delay(&self) -> u8 {
match *self {
Osr::Opt256 => 1,
Osr::Opt512 => 2,
Expand All @@ -45,9 +40,10 @@ impl Osr {
}

/// Pressure sensor
pub struct Ms5611 {
i2c_dev: LinuxI2CDevice,
prom: Prom,
pub struct Ms5611<I> {
i2c: I,
address : u8,
prom: Prom
}

enum Ms5611Reg {
Expand Down Expand Up @@ -101,35 +97,40 @@ struct Prom {
pub temp_coef_temp: u16,
}

impl Ms5611 {
impl<I, E> Ms5611<I>
where
I: Read<Error = E> + Write<Error = E> + WriteRead<Error = E>,
{

/// If i2c_addr is unspecified, 0x77 is used.
/// The addr of the device is 0x77 if CSB is low / 0x76 if CSB is high.
pub fn new(i2c_bus: i32, i2c_addr: Option<u16>)
-> Result<Ms5611, LinuxI2CError> {
let mut i2c_dev = LinuxI2CDevice::new(
get_i2c_bus_path(i2c_bus), i2c_addr.unwrap_or(0x77))?;
pub fn new(mut i2c: I, i2c_addr: Option<u8>)
-> Result<Self, E> {
let address = i2c_addr.unwrap_or(0x77);

let prom = Self::read_prom(&mut i2c_dev)?;
let prom = Self::read_prom(&mut i2c, address)?;

let ms = Ms5611 {
i2c_dev,
prom,
i2c,
address: address,
prom
};

Ok(ms)
}

/// Triggers a hardware reset of the device.
pub fn reset(&mut self) -> Result<(), LinuxI2CError> {
self.i2c_dev.write(&[Ms5611Reg::Reset.addr()])?;
pub fn reset<D>(&mut self, delay: &mut D) -> Result<(), E>
where D: DelayMs<u8>
{
self.i2c.write(self.address, &[Ms5611Reg::Reset.addr()])?;
// Haven't tested for the lower time bound necessary for the chip to
// start functioning again. But, it does require some amount of sleep.
thread::sleep(time::Duration::from_millis(50));
delay.delay_ms(50);
Ok(())
}

fn read_prom(i2c_dev: &mut LinuxI2CDevice) -> Result<Prom, LinuxI2CError> {
fn read_prom(i2c: &mut I, address : u8) -> Result<Prom, E> {
let mut crc_check = 0u16;

// This is the CRC scheme in the MS5611 AN520 (Application Note)
Expand All @@ -151,42 +152,34 @@ impl Ms5611 {

let mut buf: [u8; 2] = [0u8; 2];
// Address reserved for manufacturer. We need it for the CRC.
i2c_dev.write(&[Ms5611Reg::Prom.addr()])?;
i2c_dev.read(&mut buf)?;
i2c.write_read(address, &[Ms5611Reg::Prom.addr()], &mut buf)?;
crc_accumulate_buf2(&mut crc_check, &buf);

i2c_dev.write(&[Ms5611Reg::Prom.addr() + 2])?;
i2c_dev.read(&mut buf)?;
i2c.write_read(address, &[Ms5611Reg::Prom.addr() + 2], &mut buf)?;
let pressure_sensitivity = BigEndian::read_u16(&mut buf);
crc_accumulate_buf2(&mut crc_check, &buf);

i2c_dev.write(&[Ms5611Reg::Prom.addr() + 4])?;
i2c_dev.read(&mut buf)?;
i2c.write_read(address, &[Ms5611Reg::Prom.addr() + 4], &mut buf)?;
let pressure_offset = BigEndian::read_u16(&mut buf);
crc_accumulate_buf2(&mut crc_check, &buf);

i2c_dev.write(&[Ms5611Reg::Prom.addr() + 6])?;
i2c_dev.read(&mut buf)?;
i2c.write_read(address, &[Ms5611Reg::Prom.addr() + 6], &mut buf)?;
let temp_coef_pressure_sensitivity = BigEndian::read_u16(&mut buf);
crc_accumulate_buf2(&mut crc_check, &buf);

i2c_dev.write(&[Ms5611Reg::Prom.addr() + 8])?;
i2c_dev.read(&mut buf)?;
i2c.write_read(address, &[Ms5611Reg::Prom.addr() + 8], &mut buf)?;
let temp_coef_pressure_offset = BigEndian::read_u16(&mut buf);
crc_accumulate_buf2(&mut crc_check, &buf);

i2c_dev.write(&[Ms5611Reg::Prom.addr() + 10])?;
i2c_dev.read(&mut buf)?;
i2c.write_read(address, &[Ms5611Reg::Prom.addr() + 10], &mut buf)?;
let temp_ref = BigEndian::read_u16(&mut buf);
crc_accumulate_buf2(&mut crc_check, &buf);

i2c_dev.write(&[Ms5611Reg::Prom.addr() + 12])?;
i2c_dev.read(&mut buf)?;
i2c.write_read(address, &[Ms5611Reg::Prom.addr() + 12], &mut buf)?;
let temp_coef_temp = BigEndian::read_u16(&mut buf);
crc_accumulate_buf2(&mut crc_check, &buf);

i2c_dev.write(&[Ms5611Reg::Prom.addr() + 14])?;
i2c_dev.read(&mut buf)?;
i2c.write_read(address, &[Ms5611Reg::Prom.addr() + 14], &mut buf)?;
// CRC is only last 4 bits
let crc = BigEndian::read_u16(&mut buf) & 0x000f;
crc_accumulate_byte(&mut crc_check, buf[0]);
Expand All @@ -211,24 +204,24 @@ impl Ms5611 {
/// Based on oversampling ratio, function may block between 1ms (OSR=256)
/// to 18ms (OSR=4096). To avoid blocking, consider invoking this function
/// in a separate thread.
pub fn read_sample(&mut self, osr: Osr) -> Result<Ms5611Sample, LinuxI2CError> {
pub fn read_sample<D>(&mut self, osr: Osr, delay: &mut D) -> Result<Ms5611Sample, E>
where D: DelayMs<u8>
{
// Note: Variable names aren't pretty, but they're consistent with the
// MS5611 datasheet.
let mut buf = [0u8; 4];

self.i2c_dev.write(&[Ms5611Reg::D1.addr() + osr.addr_modifier()])?;
self.i2c.write(self.address, &[Ms5611Reg::D1.addr() + osr.addr_modifier()])?;
// If we don't delay, the read is all 0s.
thread::sleep(time::Duration::from_millis(osr.get_delay()));
self.i2c_dev.write(&[Ms5611Reg::AdcRead.addr()])?;
self.i2c_dev.read(&mut buf[1 .. 4])?;
delay.delay_ms(osr.get_delay());
self.i2c.write_read(self.address, &[Ms5611Reg::AdcRead.addr()], &mut buf[1 .. 4])?;

// Raw digital pressure
let d1 = BigEndian::read_i32(&mut buf);

self.i2c_dev.write(&[Ms5611Reg::D2.addr() + osr.addr_modifier()])?;
thread::sleep(time::Duration::from_millis(osr.get_delay()));
self.i2c_dev.write(&[Ms5611Reg::AdcRead.addr()])?;
self.i2c_dev.read(&mut buf[1 .. 4])?;
self.i2c.write(self.address, &[Ms5611Reg::D2.addr() + osr.addr_modifier()])?;
delay.delay_ms(osr.get_delay());
self.i2c.write_read(self.address, &[Ms5611Reg::AdcRead.addr()], &mut buf[1 .. 4])?;

// Raw digital temperature
let d2 = BigEndian::read_i32(&mut buf) as i64;
Expand Down Expand Up @@ -279,37 +272,3 @@ impl Ms5611 {
})
}
}

#[cfg(test)]
mod tests {
use super::{Ms5611, Osr};
use std::env;

fn get_i2c_bus() -> i32 {
match env::var("MS5611_I2C_BUS") {
Ok(bus_string) => {
bus_string.parse().expect(
"Could not convert MS5611_I2C_BUS env var to i32.")
},
Err(_) => 1,
}
}

fn get_i2c_addr() -> Option<u16> {
match env::var("MS5611_I2C_ADDR") {
Ok(addr_string) => {
Some(addr_string.parse().expect(
"Could not convert MS5611_I2C_ADDR env var to u16."))
},
Err(_) => None,
}
}

#[test]
fn basic() {
let mut ms5611 = Ms5611::new(
get_i2c_bus(), get_i2c_addr()).unwrap();
ms5611.read_sample(Osr::Opt256).unwrap();
ms5611.reset().unwrap();
}
}
41 changes: 41 additions & 0 deletions tests/basic.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
use linux_embedded_hal::{Delay, I2cdev};
use ms5611::{Ms5611, Osr};
use std::env;

fn get_i2c_bus() -> i32 {
match env::var("MS5611_I2C_BUS") {
Ok(bus_string) => {
bus_string.parse().expect(
"Could not convert MS5611_I2C_BUS env var to i32.")
},
Err(_) => 1,
}
}

fn get_i2c_addr() -> Option<u8> {
match env::var("MS5611_I2C_ADDR") {
Ok(addr_string) => {
Some(addr_string.parse().expect(
"Could not convert MS5611_I2C_ADDR env var to u16."))
},
Err(_) => None,
}
}


fn get_i2c_bus_path(i2c_bus: i32) -> String {
format!("/dev/i2c-{}", i2c_bus)
}


#[test]
fn basic() {
let dev = I2cdev::new(get_i2c_bus_path(get_i2c_bus())).unwrap();

let mut ms5611 = Ms5611::new(dev, get_i2c_addr()).unwrap();

let mut delay = Delay;

ms5611.read_sample(Osr::Opt256, &mut delay).unwrap();
ms5611.reset(&mut delay).unwrap();
}