esp-rs / esp-hal

no_std Hardware Abstraction Layers for ESP32 microcontrollers
https://docs.esp-rs.org/esp-hal/
Apache License 2.0
625 stars 167 forks source link

Trait compatibility issue between esp_hal SPI and display_interface_spi in embedded Rust project #1456

Closed Song-aff closed 2 months ago

Song-aff commented 2 months ago

Cargo.toml

[package]
name = "esp-spi"
version = "0.1.0"
authors = ["xxx <xxx@xxx.com>"]
edition = "2021"
license = "MIT OR Apache-2.0"

[dependencies]
embedded-hal = "1.0.0"
esp-backtrace = { version = "0.11.0", features = [
    "esp32c3",
    "exception-handler",
    "panic-handler",
    "println",
] }
esp-hal = { version = "0.16.0", features = [ "esp32c3" ] }
esp-println = { version = "0.9.0", features = ["esp32c3", "log"] }
log = { version = "0.4.20" }
esp-alloc = { version = "0.3.0" }
display-interface = "0.5.0"
display-interface-spi = "0.5.0"
mipidsi = {git = "https://github.com/almindor/mipidsi",branch = "master"}
[profile.dev]
# Rust debug is too slow. 
# For debug builds always builds with some optimization
opt-level = "s"

[profile.release]
codegen-units = 1 # LLVM can perform better optimizations using a single thread
debug = 2
debug-assertions = false
incremental = false
lto = 'fat'
opt-level = 's'
overflow-checks = false

main.rs

#![no_std]
#![no_main]

extern crate alloc;
use core::mem::MaybeUninit;
use display_interface_spi::SPIInterface;
use esp_backtrace as _;
use esp_hal::{
    clock::ClockControl,
    gpio::{IO, NO_PIN},
    peripherals::Peripherals,
    prelude::*,
    spi::{master::Spi, SpiMode},
    Delay,
};
use esp_println::println;
use mipidsi;

#[global_allocator]
static ALLOCATOR: esp_alloc::EspHeap = esp_alloc::EspHeap::empty();

fn init_heap() {
    const HEAP_SIZE: usize = 32 * 1024;
    static mut HEAP: MaybeUninit<[u8; HEAP_SIZE]> = MaybeUninit::uninit();

    unsafe {
        ALLOCATOR.init(HEAP.as_mut_ptr() as *mut u8, HEAP_SIZE);
    }
}
#[entry]
fn main() -> ! {
    init_heap();
    let peripherals = Peripherals::take();
    let system = peripherals.SYSTEM.split();

    let clocks = ClockControl::max(system.clock_control).freeze();
    let mut delay = Delay::new(&clocks);

    let mut delay = Delay::new(&clocks);
    let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);

    let clk = io.pins.gpio6;
    let sdo = io.pins.gpio7;
    let cs = io.pins.gpio5;

    let spi = Spi::new(peripherals.SPI2, 60u32.MHz(), SpiMode::Mode0, &clocks).with_pins(
        Some(clk),
        Some(sdo),
        NO_PIN,
        Some(cs),
    );
    println!("spi init.");

    let dc = io.pins.gpio4.into_push_pull_output();
    let rst = io.pins.gpio8.into_push_pull_output();

    let di = SPIInterface::new(spi, dc);

    let display = mipidsi::Builder::new(mipidsi::models::ST7735s, di)
        .reset_pin(rst)
        .init(&mut delay)
        .unwrap();

    loop {
        println!("Loop...");
        delay.delay_ms(500u32);
    }
}

error

error[E0277]: the trait bound `esp_hal::spi::master::Spi<'_, esp_hal::peripherals::SPI2, FullDuplexMode>: embedded_hal::spi::SpiDevice` is not satisfied
  --> src/main.rs:59:19
   |
59 |     let display = mipidsi::Builder::new(mipidsi::models::ST7735s, di)
   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `embedded_hal::spi::SpiDevice` is not implemented for `esp_hal::spi::master::Spi<'_, esp_hal::peripherals::SPI2, FullDuplexMode>`, which is required by `SPIInterface<esp_hal::spi::master::Spi<'_, esp_hal::peripherals::SPI2, FullDuplexMode>, GpioPin<Output<esp_hal::gpio::PushPull>, 4>>: display_interface::WriteOnlyDataCommand`
   |
   = help: the following other types implement trait `embedded_hal::spi::SpiDevice<Word>`:
             <&mut T as embedded_hal::spi::SpiDevice<Word>>
             <MockSpi as embedded_hal::spi::SpiDevice>
   = note: required for `SPIInterface<esp_hal::spi::master::Spi<'_, esp_hal::peripherals::SPI2, FullDuplexMode>, GpioPin<Output<esp_hal::gpio::PushPull>, 4>>` to implement `display_interface::WriteOnlyDataCommand`
note: required by a bound in `Builder`
  --> /Users/admin/.cargo/git/checkouts/mipidsi-bfc6dd65feb7ca91/a575e43/mipidsi/src/builder.rs:31:9
   |
29 | pub struct Builder<DI, MODEL, RST>
   |            ------- required by a bound in this struct
30 | where
31 |     DI: WriteOnlyDataCommand,
   |         ^^^^^^^^^^^^^^^^^^^^ required by this bound in `Builder`
Song-aff commented 2 months ago

and why spi type is {unknown}

 let spi = Spi::new(peripherals.SPI2, 60u32.MHz(), SpiMode::Mode0, &clocks).with_pins(
        Some(clk),
        Some(sdo),
        NO_PIN,
        Some(cs),
    );
bjoernQ commented 2 months ago

You are using the master branch of mipidsi: mipidsi = {git = "https://github.com/almindor/mipidsi",branch = "master"}

That is using embedded-hal 1.x.x - in esp-hal 0.16.x you need to enable embedded-hal 1.x.x via the feature "eh1". The master of mipidsi takes an SpiDevice - you can use the embedded-hal-bus crate for that.

This should compile

[package]
name = "spi"
version = "0.1.0"
authors = ["bjoernQ <bjoern.quentin@mobile-j.de>"]
edition = "2021"
license = "MIT OR Apache-2.0"

[dependencies]
embedded-hal = "1.0.0"
esp-backtrace = { version = "0.11.0", features = [
    "esp32c3",
    "exception-handler",
    "panic-handler",
    "println",
] }
esp-hal = { version = "0.16.0", features = [ "esp32c3", "eh1" ] }
esp-println = { version = "0.9.0", features = ["esp32c3", "log"] }
log = { version = "0.4.20" }
esp-alloc = { version = "0.3.0" }
display-interface = "0.5.0"
display-interface-spi = "0.5.0"
mipidsi = {git = "https://github.com/almindor/mipidsi",branch = "master"}

embedded-hal-bus = "0.1.0"

[profile.dev]
# Rust debug is too slow. 
# For debug builds always builds with some optimization
opt-level = "s"

[profile.release]
codegen-units = 1 # LLVM can perform better optimizations using a single thread
debug = 2
debug-assertions = false
incremental = false
lto = 'fat'
opt-level = 's'
overflow-checks = false
#![no_std]
#![no_main]

extern crate alloc;
use core::mem::MaybeUninit;
use display_interface_spi::SPIInterface;
use esp_backtrace as _;
use esp_hal::{
    clock::ClockControl,
    gpio::{IO, NO_PIN},
    peripherals::Peripherals,
    prelude::*,
    spi::{master::Spi, SpiMode},
    Delay,
};
use esp_println::println;
use mipidsi;

#[global_allocator]
static ALLOCATOR: esp_alloc::EspHeap = esp_alloc::EspHeap::empty();

fn init_heap() {
    const HEAP_SIZE: usize = 32 * 1024;
    static mut HEAP: MaybeUninit<[u8; HEAP_SIZE]> = MaybeUninit::uninit();

    unsafe {
        ALLOCATOR.init(HEAP.as_mut_ptr() as *mut u8, HEAP_SIZE);
    }
}
#[entry]
fn main() -> ! {
    init_heap();
    let peripherals = Peripherals::take();
    let system = peripherals.SYSTEM.split();

    let clocks = ClockControl::max(system.clock_control).freeze();
    let mut delay = Delay::new(&clocks);

    let mut delay = Delay::new(&clocks);
    let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);

    let clk = io.pins.gpio6;
    let sdo = io.pins.gpio7;
    let cs = io.pins.gpio5.into_push_pull_output();

    let spi = Spi::new(peripherals.SPI2, 60u32.MHz(), SpiMode::Mode0, &clocks).with_pins(
        Some(clk),
        Some(sdo),
        NO_PIN,
        NO_PIN,
    );
    println!("spi init.");

    let dc = io.pins.gpio4.into_push_pull_output();
    let rst = io.pins.gpio8.into_push_pull_output();

    let spi_device = embedded_hal_bus::spi::ExclusiveDevice::new(spi, cs, delay);
    let di = SPIInterface::new(spi_device, dc);

    let display = mipidsi::Builder::new(mipidsi::models::ST7735s, di)
        .reset_pin(rst)
        .init(&mut delay)
        .unwrap();

    loop {
        println!("Loop...");
        delay.delay_ms(500u32);
    }
}
Song-aff commented 2 months ago

I compiled successfully, that's great. Thank you.