esp-rs / esp-hal

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

Async SPI - already borrowed: BorrowMutError on esp32s3 #1863

Closed VersBinarii closed 2 months ago

VersBinarii commented 2 months ago

Hello, I'm having issue with the following code and would appreciate some pointers on how to make it work.

    let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
    let timg0 = TimerGroup::new(peripherals.TIMG0, &clocks);
    let tim: ErasedTimer = timg0.timer0.into();
    let timer0 = OneShotTimer::new(tim);
    let timers = make_static!([timer0]);
    esp_hal_embassy::init(&clocks, timers);

    esp_println::logger::init_logger_from_env();

    let io = Io::new(peripherals.GPIO, peripherals.IO_MUX);
    let sclk = io.pins.gpio1;
    let din = io.pins.gpio2;
    let eink_cs = Output::new(io.pins.gpio3, Level::High);
    let eink_dc = Output::new(io.pins.gpio4, Level::High);
    let busy = Input::new(io.pins.gpio7, Pull::Up);
    let reset = Output::new(io.pins.gpio8, Level::High);
    let dma = Dma::new(peripherals.DMA);
    let dma_channel = dma.channel0;
    let (tx_descriptors, rx_descriptors) = dma_descriptors!(32000);

    let spi = Spi::new(peripherals.SPI2, 100.kHz(), SpiMode::Mode0, &clocks)
        .with_mosi(din)
        .with_sck(sclk)
        .with_dma(
            dma_channel.configure_for_async(false, DmaPriority::Priority0),
            tx_descriptors,
            rx_descriptors,
        );
    let spi: SafeSpiDma = FlashSafeDma::new(spi);
    let spi_device = ExclusiveDevice::new(spi, eink_cs, Delay).unwrap();
    let spi_interface = SpiInterface::new(spi_device, eink_dc);
    let mut driver = WeActStudio213TriColorDriver::new(spi_interface, busy, reset, Delay);
    let mut display = Display213TriColor::new();
    display.set_rotation(DisplayRotation::Rotate90);
    driver.init().await.expect("Failed to init");
    let style = MonoTextStyle::new(&PROFONT_24_POINT, TriColor::Red);
    let mut string_buf = String::<30>::new();
    write!(string_buf, "Time:\nInterval:").unwrap();
    let _ = Text::with_text_style(&string_buf, Point::new(8, 40), style, TextStyle::default())
        .draw(&mut display)
        .unwrap();
    string_buf.clear();
    if let Err(e) = driver.full_update(display).await {
        log::error!("Error: {:?}", e);
    }

The code results with following:

I (45) boot: ESP-IDF v5.1-beta1-378-gea5e0ff298-dirt 2nd stage bootloader
I (46) boot: compile time Jun  7 2023 08:07:32
I (47) boot: Multicore bootloader
I (51) boot: chip revision: v0.2
I (55) boot.esp32s3: Boot SPI Speed : 40MHz
I (59) boot.esp32s3: SPI Mode       : DIO
I (64) boot.esp32s3: SPI Flash Size : 4MB
I (69) boot: Enabling RNG early entropy source...
I (74) boot: Partition Table:
I (78) boot: ## Label            Usage          Type ST Offset   Length
I (85) boot:  0 nvs              WiFi data        01 02 00009000 00006000
I (93) boot:  1 phy_init         RF data          01 01 0000f000 00001000
I (100) boot:  2 factory          factory app      00 00 00010000 003f0000
I (108) boot: End of partition table
I (112) esp_image: segment 0: paddr=00010020 vaddr=3c020020 size=07e24h ( 32292) map
I (128) esp_image: segment 1: paddr=00017e4c vaddr=3fc8929c size=00008h (     8) load
I (129) esp_image: segment 2: paddr=00017e5c vaddr=40378000 size=0129ch (  4764) load
I (139) esp_image: segment 3: paddr=00019100 vaddr=00000000 size=06f18h ( 28440)
I (153) esp_image: segment 4: paddr=00020020 vaddr=42000020 size=1169ch ( 71324) map
I (172) boot: Loaded app from partition at offset 0x10000
I (173) boot: Disabling RNG early entropy source...

!! A panic occured in 'config/cargo/git/checkouts/esp-hal-42ec44e8c6943228/2744a5d/esp-hal-embassy/src/time_driver.rs', at line 171, column 37:
PanicInfo {
    payload: Any { .. },
    message: Some(
        already borrowed: BorrowMutError,
    ),
    location: Location {
        file: ".config/cargo/git/checkouts/esp-hal-42ec44e8c6943228/2744a5d/esp-hal-embassy/src/time_driver.rs",
        line: 171,
        col: 37,
    },
    can_unwind: true,
    force_no_backtrace: false,
}

Backtrace:

0x420108b4
0x420108b4 - core::cell::RefCell<T>::borrow_mut
    at .rustup/toolchains/esp/lib/rustlib/src/rust/library/core/src/cell.rs:1076
0x4200169f
0x4200169f - embassy_time_driver::set_alarm
    at .config/cargo/git/checkouts/embassy-9312dcb0ed774b29/2537fc6/embassy-time-driver/src/lib.rs:163
0x42008503
0x42008503 - calendar::__xtensa_lx_rt_main
    at Devel/Embedded/esp_embassy/src/main.rs:59
0x4201107a
0x4201107a - Reset
    at .config/cargo/registry/src/index.crates.io-6f17d22bba15001f/xtensa-lx-rt-0.16.0/src/lib.rs:70
0x403788b0
0x403788b0 - ESP32Reset
    at .config/cargo/git/checkouts/esp-hal-42ec44e8c6943228/2744a5d/esp-hal/src/soc/esp32s3/mod.rs:152
0x3ffffffd
0x3ffffffd - _stack_start_cpu0
    at ??:??
0x403cdd79
0x403cdd79 - _ZN7esp32s312__INTERRUPTS17hcdbf28238c6f341aE
    at ??:??
0x403c9971
0x403c9971 - _ZN7esp32s312__INTERRUPTS17hcdbf28238c6f341aE
    at ??:??
0x40045c01
0x40045c01 - rom_i2c_writeReg_Mask
    at ??:??
0x40043ab6
0x40043ab6 - rom_i2c_writeReg_Mask
    at ??:??

The actual lines of code that cause the crash are:

    if let Err(e) = driver.full_update(display).await {
        log::error!("Error: {:?}", e);
    }

Removing it makes the rest of the code work correctly I'm using follwing packages:

[dependencies]
esp-hal-embassy = { version = "0.2", features = ["esp32s3"] }
embassy-executor = { version = "0.5.0", features = [
  "task-arena-size-327680",
  "integrated-timers",
] }
embassy-time = { version = "0.3.1", features = [] }
embassy-sync = { version = "0.6.0" }
embassy-embedded-hal = { version = "0.1.0" }
esp-backtrace = { version = "0.13.0", features = [
  "esp32s3",
  "exception-handler",
  "panic-handler",
  "println",
] }
esp-hal = { version = "0.19.0", features = ["esp32s3", "async"] }
esp-println = { version = "0.10.0", features = ["esp32s3", "log"] }
log = { version = "0.4.21" }
static_cell = { version = "2", features = ["nightly"] }
bme280 = { version = "0.5.1", features = ["async"] }
embedded-hal-async = { version = "1.0.0" }
display-interface = { version = "0.5" }
display-interface-spi = { version = "0.5" }
embedded-hal-bus = { version = "0.2.0", features = ["async"] }
weact-studio-epd = { git = "https://github.com/avsaase/weact-studio-epd" }
profont = { version = "0.7.0" }
embedded-graphics = { version = "0.8.1" }
heapless = { version = "0.8" }

[patch.crates-io]
embassy-embedded-hal = { git = "https://github.com/embassy-rs/embassy", rev = "2537fc6f4fcbdaa0fcea45a37382d61f59cc5767" }
embassy-executor = { git = "https://github.com/embassy-rs/embassy", rev = "2537fc6f4fcbdaa0fcea45a37382d61f59cc5767" }
embassy-time = { git = "https://github.com/embassy-rs/embassy", rev = "2537fc6f4fcbdaa0fcea45a37382d61f59cc5767" }
embassy-time-driver = { git = "https://github.com/embassy-rs/embassy", rev = "2537fc6f4fcbdaa0fcea45a37382d61f59cc5767" }
embassy-time-queue-driver = { git = "https://github.com/embassy-rs/embassy", rev = "2537fc6f4fcbdaa0fcea45a37382d61f59cc5767" }
embassy-sync = { git = "https://github.com/embassy-rs/embassy", rev = "2537fc6f4fcbdaa0fcea45a37382d61f59cc5767" }
display-interface = { git = "https://github.com/therealprof/display-interface", rev = "8fca041b0288740678f16c1d05cce21bd3867ee5" }
display-interface-spi = { git = "https://github.com/therealprof/display-interface", rev = "8fca041b0288740678f16c1d05cce21bd3867ee5" }
esp-hal = { git = "https://github.com/esp-rs/esp-hal", rev = "2744a5d" }
esp-hal-embassy = { git = "https://github.com/esp-rs/esp-hal", rev = "2744a5d" }
plaes commented 2 months ago

Firstly, this line looks really odd as one would assume you would add at least driver as an argument there...

    let mut display = Display213TriColor::new();

How about:

    if let Err(e) = driver.full_update(&mut display).await {
        log::error!("Error: {:?}", e);
    }
VersBinarii commented 2 months ago

@plaes this is how the API for the driver is designed

VersBinarii commented 2 months ago

Ok, i managed to get it working without changing any code i did however change the dependencies to following:

embassy-executor = { version = "0.5.0", features = ["nightly"] }
embassy-time = { version = "0.3.1", features = ["generic-queue"] }