Describe the bug
When I include terminal.draw(draw).unwrap(); even to reproduce the example code, probe-rs gets the following error:
❯ cargo run
Compiling plague_rat v0.1.0 (/Users/jamin/Documents/Programming/Rust/plague_rat)
Finished `dev` profile [optimized + debuginfo] target(s) in 2.43s
Running `probe-rs run --chip=esp32c6 --preverify --always-print-stacktrace --no-location target/riscv32imac-unknown-none-elf/debug/plague_rat`
Erasing ✔ 100% [####################] 320.00 KiB @ 316.61 KiB/s (took 1s) Finished in 3.55s
ERROR nusb::platform::macos_iokit::device: Failed to submit Out transfer 0xbdf938d80 of len 48 on endpoint 02: e000404f
WARN probe_rs::session: Could not clear all hardware breakpoints: An error with the usage of the probe occurred
Caused by:
0: USB Communication Error
1: endpoint stalled
ERROR nusb::platform::macos_iokit::device: Failed to submit Out transfer 0xbdf938d80 of len 64 on endpoint 02: e000404f
WARN probe_rs::session: Failed to deconfigure device during shutdown: Probe(Usb(Custom { kind: ConnectionReset, error: Stall }))
Error: An error with the usage of the probe occurred
Caused by:
0: USB Communication Error
1: endpoint stalled
When it removed, the chip is flashed and I get the expect output.
Finished `release` profile [optimized + debuginfo] target(s) in 2.10s
Running `probe-rs run --chip=esp32c6 --preverify --always-print-stacktrace --no-location target/riscv32imac-unknown-none-elf/release/plague_rat`
Erasing ✔ 100% [####################] 128.00 KiB @ 271.13 KiB/s (took 0s)
Programming ✔ 100% [####################] 44.82 KiB @ 57.41 KiB/s (took 1s) Finished in 2.29s
[INFO ] Booting...
[INFO ] Heap OK
[INFO ] GPIO OK - busy: false
[INFO ] SPI OK
[INFO ] Pre-init delay...
[INFO ] Driver init...
[INFO ] Driver init OK
[INFO ] Display buffer OK
[INFO ] Creating backend...
[INFO ] Backend OK
[INFO ] Terminal OK
[INFO ] Calling draw...
I have checked the display is initialising correctly by 1. Rendering a raw image to it through embeded graphics directly. 2. Recreating my desired terminal display on a pipico.
To Reproduce
Steps to reproduce the behavior:
- setup project using esp-generate
- add mousefood, ratatui
- use mousefood example code
Fingers crossed its some weird copy pasta error from converting from the pipico version, but given I cant even get the mousefood demo working, it might be more serious.
Expected behavior
The example ratatui terminal display should be rendered to the display.
Additional context
I have migrated this from a pipico, where I was able to get my own draw logic to render on this display.
I have attached my cargo.toml, the src file itself here:
cargo.toml
[package]
edition = "2024"
name = "plague_rat"
rust-version = "1.88"
version = "0.1.0"
[[bin]]
name = "plague_rat"
path = "./src/bin/main.rs"
[dependencies]
esp-hal = { version = "~1.0", features = ["defmt", "esp32c6", "unstable"] }
esp-rtos = { version = "0.2.0", features = [
"defmt",
"embassy",
"esp-alloc",
"esp-radio",
"esp32c6",
] }
defmt = "1.0.1"
esp-bootloader-esp-idf = { version = "0.4.0", features = ["defmt", "esp32c6"] }
bt-hci = "0.6.0"
embassy-executor = { version = "0.9.1", features = ["defmt"] }
embassy-time = { version = "0.5.0", features = ["defmt"] }
embedded-io = { version = "0.7.1", features = ["defmt"] }
embedded-io-async = { version = "0.7.0", features = ["defmt"] }
embedded-hal-bus = "0.2"
esp-alloc = { version = "0.9.0", features = ["defmt"] }
esp-radio = { version = "0.17.0", features = [
"ble",
"defmt",
"esp-alloc",
"esp32c6",
"unstable",
] }
rtt-target = { version = "0.6.2", features = ["defmt"] }
trouble-host = { version = "0.5.0", features = ["gatt"] }
critical-section = "1.2.0"
static_cell = "2.1.1"
weact-studio-epd = { version = "0.1.2", features = ["blocking"] }
display-interface-spi = "0.5"
embedded-graphics = "0.8.2"
mousefood = { git = "https://github.com/ratatui/mousefood", default-features = false, features = ["epd-weact", "fonts"] }
ratatui = { version = "0.30.0", default-features = false }
kasuari = { version = "0.4", default-features = false, features = ["portable-atomic"] }
heapless = "0.9.2"
[profile.dev]
opt-level = "s"
[profile.release]
codegen-units = 1
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 alloc::boxed::Box;
use defmt::info;
use esp_hal::clock::CpuClock;
use esp_hal::delay::Delay;
use esp_hal::gpio::{Input, InputConfig, Level, Output, OutputConfig, Pull};
use esp_hal::main;
use esp_hal::spi::Mode;
use esp_hal::spi::master::{Config as SpiConfig, Spi};
use esp_hal::time::Rate;
use embedded_hal_bus::spi::ExclusiveDevice;
use weact_studio_epd::graphics::{Display213BlackWhite, DisplayRotation};
use weact_studio_epd::WeActStudio213BlackWhiteDriver;
use mousefood::prelude::*;
use ratatui::style::Stylize;
use ratatui::widgets::{Block, Paragraph, Wrap};
use ratatui::{Frame, Terminal};
esp_bootloader_esp_idf::esp_app_desc!();
#[panic_handler]
fn panic(info: &core::panic::PanicInfo) -> ! {
defmt::error!("PANIC: {:?}", defmt::Debug2Format(info));
loop {}
}
#[allow(clippy::large_stack_frames)]
#[main]
fn main() -> ! {
rtt_target::rtt_init_defmt!();
info!("Booting...");
let config = esp_hal::Config::default().with_cpu_clock(CpuClock::max());
let peripherals = esp_hal::init(config);
esp_alloc::heap_allocator!(size: 128 * 1024);
info!("Heap OK");
let cs = Output::new(peripherals.GPIO4, Level::High, OutputConfig::default());
let dc = Output::new(peripherals.GPIO5, Level::High, OutputConfig::default());
let rst = Output::new(peripherals.GPIO10, Level::High, OutputConfig::default());
let busy = Input::new(peripherals.GPIO11, InputConfig::default().with_pull(Pull::Up));
info!("GPIO OK - busy: {}", busy.is_high());
let spi = Spi::new(
peripherals.SPI2,
SpiConfig::default()
.with_frequency(Rate::from_mhz(4))
.with_mode(Mode::_0),
)
.unwrap()
.with_sck(peripherals.GPIO2)
.with_mosi(peripherals.GPIO3);
let spi_device = ExclusiveDevice::new_no_delay(spi, cs).unwrap();
let interface = display_interface_spi::SPIInterface::new(spi_device, dc);
info!("SPI OK");
let mut driver = WeActStudio213BlackWhiteDriver::new(interface, busy, rst, Delay::new());
info!("Pre-init delay...");
for _ in 0..1_000_000u32 {
core::hint::spin_loop();
}
info!("Driver init...");
driver.init().unwrap();
info!("Driver init OK");
let mut display = Display213BlackWhite::new();
display.set_rotation(DisplayRotation::Rotate270);
info!("Display buffer OK");
info!("Creating backend...");
let config = EmbeddedBackendConfig {
flush_callback: Box::new(move |d: &mut Display213BlackWhite| {
info!("Flushing to e-paper...");
driver.full_update(d).expect("epd update failed");
info!("Flush done!");
}),
..Default::default()
};
let backend = EmbeddedBackend::new(&mut display, config);
info!("Backend OK");
let mut terminal = Terminal::new(backend).unwrap();
info!("Terminal OK");
info!("Calling draw...");
terminal.draw(draw).unwrap();
loop {}
}
fn draw(frame: &mut Frame) {
let text = "Ratatui on embedded devices!";
let paragraph = Paragraph::new(text.white()).wrap(Wrap { trim: true });
let bordered_block = Block::bordered().title("Mousefood");
frame.render_widget(paragraph.block(bordered_block), frame.area());
}
build.rs
fn main() {
linker_be_nice();
println!("cargo:rustc-link-arg=-Tdefmt.x");
// make sure linkall.x is the last linker script (otherwise might cause problems with flip-link)
println!("cargo:rustc-link-arg=-Tlinkall.x");
}
fn linker_be_nice() {
let args: Vec<String> = std::env::args().collect();
if args.len() > 1 {
let kind = &args[1];
let what = &args[2];
match kind.as_str() {
"undefined-symbol" => match what.as_str() {
what if what.starts_with("_defmt_") => {
eprintln!();
eprintln!(
"💡 `defmt` not found - make sure `defmt.x` is added as a linker script and you have included `use defmt_rtt as _;`"
);
eprintln!();
}
"_stack_start" => {
eprintln!();
eprintln!("💡 Is the linker script `linkall.x` missing?");
eprintln!();
}
what if what.starts_with("esp_rtos_") => {
eprintln!();
eprintln!(
"💡 `esp-radio` has no scheduler enabled. Make sure you have initialized `esp-rtos` or provided an external scheduler."
);
eprintln!();
}
"embedded_test_linker_file_not_added_to_rustflags" => {
eprintln!();
eprintln!(
"💡 `embedded-test` not found - make sure `embedded-test.x` is added as a linker script for tests"
);
eprintln!();
}
"free"
| "malloc"
| "calloc"
| "get_free_internal_heap_size"
| "malloc_internal"
| "realloc_internal"
| "calloc_internal"
| "free_internal" => {
eprintln!();
eprintln!(
"💡 Did you forget the `esp-alloc` dependency or didn't enable the `compat` feature on it?"
);
eprintln!();
}
_ => (),
},
// we don't have anything helpful for "missing-lib" yet
_ => {
std::process::exit(1);
}
}
std::process::exit(0);
}
println!(
"cargo:rustc-link-arg=--error-handling-script={}",
std::env::current_exe().unwrap().display()
);
}
config.toml
[target.riscv32imac-unknown-none-elf]
runner = "probe-rs run --chip=esp32c6 --preverify --always-print-stacktrace --no-location"
[env]
DEFMT_LOG="info"
[build]
rustflags = [
# Required to obtain backtraces (e.g. when using the "esp-backtrace" crate.)
# NOTE: May negatively impact performance of produced code
"-C", "force-frame-pointers",
]
target = "riscv32imac-unknown-none-elf"
[unstable]
build-std = ["alloc", "core"]
Describe the bug
When I include terminal.draw(draw).unwrap(); even to reproduce the example code, probe-rs gets the following error:
When it removed, the chip is flashed and I get the expect output.
I have checked the display is initialising correctly by 1. Rendering a raw image to it through embeded graphics directly. 2. Recreating my desired terminal display on a pipico.
To Reproduce
Steps to reproduce the behavior:
Fingers crossed its some weird copy pasta error from converting from the pipico version, but given I cant even get the mousefood demo working, it might be more serious.
Expected behavior
The example ratatui terminal display should be rendered to the display.
Additional context
I have migrated this from a pipico, where I was able to get my own draw logic to render on this display.
I have attached my cargo.toml, the src file itself here:
cargo.tomlmain.rs
build.rsconfig.toml