rust-embedded-community / ssd1306

SSD1306 OLED driver
Apache License 2.0
315 stars 70 forks source link

embedded-hal v1.0.0 and embedded-hal-bus #205

Open pdgilbert opened 10 months ago

pdgilbert commented 10 months ago

I am using @bugadani 's ehal1 fork of ssd1306 to make some examples work with embedded-hal-1.0.0. One of my main problems has been using ssd1306 with shared-bus. (see https://github.com/stm32-rs/stm32f4xx-hal/issues/722#issuecomment-1883868885). @rursprung pointed out that embedded-hal-bus is a replacement for shared-bus, but so far I have not been able to get the trait formulation and other pieces correct. I am not sure if this is just my newbie understanding, or if something is needed in ssd1306. The documentaion is written for HAL and crate developers, not for naive users. (I need a working example.)

With a local fork of @bugadani 's ehal1 I have modified example/text_i2c.rs and added a few lines toCargo.toml.

Click to expand modified examples/text_i2c.rs ``` //! Print "Hello world!" with "Hello rust!" underneath. Uses the `embedded_graphics` crate to draw //! the text with a 6x10 pixel font. //! //! This example is for the STM32F103 "Blue Pill" board and others using I2C1. //! //! Wiring connections are as follows for a CRIUS-branded display: //! //! ``` //! Display -> Blue Pill //! (black) GND -> GND //! (red) +5V -> VCC //! (yellow) SDA -> PB9 //! (green) SCL -> PB8 //! ``` //! //! Build on a Black Pill with //! cargo build --target thumbv7em-none-eabihf --features stm32f4xx-hal --example text_i2c //! Build on stm32h742 with //! cargo build --target thumbv7em-none-eabihf --features stm32h7xx-hal --example text_i2c #![no_std] #![no_main] use cortex_m_rt::{entry, exception, ExceptionFrame}; use embedded_graphics::{ mono_font::{ascii::FONT_6X10, MonoTextStyleBuilder}, pixelcolor::BinaryColor, prelude::*, text::{Baseline, Text}, }; use panic_halt as _; use ssd1306::{prelude::*, I2CDisplayInterface, Ssd1306}; #[cfg(feature = "stm32f4xx-hal")] use stm32f4xx_hal as hal; #[cfg(feature = "stm32h7xx-hal")] use stm32h7xx_hal as hal; use hal::{ i2c::I2c, prelude::*, pac::{Peripherals, I2C1}, pac, }; //use embedded_hal_bus::*; //use embedded_hal_bus::i2c; //use embedded_hal::i2c::I2c; //use embedded_hal_bus::i2c::I2c; //use embedded_hal_async::i2c::I2c; //use embedded_hal::i2c::{I2c, ErrorType as I2cErrorType, SevenBitAddress, TenBitAddress, Operation, Error as I2cError, }; #[cfg(feature = "stm32f4xx-hal")] fn setup(dp:Peripherals) -> I2c { let rcc = dp.RCC.constrain(); let clocks = rcc.cfgr.freeze(); let gpiob = dp.GPIOB.split(); let scl = gpiob.pb8.into_alternate_open_drain(); let sda = gpiob.pb9.into_alternate_open_drain(); let r = I2c::new(dp.I2C1, (scl, sda), 400.kHz(), &clocks); r } #[cfg(feature = "stm32h7xx-hal")] fn setup(dp:Peripherals) -> I2c { let pwr = dp.PWR.constrain(); let vos = pwr.freeze(); let rcc = dp.RCC.constrain(); let ccdr = rcc.sys_ck(160.MHz()).freeze(vos, &dp.SYSCFG); 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(); let r = dp.I2C1.i2c((scl, sda), 400.kHz(), ccdr.peripheral.I2C1, &clocks); r } #[entry] fn main() -> ! { let dp = pac::Peripherals::take().unwrap(); let r = setup(dp); let interface = I2CDisplayInterface::new(r); // need address and ErrorType //pub trait I2c: ErrorType { let mut display = Ssd1306::new(interface, DisplaySize128x64, DisplayRotation::Rotate0) .into_buffered_graphics_mode(); display.init().unwrap(); let text_style = MonoTextStyleBuilder::new() .font(&FONT_6X10) .text_color(BinaryColor::On) .build(); Text::with_baseline("Hello world!", Point::zero(), text_style, Baseline::Top) .draw(&mut display) .unwrap(); Text::with_baseline("Hello Rust!", Point::new(0, 16), text_style, Baseline::Top) .draw(&mut display) .unwrap(); display.flush().unwrap(); loop {} } #[exception] unsafe fn HardFault(ef: &ExceptionFrame) -> ! { panic!("{:#?}", ef); } ```
Click to expand Cargo.toml diff ``` 29a30,34 > # Used by text_i2c examples > embedded-hal-bus = { git = "https://github.com/rust-embedded/embedded-hal/" } > stm32f4xx-hal = { git = "https://github.com/rursprung/stm32f4xx-hal", features = [ "rt", "stm32f401" ], optional = true, branch = "update-to-eh-1" } > stm32h7xx-hal = { git = "https://github.com/stm32-rs/stm32h7xx-hal", features = [ "rt", "stm32h742" ], optional = true, branch = "eh-v1.0"} > ```

Without trying to share the bus, the code compiles in ssd1306 with both stm32f4xx-hal and stm32h7xx-hal using

cargo build --target thumbv7em-none-eabihf --features stm32f4xx-hal --example  text_i2c
cargo build --target thumbv7em-none-eabihf --features stm32h7xx-hal --example  text_i2c

When I try to make changes for sharing the bus (see https://crates.io/crates/embedded-hal-bus and https://github.com/rust-embedded/embedded-hal/blob/master/docs/migrating-from-0.2-to-1.0.md#error-type-bounds ) I cannot get the correct formulation or the proper trait. Commented out in the code are many of the lines I think I need, but I have not had any success with a very large number of attempts. Suggestions would be appreciated.

bugadani commented 10 months ago

Could you please try with embedded-hal-bus = "0.1.0" instead of trying to use the dependency from github?

pdgilbert commented 10 months ago

Changing Cargo.toml so I have

embedded-hal-bus = "0.1.0"

and text_i2c.rs to what I think I should have:

...
use hal::{
    //i2c::I2c,
    prelude::*,
    pac::{Peripherals, I2C1},
    pac,
};

use embedded_hal_bus::i2c::I2c;
...

Then when I compile I get

...

 Downloaded embedded-hal-bus v0.1.0
  Downloaded 1 crate (11.9 KB) in 0.72s
   Compiling embedded-hal-bus v0.1.0
   Compiling ssd1306 v0.8.4 (/home/paul/githubClones/ssd1306)

error[E0432]: unresolved import `embedded_hal_bus::i2c::I2c`
  --> examples/text_i2c.rs:53:5
   |
53 | use embedded_hal_bus::i2c::I2c;
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ no `I2c` in `i2c`
   |
help: consider importing one of these items instead
   |
53 | use crate::hal::i2c::I2c;
   |     ~~~~~~~~~~~~~~~~~~~~
53 | use embedded_hal::i2c::I2c;
   |     ~~~~~~~~~~~~~~~~~~~~~~
53 | use embedded_hal_async::i2c::I2c;
   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
53 | use stm32f1xx_hal::i2c::I2c;
   |     ~~~~~~~~~~~~~~~~~~~~~~~
     and 2 other candidates

For more information about this error, try `rustc --explain E0432`.
error: could not compile `ssd1306` (example "text_i2c") due to 1 previous error

I find it strange that there is "no I2c in i2c". It really looks to me like it should be there. I don't see typos or anything simple, but this does not seem right.

Also, when I look at cargo tree, it looks like display-interface-i2c depends on embedded-hal-async but not on embedded-hal-bus.

$ cargo tree ssd1306 v0.8.4 (/home/paul/githubClones/ssd1306) ├── display-interface v0.5.0 (https://github.com/bugadani/display-interface.git?branch=eh1#e65eaf6d) ├── display-interface-i2c v0.5.0 (https://github.com/bugadani/display-interface.git?branch=eh1#e65eaf6d) │ ├── display-interface v0.5.0 (https://github.com/bugadani/display-interface.git?branch=eh1#e65eaf6d) │ ├── embedded-hal v1.0.0 │ └── embedded-hal-async v1.0.0 │ └── embedded-hal v1.0.0 ├── display-interface-spi v0.5.0 (https://github.com/bugadani/display-interface.git?branch=eh1#e65eaf6d) │ ├── byte-slice-cast v1.2.2 │ ├── display-interface v0.5.0 (https://github.com/bugadani/display-interface.git?branch=eh1#e65eaf6d) │ ├── embedded-hal v1.0.0 │ └── embedded-hal-async v1.0.0 () ├── embedded-graphics-core v0.4.0 │ ├── az v1.2.1 │ └── byteorder v1.5.0 ├── embedded-hal v1.0.0 ├── embedded-hal-async v1.0.0 () └── embedded-hal-bus v0.1.0 ├── critical-section v1.1.2 └── embedded-hal v1.0.0 [dev-dependencies] ...

bugadani commented 10 months ago

embedded-hal-bus isn't a simple plug-and-play crate, you don't get an I2c struct that "just works". You need to decide on how you share your bus between your devices, and for that you have three options.

Why do you expect display-interface-i2c to depend on embedded-hal-bus? embedded-hal-bus doesn't define any new traits that would require any special handling in display-interface-i2c.

pdgilbert commented 10 months ago

Thanks for the hint @bugadani . I guess it is more complicated than I thought. I'll eventually figure it out. Not exactly a simple replacement for shared_bus, but seems like more control over the mechanism.

My thinking on display-interface-i2c depending on embedded-hal-bus was because I mis-read the tree and thought it depended on embedded-hal-spi. I think the spi and i2c similarities are such that one dependency would suggest the other too..