Skip to content
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

sandwiched eh versions failure #722

Closed
pdgilbert opened this issue Jan 5, 2024 · 4 comments
Closed

sandwiched eh versions failure #722

pdgilbert opened this issue Jan 5, 2024 · 4 comments

Comments

@pdgilbert
Copy link
Contributor

I have been testing embedded-hal-1.0.0-rc3 with relatively good results in many examples, using stm32f4xx_hal and stm32h7xx_hal. Of course many of my examples use crates which do not have a embedded-hal-1.0.0-rc3 version. Thus, they fail with stm32h7xx_hal because it does not have the magic dual embedded-hal version suport. (OTOH, that highlights the device crates that do not yet support embedded-hal-1.0.0.)

One problem I have encountered with stm32f4xx_hal is when shared-bus with embedded-hal = "0.2.3" is sandwiched between my embedded-hal-1.0.0 code and an embedded-hal-1.0.0-rc3 version of the ssd1306 display driver. I use this driver in several examples. From details below I hope someone can confirm if I am missing something simple. Also, if anyone is aware of a shared-bus with embedded-hal = "1.0.0-rc3" please point me to it. (I have tried @TeyKey1 's fork at https://github.com/TeyKey1/shared-bus" but I don't think it is working yet - please correct me if I am wrong.)

Below is code simplified from an example that does not necessarily need shared-bus. The code works when shared-bus is omitted and fails when it is included. The error is

Click to expand error messages
error[E0277]: the trait bound `I2cProxy<'static, cortex_m::interrupt::Mutex<RefCell<stm32f4xx_hal::i2c::I2c<I2C1>>>>: embedded_hal::i2c::I2c` is not satisfied
   --> examples/zzdisplay_stuff_rtic2.rs:194:25
    |
194 |            show_display(cx.local.display);
    |            ------------ ^^^^^^^^^^^^^^^^ the trait `embedded_hal::i2c::I2c` is not implemented for `I2cProxy<'static, cortex_m::interrupt::Mutex<RefCell<stm32f4xx_hal::i2c::I2c<I2C1>>>>`
    |            |
    |            required by a bound introduced by this call
    |
    = help: the following other types implement trait `embedded_hal::i2c::I2c<A>`:
              <I2cStub as embedded_hal::i2c::I2c>
              <stm32f4xx_hal::i2c::I2c<I2C> as embedded_hal::i2c::I2c>
              <&mut T as embedded_hal::i2c::I2c<A>>
    = note: required for `I2CInterface<I2cProxy<'static, Mutex<RefCell<I2c<I2C1>>>>>` to implement `ssd1306::prelude::WriteOnlyDataCommand`
    = note: the full type name has been written to '/home/paul/githubClones/rust-integration-testing/dev-testing/target/thumbv7em-none-eabihf/debug/examples/zzdisplay_stuff_rtic2-a07c81e330eef225.long-type-4472187899878778957.txt'
note: required by a bound in `show_display`
   --> examples/zzdisplay_stuff_rtic2.rs:107:33
    |
106 |     fn show_display<S>(
    |        ------------ required by a bound in this function
107 |         disp: &mut Ssd1306<impl WriteOnlyDataCommand, S, BufferedGraphicsMode<S>>,
    |                                 ^^^^^^^^^^^^^^^^^^^^ required by this bound in `show_display`

error[E0599]: the method `flush` exists for mutable reference `&mut Ssd1306<I2CInterface<I2cProxy<'static, Mutex<...>>>, ..., ...>`, but its trait bounds were not satisfied
   --> examples/zzdisplay_stuff_rtic2.rs:211:29
    |
211 |            cx.local.display.flush().unwrap();
    |                             ^^^^^ method cannot be called due to unsatisfied trait bounds
    |
   ::: /home/paul/.cargo/git/checkouts/display-interface-671cffc841c04cf5/0ed9dc9/i2c/src/lib.rs:10:1
    |
10  | pub struct I2CInterface<I2C> {
    | ---------------------------- doesn't satisfy `_: WriteOnlyDataCommand`
    |
    = note: the full type name has been written to '/home/paul/githubClones/rust-integration-testing/dev-testing/target/thumbv7em-none-eabihf/debug/examples/zzdisplay_stuff_rtic2-a07c81e330eef225.long-type-10539551830589570764.txt'
    = note: the following trait bounds were not satisfied:
            `I2CInterface<I2cProxy<'static, cortex_m::interrupt::Mutex<RefCell<stm32f4xx_hal::i2c::I2c<I2C1>>>>>: ssd1306::prelude::WriteOnlyDataCommand`

error[E0277]: the trait bound `I2cProxy<'_, cortex_m::interrupt::Mutex<RefCell<stm32f4xx_hal::i2c::I2c<I2C1>>>>: embedded_hal::i2c::I2c` is not satisfied
   --> examples/zzdisplay_stuff_rtic2.rs:152:49
    |
152 |        let interface = I2CDisplayInterface::new(manager.acquire_i2c());
    |                        ------------------------ ^^^^^^^^^^^^^^^^^^^^^ the trait `embedded_hal::i2c::I2c` is not implemented for `I2cProxy<'_, cortex_m::interrupt::Mutex<RefCell<stm32f4xx_hal::i2c::I2c<I2C1>>>>`
    |                        |
    |                        required by a bound introduced by this call
    |
    = help: the following other types implement trait `embedded_hal::i2c::I2c<A>`:
              <I2cStub as embedded_hal::i2c::I2c>
              <stm32f4xx_hal::i2c::I2c<I2C> as embedded_hal::i2c::I2c>
              <&mut T as embedded_hal::i2c::I2c<A>>
note: required by a bound in `I2CDisplayInterface::new`
   --> /home/paul/.cargo/git/checkouts/ssd1306-407b1a92e31533f1/c019ef1/src/i2c_interface.rs:15:12
    |
13  |     pub fn new<I>(i2c: I) -> I2CInterface<I>
    |            --- required by a bound in this associated function
14  |     where
15  |         I: embedded_hal::i2c::I2c,
    |            ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `I2CDisplayInterface::new`

error[E0599]: the method `init` exists for struct `Ssd1306<I2CInterface<I2cProxy<'_, Mutex<RefCell<...>>>>, ..., ...>`, but its trait bounds were not satisfied
   --> examples/zzdisplay_stuff_rtic2.rs:161:16
    |
161 |        display.init().unwrap();
    |                ^^^^ method cannot be called due to unsatisfied trait bounds
    |
   ::: /home/paul/.cargo/git/checkouts/ssd1306-407b1a92e31533f1/c019ef1/src/lib.rs:139:1
    |
139 | pub struct Ssd1306<DI, SIZE, MODE> {
    | ---------------------------------- doesn't satisfy `_: DisplayConfig`
    |
   ::: /home/paul/.cargo/git/checkouts/display-interface-671cffc841c04cf5/0ed9dc9/i2c/src/lib.rs:10:1
    |
10  | pub struct I2CInterface<I2C> {
    | ---------------------------- doesn't satisfy `_: WriteOnlyDataCommand`
    |
    = note: the full type name has been written to '/home/paul/githubClones/rust-integration-testing/dev-testing/target/thumbv7em-none-eabihf/debug/examples/zzdisplay_stuff_rtic2-a07c81e330eef225.long-type-1568608426302395845.txt'
    = note: the following trait bounds were not satisfied:
            `I2CInterface<I2cProxy<'_, cortex_m::interrupt::Mutex<RefCell<stm32f4xx_hal::i2c::I2c<I2C1>>>>>: ssd1306::prelude::WriteOnlyDataCommand`
            which is required by `Ssd1306<I2CInterface<I2cProxy<'_, cortex_m::interrupt::Mutex<RefCell<stm32f4xx_hal::i2c::I2c<I2C1>>>>>, ssd1306::prelude::DisplaySize128x64, BufferedGraphicsMode<ssd1306::prelude::DisplaySize128x64>>: ssd1306::mode::DisplayConfig`

Some errors have detailed explanations: E0277, E0599.
For more information about an error, try `rustc --explain E0277`.
error: could not compile `rust-integration-testing-of-examples` (example "zzdisplay_stuff_rtic2") due to 4 previous errors

I compile with

cargo build --no-default-features --target thumbv7em-none-eabihf --features stm32f401,stm32f4xx --example zzdisplay_stuff_rtic2

The embedded-hal-1.0.0-rc3 hal and crate branches I have been using are

stm32f4xx-hal = { git = "https://github.com/stm32-rs/stm32f4xx-hal", optional = true } 
stm32h7xx-hal = { git = "https://github.com/stm32-rs/stm32h7xx-hal", optional = true , branch = "eh-v1.0"}
ssd1306       = { git = "https://github.com/bugadani/ssd1306", branch = "ehal1"  }  
one-wire-bus  = { git = "https://github.com/daniel-larsen/one-wire-bus" }

The example code is

Click to expand code
//! Display "stuff" on OLED with i2c.

#![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]))]
#[cfg_attr(feature = "stm32h7xx", app(device = stm32h7xx_hal::pac,   dispatchers = [TIM2, TIM3]))]

mod app {

    use embedded_graphics::{
        mono_font::{iso_8859_1::FONT_10X20, MonoTextStyleBuilder},  //FONT_6X10  FONT_8X13
        pixelcolor::BinaryColor,
        prelude::*,
        text::{Baseline, Text},
    };

    use ssd1306::{mode::BufferedGraphicsMode, prelude::I2CInterface, prelude::*, I2CDisplayInterface, Ssd1306};

    use rtic;
    use rtic_monotonics::systick::Systick;
    use rtic_monotonics::systick::fugit::{ExtU32};

    use core::fmt::Write;

    const READ_INTERVAL: u32 = 10;  // used as seconds

    const BLINK_DURATION: u32 = 20;  // used as milliseconds

    #[cfg(feature = "stm32f4xx")]
    pub const MONOCLOCK: u32 = 16_000_000; //should be set for board not for HAL

    #[cfg(feature = "stm32h7xx")]
    pub const MONOCLOCK: u32 = 8_000_000; //should be set for board not for HAL


    #[cfg(feature = "stm32f4xx")]
    use stm32f4xx_hal as hal;
    
    #[cfg(feature = "stm32h7xx")]
    use stm32h7xx_hal as hal;
    
    use hal::{
        pac::{Peripherals, I2C1},
        rcc::RccExt,
        i2c::I2c,
        gpio::GpioExt,
        prelude::*,  // otherwise 400.kHz() gives "you must specify a concrete type"
    };




    type I2cType = I2c<I2C1>;

    #[cfg(feature = "stm32f4xx")]
    fn setup(dp: Peripherals) ->  I2cType {
       let gpiob = dp.GPIOB.split();
    
       let rcc = dp.RCC.constrain();
       let clocks = rcc.cfgr.freeze();
    
       let scl = gpiob.pb8.into_alternate_open_drain(); 
       let sda = gpiob.pb9.into_alternate_open_drain(); 

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

    #[cfg(feature = "stm32h7xx")]
    pub fn setup(dp: Peripherals) ->  I2cType {
       let pwr = dp.PWR.constrain();
       let vos = pwr.freeze();
       let rcc = dp.RCC.constrain();
       let ccdr = rcc.sys_ck(100.MHz()).freeze(vos, &dp.SYSCFG); // calibrate for correct blink rate
       let clocks = ccdr.clocks;
    
       let gpiob = dp.GPIOB.split(ccdr.peripheral.GPIOB);
        
       let scl = gpiob.pb8.into_alternate().set_open_drain();
       let sda = gpiob.pb9.into_alternate().set_open_drain();

       // should work?  let i2c = I2c::new(dp.I2C1, (scl, sda), 100.kHz(), ccdr.peripheral.I2C1, &clocks);
       let i2c =  dp.I2C1.i2c( (scl, sda), 100.kHz(), ccdr.peripheral.I2C1, &clocks);

       i2c
    }


    use shared_bus::{I2cProxy};
    use core::cell::RefCell;
    use cortex_m::interrupt::Mutex;


    fn show_display<S>(
        disp: &mut Ssd1306<impl WriteOnlyDataCommand, S, BufferedGraphicsMode<S>>,
    ) -> ()
    where
        S: DisplaySize,
    {
       let mut lines: [heapless::String<32>; 5] = [heapless::String::new(),  //should be a better way
                                                   heapless::String::new(),
                                                   heapless::String::new(),
                                                   heapless::String::new(),
                                                   heapless::String::new(),];
       lines[0] = "s".into();
       lines[1] = "t".into();
       lines[2] = "u".into();
       lines[3] = "f".into();
       lines[4] = "f".into();

       // should not be necessary to do this every call but have not yet managed to pass it as an arg
       let text_style = MonoTextStyleBuilder::new().font(&FONT_10X20).text_color(BinaryColor::On).build();
    
       disp.clear_buffer();
       for i in 0..lines.len() {
           // start from 0 requires that the top is used for font baseline
           Text::with_baseline(
               &lines[i],
               Point::new(0, i as i32 * 12), //with font 6x10, 12 = 10 high + 2 space
               text_style,
               Baseline::Top,
           )
           .draw(&mut *disp)
           .unwrap();
       }
       disp.flush().unwrap();
       ()
    }


    #[init]
    fn init(cx: init::Context) -> (Shared, Local ) {

       let mono_token = rtic_monotonics::create_systick_token!();
       Systick::start(cx.core.SYST, MONOCLOCK, mono_token);

       let i2c = setup(cx.device);

       let manager: &'static _ = shared_bus::new_cortexm!(I2cType = i2c).unwrap();
       let interface = I2CDisplayInterface::new(manager.acquire_i2c());

       //let interface = I2CDisplayInterface::new(i2c);

       let text_style = MonoTextStyleBuilder::new().font(&FONT_10X20).text_color(BinaryColor::On).build();

       let mut display = Ssd1306::new(interface, DisplaySize128x64, DisplayRotation::Rotate0)
          .into_buffered_graphics_mode();

       display.init().unwrap();

       Text::with_baseline("Display initialized ...", Point::zero(), text_style, Baseline::Top, )
          .draw(&mut display).unwrap();

       display_stuff::spawn().unwrap();

       (Shared { }, Local { display })
    }

    #[shared]
    struct Shared { }
 

    #[local]
    struct Local {
        display:  Ssd1306<I2CInterface<I2cProxy<'static, Mutex<RefCell<I2cType>>>>, 
                          ssd1306::prelude::DisplaySize128x64, 
                          BufferedGraphicsMode<DisplaySize128x64>>

         // display: Ssd1306<I2CInterface<I2c<I2C1>>, 
         //                   ssd1306::prelude::DisplaySize128x64, 
        //                   BufferedGraphicsMode<DisplaySize128x64>>
     }


    #[task(shared = [ ], local = [ display ] )]
    async fn display_stuff(cx: display_stuff::Context) {
       loop {

           // workaround. build here because text_style cannot be shared
           let text_style = MonoTextStyleBuilder::new().font(&FONT_10X20).text_color(BinaryColor::On).build();

           let mut lines: [heapless::String<32>; 1] = [heapless::String::new(),];
           show_display(cx.local.display);
       
           cx.local.display.clear_buffer();

           write!(lines[1], "stuff").unwrap();

           for i in 0..lines.len() {
              // start from 0 requires that the top is used for font baseline
              Text::with_baseline(
                  &lines[i],
                  Point::new(0, i as i32 * 12), //with font 6x10, 12 = 10 high + 2 space
                  //cx.local.text_style,
                  text_style,
                  Baseline::Top,
              ).draw(cx.local.display).unwrap();
           }

           cx.local.display.flush().unwrap();

           Systick::delay(READ_INTERVAL.secs()).await;
       }        
     }
   }

Results from my testing are at https://github.com/pdgilbert/rust-integration-testing/actions in the eh-1-rc3 workflow runs. The code above is extracted from example display_stuff_rtic. A different problem regarding serial is reported at stm32-rs/stm32h7xx-hal#474 (comment)

@TeyKey1
Copy link

TeyKey1 commented Jan 7, 2024

Hi @pdgilbert my fork has updated to rc3 but I haven't tested it yet so it's quite possible that it does not work as expected. I'll likely stay on rc2 in my libraries until 1.0 lands so I won't adjust the fork anymore.

@pdgilbert
Copy link
Contributor Author

Ok, thanks @TeyKey1 for the confirmation. I can wait, hopefully it won't be long.

@rursprung
Copy link
Contributor

see the migration guide, shared-bus shouldn't be used anymore. you can now use embedded-hal-bus.

@pdgilbert
Copy link
Contributor Author

Thanks for point this out @rursprung . I am not having much luck with the embedded-hal-bus formulation but that is a different problem. I will close this as the sandwich issue is probably not too important anymore.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants