rtic-rs / rtic

Real-Time Interrupt-driven Concurrency (RTIC) framework for ARM Cortex-M microcontrollers

Home Page:https://rtic.rs

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

broken usage example for i2c sharing

pdgilbert opened this issue · comments

I have been trying to compile the Arbiter i2c usage example in rtic-rs/rtic/rtic-sync/src/arbiter.rs. It has some typos which suggest it has never been tested. With some fixes and adjustments for different hals I have made progress but have a problem with an unsatisfied trait bounds for &mut Ens160<ArbiterDevice<'static, I2c<I2C1>>>. I have tried with both release and git versions of rtic-sync and also tried with both stm32f4xx_hal and a version of stm32g4xx_hal that uses embedded-hal-1.0.0. I think the problem is possibly a bug in rtic-sync or elsewhere, but maybe that I am just not bringing the proper trait into scope. Below are results for the git versions using stm32f4xx_hal.

Click to expand code
// I2C bus sharing using [`Arbiter`]
//
// An Example how to use it in RTIC application:

#![deny(unsafe_code)]
#![no_std]
#![no_main]
#![feature(type_alias_impl_trait)]

#[cfg(debug_assertions)]
use panic_semihosting as _;

#[cfg(not(debug_assertions))]
use panic_halt as _;

use rtic::app;

#[cfg_attr(feature = "stm32f4xx", app(device = stm32f4xx_hal::pac,   dispatchers = [TIM2, TIM3]))]

mod app {
    use core::mem::MaybeUninit;
    use rtic_sync::arbiter::{i2c::ArbiterDevice, Arbiter};

    // Instantiate an Arbiter with a static lifetime.
    static ARBITER: Arbiter<u32> = Arbiter::new(32);

    use ens160::{Ens160, AirQualityIndex, ECo2};

    pub use stm32f4xx_hal::{
       pac::{I2C1, TIM2, TIM5},
       i2c::I2c,
       gpio::GpioExt,
       rcc::{Clocks, RccExt},
       timer::TimerExt,
       prelude::*,
    };

    pub type I2c1Type = I2c<I2C1>;

    #[shared]
    struct Shared {}

    #[local]
    struct Local {
        ens160: Ens160<ArbiterDevice<'static, I2c1Type>>,
    }

    #[init(local = [
        i2c_arbiter: MaybeUninit<Arbiter<I2c1Type>> = MaybeUninit::uninit(),
    ])]
    fn init(cx: init::Context) -> (Shared, Local) {

        let rcc = cx.device.RCC.constrain();
        let clocks = rcc.cfgr.freeze();

        let gpiob = cx.device.GPIOB.split();
        let scl = gpiob.pb8.into_alternate_open_drain(); 
        let sda = gpiob.pb9.into_alternate_open_drain(); 

        let i2c = I2c::new(cx.device.I2C1, (scl, sda), 400.kHz(), &clocks);

        let i2c_arbiter = cx.local.i2c_arbiter.write(Arbiter::new(i2c));
        let ens160 = Ens160::new(ArbiterDevice::new(i2c_arbiter), 0x52);

        i2c_sensors::spawn(i2c_arbiter).ok();

        (Shared {}, Local { ens160 })
    }

    #[task(local = [ens160])]
    async fn i2c_sensors(cx: i2c_sensors::Context, i2c: &'static Arbiter<I2c1Type>) {
    //async fn i2c_sensors(cx: i2c_sensors::Context, i2c: &'static Arbiter<I2c<'static, I2c1Type>>) {
        loop {
            // Read ENS160 sensor.
            let eco2 = cx.local.ens160.eco2().await;
        }
    }
}
Click to expand compiling error
$ cargo build --no-default-features --target thumbv7em-none-eabihf --features stm32f411,stm32f4xx --example ens160_f4
   Compiling rust-integration-testing-of-examples v0.3.0 (dev-testing)
warning: unused imports: `AirQualityIndex`, `ECo2`
  --> examples/ens160_f4.rs:27:26
   |
27 |     use ens160::{Ens160, AirQualityIndex, ECo2};
   |                          ^^^^^^^^^^^^^^^  ^^^^
   |
   = note: `#[warn(unused_imports)]` on by default

error[E0599]: the method `eco2` exists for mutable reference `&mut Ens160<ArbiterDevice<'static, I2c<I2C1>>>`, but its trait bounds were not satisfied
   --> examples/ens160_f4.rs:75:40
    |
75  |             let eco2 = cx.local.ens160.eco2().await;
    |                                        ^^^^ method cannot be called on `&mut Ens160<ArbiterDevice<'static, I2c<I2C1>>>` due to unsatisfied trait bounds
    |
   ::: /home/paul/.cargo/git/checkouts/rtic-98d87eafbe677b11/22ac33a/rtic-sync/src/arbiter.rs:330:5
    |
330 |     pub struct ArbiterDevice<'a, BUS> {
    |     --------------------------------- doesn't satisfy `_: I2c`
    |
    = note: the full type name has been written to 'dev-testing/target/thumbv7em-none-eabihf/debug/examples/ens160_f4-64d1daf9f661405a.long-type-16809872599107602039.txt'
    = note: the following trait bounds were not satisfied:
            `rtic_sync::arbiter::i2c::ArbiterDevice<'static, stm32f4xx_hal::i2c::I2c<I2C1>>: stm32f4xx_hal::embedded_hal::i2c::I2c`

For more information about this error, try `rustc --explain E0599`.
warning: `rust-integration-testing-of-examples` (example "ens160_f4") generated 1 warning
error: could not compile `rust-integration-testing-of-examples` (example "ens160_f4") due to 1 previous error; 1 warning emitted

Is this a bug or am I missing something simple?

(This issue is somewhat related to #886 where @perlindgren and @korken89 suggested this example.)

Hi,

The error you are getting is because the trait I2c is the async trait.
You seem to be providing a sync implementation. Hope that helps!

Thanks @korken89. I'm new to many pieces of this, so pretty confused. I think you are suggesting I should

use embedded_hal_async::i2c::I2c;

rather than

use stm32f4xx_hal::i2c::I2c;

If so, that gets me back to all the errors that had me looking for a working example of arbiter with embedded-hal 1.0 and rtic. Is the example in rtic-sync (https://github.com/rtic-rs/rtic/blob/master/rtic-sync/src/arbiter.rs#L276) supposed to use an async I2c trait?

A pointer to a working stm32*-hal arbiter example would be helpful, for me and in documentation. Actually, any working example of embedded-hal 1.0, rtic v2 ,stm32*-hal with shared I2C bus would help me. (I have lots of rtic shared I2C bus examples that do not work after shifting to embedded-hal 1.0.)

@pdgilbert have you managed to make Arbiter work and have shared access to I2C? If so, could you please open a PR with an example?

No I have not got Arbiter compiling. I finally had to put it aside to do other work, and was hoping someone else would get a working usage example. Shared access to an I2C bus in rtic is the main broken piece in my crate/hal testing with eh-1 (https://github.com/pdgilbert/rust-integration-testing/actions/) . In testing with stm32g4xx_hal I have 68 examples compiling of the 72 I had compiling prior to switching to eh-1. The 5 failing are because of this problem. In testing with stm32f4xx_hal I have 61 examples compiling of the 72. The additional failures are because stm32f4xx_hal does not yet support eh-1 Read/Write style. (Someone please correct me if I am wrong on that.) Also beware that hardware testing suggests that "compiling" is not the same as "working".