Git Product home page Git Product logo

bme280-rs's Introduction

bme280

Crates.io Crates.io Released API docs

A rust device driver for the Bosch BME280 temperature, humidity, and atmospheric pressure sensor and the Bosch BMP280 temperature and atmospheric pressure sensor.

Usage

use linux_embedded_hal as hal;

use linux_embedded_hal::{Delay, I2cdev};
use bme280::i2c::BME280;

// using Linux I2C Bus #1 in this example
let i2c_bus = I2cdev::new("/dev/i2c-1").unwrap();
let mut delay = /* ..delay provider */
// initialize the BME280 using the primary I2C address 0x76
let mut bme280 = BME280::new_primary(i2c_bus);

// or, initialize the BME280 using the secondary I2C address 0x77
// let mut bme280 = BME280::new_secondary(i2c_bus);

// or, initialize the BME280 using a custom I2C address
// let bme280_i2c_addr = 0x88;
// let mut bme280 = BME280::new(i2c_bus, bme280_i2c_addr);

// initialize the sensor
bme280.init(&mut delay).unwrap();

// measure temperature, pressure, and humidity
let measurements = bme280.measure(&mut delay).unwrap();

println!("Relative Humidity = {}%", measurements.humidity);
println!("Temperature = {} deg C", measurements.temperature);
println!("Pressure = {} pascals", measurements.pressure);

Serde Support

To enable optional serde serialization support for the measurements struct, simply enable the serde feature, like so in Cargo.toml:

[dependencies]
bme280 = { version = "0.2", features = ["serde"] }

License

Licensed under either of:

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

bme280-rs's People

Contributors

cbjamo avatar mbuesch avatar mgottschlag avatar mrd0ll4r avatar quentinmit avatar sbruton avatar sycrosity avatar texitoi avatar versbinarii avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

bme280-rs's Issues

Suggestion to add embedded-hal feature flag

In trying to bring along an embedded Rust application that I'm working on to the latest bme280-rs crate version, I can no longer get this working due to the particular DelayUs trait required by the rp2040-hal.

So my suggestion is to have the crate still utilize embedded-hal-0.2.7 but then have an experimental feature flag to utilize the 1.0.0-alpha.X series, at least until the 1.0.0 releases.

I'm running into the following issue that I can't quite seem to resolve otherwise. If there is a way to work around this I'd love to know, otherwise I submit my suggestion above which is exactly the approach that the rp2040-hal project has gone with.

let res = bme280.init(&mut delay);
     |           ---- ^^^^^^^^^^ the trait `DelayUs` is not implemented for `cortex_m::delay::Delay`

Example from README not working

Hi!

I was trying to implement the bme280 crate in a project of mine. While trying I always ran into some issues. I was then running the example from the README and the basic.rs example from the examples folder..

I always run into the following errors:

error[E0277]: the trait bound `I2cdev: embedded_hal::i2c::blocking::I2c` is not satisfied
  --> src/main.rs:8:44
   |
8  |     let mut bme280 = BME280::new_secondary(i2c_bus);
   |                      --------------------- ^^^^^^^ the trait `embedded_hal::i2c::blocking::I2c` is not implemented for `I2cdev`
   |                      |
   |                      required by a bound introduced by this call
   |
note: required by a bound in `bme280::i2c::BME280::<I2C>::new_secondary`
  --> /cargo/registry/src/github.com-1ecc6299db9ec823/bme280-0.4.4/src/i2c.rs:22:10
   |
22 |     I2C: I2c + ErrorType,
   |          ^^^ required by this bound in `bme280::i2c::BME280::<I2C>::new_secondary`

error[E0599]: the method `init` exists for struct `bme280::i2c::BME280<I2cdev>`, but its trait bounds were not satisfied
   --> src/main.rs:10:12
    |
10  |     bme280.init(&mut delay).unwrap();
    |            ^^^^ method cannot be called on `bme280::i2c::BME280<I2cdev>` due to unsatisfied trait bounds
    |
   ::: /cargo/registry/src/github.com-1ecc6299db9ec823/linux-embedded-hal-0.3.2/src/lib.rs:124:1
    |
124 | pub struct I2cdev {
    | -----------------
    | |
    | doesn't satisfy `I2cdev: embedded_hal::i2c::ErrorType`
    | doesn't satisfy `I2cdev: embedded_hal::i2c::blocking::I2c`
    |
    = note: the following trait bounds were not satisfied:
            `I2cdev: embedded_hal::i2c::blocking::I2c`
            `I2cdev: embedded_hal::i2c::ErrorType`

error[E0599]: the method `measure` exists for struct `bme280::i2c::BME280<I2cdev>`, but its trait bounds were not satisfied
   --> src/main.rs:12:35
    |
12  |         let measurements = bme280.measure(&mut delay).unwrap();
    |                                   ^^^^^^^ method cannot be called on `bme280::i2c::BME280<I2cdev>` due to unsatisfied trait bounds
    |
   ::: /cargo/registry/src/github.com-1ecc6299db9ec823/linux-embedded-hal-0.3.2/src/lib.rs:124:1
    |
124 | pub struct I2cdev {
    | -----------------
    | |
    | doesn't satisfy `I2cdev: embedded_hal::i2c::ErrorType`
    | doesn't satisfy `I2cdev: embedded_hal::i2c::blocking::I2c`
    |
    = note: the following trait bounds were not satisfied:
            `I2cdev: embedded_hal::i2c::blocking::I2c`
            `I2cdev: embedded_hal::i2c::ErrorType`

Some errors have detailed explanations: E0277, E0599.
For more information about an error, try `rustc --explain E0277`.
error: could not compile `bmetest` due to 3 previous errors

I suppose it's an issue in the linux-embedded-hal crate but I wanted to ask for advice on how to fix this in case I'm doing something wrong...

Also, would you mind a MR removing the example from the README and replace it with a link to the examples folder? Or do you have the example in the README for docs.rs/crates.io?

Is a pinned embedded-hal necessary?

Is there any reason why embedded-hal is pinned to a specific version? Usually drivers seem to require only a minimum version. This unfortunately causes this crate to break each time e.g. embassy bumps it's embedded hal dependency.

Consumes the delay provider

The driver works great, but consumes the delay provider, making it unavailable for the rest of the code. Of course the delay is necessary for soft_reset and measure functions, but I was wondering whether it could be done differently. Possible ideas (which may or may not work):

  • borrow the delay instead of owning it - no idea whether this could work
  • delay in a different way, either with a simple busy NOP loop or ASM delay: both would require reading the actual core frequency first

I don't know enough Rust to try and tackle it myself yet, but maybe one of these could be tried?

BME280 not working on ESP32

I'm trying to get this running on an ESP32 (with ESP-IDF).
I'm able to initialize the device but any measurement results in I2c(EspError(-1)) (while -1 is ESP_FAIL).
I was able to fix the error above by fixing what looks like a typo (or are two 0xF4 intentional?):

diff --git a/src/lib.rs b/src/lib.rs
index 6b142e1..8aa4779 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -72,7 +72,7 @@ use serde::Serialize;
 const BME280_I2C_ADDR_PRIMARY: u8 = 0x76;
 const BME280_I2C_ADDR_SECONDARY: u8 = 0x77;
 
-const BME280_PWR_CTRL_ADDR: u8 = 0xF4;
+const BME280_PWR_CTRL_ADDR: u8 = 0xF3;
 const BME280_CTRL_HUM_ADDR: u8 = 0xF2;
 const BME280_CTRL_MEAS_ADDR: u8 = 0xF4;
 const BME280_CONFIG_ADDR: u8 = 0xF5;

With that fix in place i can get measurements (as many as i want) until i wait for a bit. After a break of some seconds every measurement is the I2c(EspError(-1)) again.
A logic analizer shows that the ESP is trying to talk to the BME280 but the transfer gets NACKed:
Bildschirmfoto von 2021-09-14 21-55-19
(That's all, there is nothing following on the right side)

I've also notices that the measured values do not change at all and also look (completely) wrong (60_000 hPa ?!).

measured 21.517174°C
measured 59912.863hPa
measured 63.775578%

Use configurable readout delay

The measurement time is hardcoded using a delay of 40ms:

delay.delay_ms(40).await.map_err(|_| Error::Delay)?; // await measurement

This limits the measurement rate to 25Hz, while both the BMP280 and BME280 datasheets say faster updates rates are supported when using lower oversampling and IIR values. Would it make sense to add a measurement delay field to the Configuration struct? The datasheets don't provide the correct values for all combinations of oversampling and IRR filter settings so I think setting the delay is best left to the user.

called `Result::unwrap()` on an `Err` value: InvalidData

With this code (to read the weather with esp32-c3 and bm280):

use esp_idf_svc::hal::{
    delay,
    i2c::{I2cConfig, I2cDriver},
    peripherals::Peripherals,
    prelude::*,
};

use bme280::i2c::BME280;

fn main() {
    esp_idf_svc::sys::link_patches();
    esp_idf_svc::log::EspLogger::initialize_default();

    let peripherals = Peripherals::take().unwrap();
    let sda = peripherals.pins.gpio2;
    let scl = peripherals.pins.gpio3;
    let config = I2cConfig::new().baudrate(400_u32.kHz().into());
    let i2c = I2cDriver::new(peripherals.i2c0, sda, scl, &config).unwrap();
    let mut bme280 = BME280::new_primary(i2c);
    let mut delay = delay::Ets;

    bme280.init(&mut delay);

    loop {
        let measurements = bme280.measure(&mut delay).unwrap();

        log::info!("Relative Humidity = {}%", measurements.humidity);
        log::info!("Temperature = {} deg C", measurements.temperature);
        log::info!("Pressure = {} pascals", measurements.pressure);
        delay::FreeRtos::delay_ms(10000u32);
    }
}

And I get this error:

thread 'main' panicked at src/main.rs:40:55:
called `Result::unwrap()` on an `Err` value: InvalidData

It panics here:

let measurements = bme280.measure(&mut delay).unwrap();

It's strange because this almost identical code works:

#![no_std]
#![no_main]

use bme280::i2c::BME280;
use esp32c3_hal::{clock::ClockControl, i2c::I2C, peripherals::Peripherals, prelude::*, Delay, IO};
use esp_backtrace as _;
use esp_println::println;

#[entry]
fn main() -> ! {
    let peripherals = Peripherals::take();
    let system = peripherals.SYSTEM.split();
    let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
    let mut delay = Delay::new(&clocks);
    let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
    let sda = io.pins.gpio2;
    let scl = io.pins.gpio3;
    let i2c = I2C::new(peripherals.I2C0, sda, scl, 400u32.kHz(), &clocks);
    let mut bme280 = BME280::new_primary(i2c);

    bme280.init(&mut delay).unwrap();

    loop {
        let measurements = bme280.measure(&mut delay).unwrap();
        println!("Relative Humidity = {}%", measurements.humidity);
        println!("Temperature = {} deg C", measurements.temperature);
        println!("Pressure = {} pascals", measurements.pressure);
        delay.delay_ms(1000u32);
    }
}

What could be the issue with the first code?

Ability to configure oversampling and IIR filter

Hey,

looking through the source, the configure function sets a bunch of options, notably the oversampling and IIR filter settings.
For our application, it'd be nice to change those, especially the IIR filter, since we're using this for something like weather monitoring, with a very low sample rate.
Any chance you could add a parameter for configuration values to init, maybe?

Best,
Leo

I2C address inconsistency

hey thanks for making a neat library!

i notice in the docs the primary address is listed as 0x77 with secondary as 0x78, whereas afaik in the datasheet this should be 0x77 and 0x76, and in the constants primary is set to 0x76 and secondary is set to 0x77 which is inconsistent with the documentation.

i was a bit bamboozled until i manually set the address. can open a PR but i’m not sure which way around you’d prefer to fix this?

Driver panics when trying to make a measurement with BME280

Hey!
I love your library, looks overall pretty clean. However, I'm struggling to spin it up. I created a simple program (very similar to your example) running on the STM32F407. Everything works fine (temperature and pressure is calculated correctly) with bmp280_ehal driver as BME280 is backward compatible (somewhat) to BMP280. It's downside is that it lacks humidity support.

When trying to use your library, it panics when it tries to make a measurement (bme280::BME280::measure()) - after query to device and applying compensations, pressure appears to be equal 0, so condition is not fulfilled and panic is raised here

Sample source code

#![no_std]
#![no_main]

extern crate panic_halt;
extern crate stm32f4;
use cortex_m_rt::entry;
use stm32f4xx_hal::i2c::I2c;
use stm32f4xx_hal::gpio::GpioExt;
use stm32f4xx_hal::rcc::RccExt;
use stm32f4xx_hal::time::U32Ext;

#[entry]
fn main() -> ! {
    let stm32_specific_peripherals = stm32f4::stm32f407::Peripherals::take().unwrap();
    let cortex_m_peripherals = cortex_m::Peripherals::take().unwrap();
    let clocks = stm32_specific_peripherals.RCC.constrain().cfgr.sysclk(168.mhz()).freeze();

    // I2C
    let gpiob = stm32_specific_peripherals.GPIOB.split();
    let i2c = I2c::i2c1(
        stm32_specific_peripherals.I2C1,
        (gpiob.pb6.into_alternate_af4_open_drain(), gpiob.pb7.into_alternate_af4_open_drain()),
        400.khz(),
        clocks,
    );

    let delay_provider = stm32f4xx_hal::delay::Delay::new(cortex_m_peripherals.SYST, clocks);
    let mut bme280 = bme280::BME280::new_primary(i2c, delay_provider);
    bme280.init().unwrap();

    loop {
        let measurements = bme280.measure().unwrap();
        // .. do stuff
    }
}

There's a zipped Logic Saleae I2C transmission capture dump provided in attachment that might contain some helpful info regarding issue: i2c_communication.zip

If you were to just point me to the right direction, I'd be very grateful. Thank you for your help!

New Release?

Hello again :)

Would it be possible to cut a new release some time? I'm eager to try out those new oversampling and IIR filter settings...

Best

Build fails for ESP32

Trying to build (use) bme280-rs with my project. The build fails with the following error.

error[E0432]: unresolved import `embedded_hal::spi::blocking::Transfer`
 --> /home/ed/.cargo/registry/src/github.com-1ecc6299db9ec823/bme280-0.4.1/src/spi.rs:5:5
  |
5 | use embedded_hal::spi::blocking::Transfer;
  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no `Transfer` in `spi::blocking`

For more information about this error, try `rustc --explain E0432`.
error: could not compile `bme280` due to previous error

When I look at my cargo.lock file I see the following.

[[package]]
name = "bme280"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "afa0ec59ce7903e8f6678855e70140b78f2d7a047d5afadf7b14266b020799ae"
dependencies = [
 "embedded-hal 1.0.0-alpha.8",
]
  1. It looks like embedded-hal 1.0.0-aplha.8 is being used.
  2. When I look at embedded-hal 1.0.0-alpha.8 for spi blocking there is no trait Transfer. In embedded-hal 1.0.0-alpha.7 there is a Transfer trait. I may be looking at this wrong since I am new to rust.
  3. In bme280-rs git hub repository the cargo.toml list the dependency for embedded-hal = 1.0.0-alpha.7.
  4. I am new to rust. So how do I make my cargo.toml make bme280-rs use embedded-hal = 1.0.0-alpha.7 and not embedded-hal = 1.0.0-alpha.8 if the problem really is because of version 1.0.0-alpha.8 ?

For my project I am using I2c and not spi for the bme280 device.

failed to select a version for `embedded-hal`

I generated a project with this: https://github.com/esp-rs/esp-template (I selected esp32-c3).

Then I added bme280 (0.5.0) to my Cargo.toml. Then I built. I got this error:

error: failed to select a version for `embedded-hal`.
    ... required by package `embassy-time v0.2.0`
    ... which satisfies dependency `embassy-time = "^0.2"` of package `embassy-executor v0.4.0`
    ... which satisfies dependency `embassy-executor = "^0.4.0"` of package `esp-hal-common v0.14.0`
    ... which satisfies dependency `esp-hal-common = "^0.14.0"` of package `esp32c3-hal v0.14.0`
    ... which satisfies dependency `esp32c3-hal = "^0.14.0"` of package `esp-test v0.1.0 (/home/weiying-chen/rust/esp-test)`
versions that meet the requirements `=1.0.0-rc.2` are: 1.0.0-rc.2

all possible versions conflict with previously selected packages.

  previously selected package `embedded-hal v1.0.0`
    ... which satisfies dependency `embedded-hal = "^1.0.0"` of package `bme280 v0.5.0`
    ... which satisfies dependency `bme280 = "^0.5.0"` of package `esp-test v0.1.0 (/home/weiying-chen/rust/esp-test)`

failed to select a version for `embedded-hal` which could resolve this conflict

What could be the issue?

Supporting BMP280

Hi!

I have a BMP280, with is basically a BME280 without humidity. Your driver is working by just allowing CHIP_ID == 0x58, humidity is outputed to 0%.

It could be great to support this sensor. I can make the modifications and test on the BMP280, but we need to choose how to support it:

  • just allowing 0x58
  • add a mode for only temperature and pressure
  • managing the 2 chips, and BMP can only di temperature and pressure, when BME can do temerature and pressure, or temperature, pressure and humidity.
  • something else.

What do you think?

RTIC example?

Hi!
I am struggling to use this driver with RTIC because of delay provider.
What is the best way to use this library with RTIC?

Allow sharing the I2C bus.

The driver should allow sharing the bus with other devices. Other drivers provide one of two mechanisms for this:

  1. Allowing the user to "uninitialize" the device again and regain access to the underlying objects. I have implemented this approach at https://github.com/mgottschlag/bme280-rs/tree/destroy (on top of on #6). This approach might have advantages in certain scenarios if it allows better power management (it both allows the user to reinitialize the device, e.g., after temporary power supply deactivation, and allows the HAL to reinitialize the bus when required by low-power modes).

  2. Passing the bus object as a mutable reference to all functions requiring it. This approach is used, for example, by the (epd_waveshare)[https://github.com/caemor/epd-waveshare] crate. This approach is vastly superior in that it does not require reinitialization of the device over and over again.

Maybe both should be provided, as each has its potential use cases.

SPI communication doesn't work

The following code is not right, as it would require the data to be prepended with a dummy byte

impl<SPI, CS> SPIInterface<SPI, CS>
where
    SPI: Transfer<u8>,
    CS: OutputPin,
{
    fn read_any_register(
        &mut self,
        register: u8,
        data: &mut [u8],
    ) -> Result<(), Error<SPIError<SPI::Error, CS::Error>>> {
        self.cs
            .set_low()
            .map_err(|e| Error::Bus(SPIError::Pin(e)))?;
        self.spi
            .transfer(data, &[register])
            .map_err(|e| Error::Bus(SPIError::SPI(e)))?;
        self.cs
            .set_high()
            .map_err(|e| Error::Bus(SPIError::Pin(e)))?;
        Ok(())
    }
}

Spitting the transfer would do the job:

bus.write(&[register])?;
bus.read(data)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.