Rahix / shared-bus

Crate for sharing buses between multiple devices
Apache License 2.0
129 stars 34 forks source link

Errors using shared-bus with ESP32 (esp_idf_hal and bme280-rs) #34

Closed enelson1001 closed 2 years ago

enelson1001 commented 2 years ago

I am trying to use shared-bus with ESP32 using esp_idf_hal and bme280-rs. If I don't use shared-bus I have no problems using bme280.

Code with problems

use esp_idf_hal::delay;
use esp_idf_hal::i2c;
use esp_idf_hal::prelude::*;
use esp_idf_sys as _; // If using the `binstart` feature of `esp-idf-sys`, always keep this module imported

use log::*;

use bme280::i2c::BME280;

fn main() {
    esp_idf_sys::link_patches();

    // Bind the log crate to the ESP Logging facilities
    esp_idf_svc::log::EspLogger::initialize_default();

    let peripherals = Peripherals::take().unwrap();
    let pins = peripherals.pins;

    // Create i2c interface on I2C0 with bus speed of 400kHz
    let i2c0 = peripherals.i2c0;
    let scl = pins.gpio22;
    let sda = pins.gpio21;
    let i2c_config = <i2c::config::MasterConfig as Default>::default().baudrate(400.kHz().into());

    let i2c_bus_0 = i2c::Master::<i2c::I2C0, _, _>::new(i2c0, i2c::MasterPins { sda, scl }, i2c_config).unwrap();

    let i2c_bus_manager = shared_bus::BusManagerSimple::new(i2c_bus_0);

    let mut i2c_bme280 = BME280::new_primary(i2c_bus_manager.acquire_i2c());  <-----ERROR HERE
    //let mut i2c_bme280 = BME280::new_primary(i2c_bus_0);  <---- This works fine no ERRORS when not using shared-bus

    let mut delay = delay::Ets;
    i2c_bme280.init(&mut delay).unwrap();    <---ERROR HERE

Errors

error[E0277]: the trait bound `I2cProxy<'_, NullMutex<esp_idf_hal::i2c::Master<I2C0, esp_idf_hal::gpio::Gpio21<esp_idf_hal::gpio::Unknown>, esp_idf_hal::gpio::Gpio22<esp_idf_hal::gpio::Unknown>>>>: embedded_hal::i2c::blocking::I2c` is not satisfied
  --> src/main.rs:46:46
   |
46 |     let mut i2c_bme280 = BME280::new_primary(i2c_bus_manager.acquire_i2c());
   |                          ------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `embedded_hal::i2c::blocking::I2c` is not implemented for `I2cProxy<'_, NullMutex<esp_idf_hal::i2c::Master<I2C0, esp_idf_hal::gpio::Gpio21<esp_idf_hal::gpio::Unknown>, esp_idf_hal::gpio::Gpio22<esp_idf_hal::gpio::Unknown>>>>`
   |                          |
   |                          required by a bound introduced by this call
   |
note: required by a bound in `bme280::i2c::BME280::<I2C>::new_primary`
  --> /home/ed/rust-crates/bme280-rs/src/i2c.rs:22:10
   |
22 |     I2C: I2c + ErrorType,
   |          ^^^ required by this bound in `bme280::i2c::BME280::<I2C>::new_primary`

error[E0599]: the method `init` exists for struct `bme280::i2c::BME280<I2cProxy<'_, NullMutex<esp_idf_hal::i2c::Master<I2C0, esp_idf_hal::gpio::Gpio21<esp_idf_hal::gpio::Unknown>, esp_idf_hal::gpio::Gpio22<esp_idf_hal::gpio::Unknown>>>>>`, but its trait bounds were not satisfied
  --> src/main.rs:49:16
   |
49 |     i2c_bme280.init(&mut delay).unwrap();
   |                ^^^^ method cannot be called on `bme280::i2c::BME280<I2cProxy<'_, NullMutex<esp_idf_hal::i2c::Master<I2C0, esp_idf_hal::gpio::Gpio21<esp_idf_hal::gpio::Unknown>, esp_idf_hal::gpio::Gpio22<esp_idf_hal::gpio::Unknown>>>>>` due to unsatisfied trait bounds
   |
  ::: /home/ed/.cargo/registry/src/github.com-1ecc6299db9ec823/shared-bus-0.2.3/src/proxies.rs:15:1
   |
15 | pub struct I2cProxy<'a, M> {
   | --------------------------
   | |
   | doesn't satisfy `_: embedded_hal::i2c::ErrorType`
   | doesn't satisfy `_: embedded_hal::i2c::blocking::I2c`
   |
   = note: the following trait bounds were not satisfied:
           `I2cProxy<'_, NullMutex<esp_idf_hal::i2c::Master<I2C0, esp_idf_hal::gpio::Gpio21<esp_idf_hal::gpio::Unknown>, esp_idf_hal::gpio::Gpio22<esp_idf_hal::gpio::Unknown>>>>: embedded_hal::i2c::blocking::I2c`
           `I2cProxy<'_, NullMutex<esp_idf_hal::i2c::Master<I2C0, esp_idf_hal::gpio::Gpio21<esp_idf_hal::gpio::Unknown>, esp_idf_hal::gpio::Gpio22<esp_idf_hal::gpio::Unknown>>>>: embedded_hal::i2c::ErrorType`

How can I make shared-bus work with esp_idf_hal and bme280-rs?

Rahix commented 2 years ago

The problem is here:

https://github.com/VersBinarii/bme280-rs/blob/1c8b587e83167bbf3d43ed9e5331f6846bf1927c/Cargo.toml#L16

bme280-rs is already using the embedded-hal 1.0 alpha version which is not yet supported here in shared-bus unfortunately (we're still on 0.2.x). This is in the works but I don't have anything ready yet...

Rahix commented 2 years ago

Pull-request #36 should help. I added support for the latest embedded-hal alpha's I2C traits over there. However, your dependencies are still on alpha.7 while the latest release is alpha.8 so you'll have to get them update first as well.

Rahix commented 2 years ago

Please let me know once you've tested this, I'll then merge the PR and publish a new release.

enelson1001 commented 2 years ago

I have updated bme280-rs locally to use alpha.8. Does PR#36 support alpha.8 as esp_idf_hal requires alpha.8.

Thanks

Rahix commented 2 years ago

https://github.com/Rahix/shared-bus/blob/049f206fc6504337494aa3238465d1add6730f83/Cargo.toml#L27

enelson1001 commented 2 years ago

This is what I did

  1. Modified my project cargo.toml with the following.

    shared-bus = {git = "https://github.com/Rahix/shared-bus.git", version = "0.2.3", branch = "i2c-eh-alpha", features = ["eh-alpha"]}

    My code in main:

    let peripherals = Peripherals::take().unwrap();
    let pins = peripherals.pins;
    
    // Create i2c interface on I2C0 with bus speed of 400kHz
    let i2c0 = peripherals.i2c0;
    let scl = pins.gpio22;
    let sda = pins.gpio21;
    let i2c_config = <i2c::config::MasterConfig as Default>::default().baudrate(400.kHz().into());
    let i2c_bus_0 = i2c::Master::<i2c::I2C0, _, _>::new(i2c0, i2c::MasterPins { sda, scl }, i2c_config).unwrap();
    
    let i2c_bus_manager = shared_bus::BusManagerSimple::new(i2c_bus_0);
    let mut i2c_bme280 = BME280::new_primary(i2c_bus_manager.acquire_i2c());
    
    //let mut i2c_bme280 = BME280::new_primary(i2c_bus_0);
    let mut delay = delay::Ets;
    i2c_bme280.init(&mut delay).unwrap();
    
    thread::sleep(Duration::from_millis(5000));
    let mut count = 0;
    
    loop {
        let measurements = i2c_bme280.measure(&mut delay).unwrap();
        println!("Relative Humidity = {}%", measurements.humidity);
        println!("Temperature = {} deg C", measurements.temperature);
        println!("Pressure = {} pascals", measurements.pressure);
    
        count += 1;
    
        thread::sleep(Duration::from_millis(5000));
    
        if count == 5 {
            break;
        }
    }

    And now everything works (I haven't shared bus with SSD1306 display yet but will do shortly)

  2. One question - We can't pass i2c_bus_manager as a reference correct? But we can make static?

thanks

Rahix commented 2 years ago

Great, thanks for testing! I'll get the PR merged.

One question - We can't pass i2c_bus_manager as a reference correct? But we can make static?

Please open a new issue and describe in more detail what you need.