Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,11 @@ jobs:
dir: examples/epd-waveshare-demo
target: ""
setup_xtensa: true
# Lilygo-epd47 demo
- name: lilygo-epd47-demo
dir: examples/lilygo-epd47-demo
target: ""
setup_xtensa: true
steps:
- name: Checkout
uses: actions/checkout@v6
Expand Down
58 changes: 56 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

66 changes: 64 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,8 +147,8 @@ let config = EmbeddedBackendConfig {
cursor: CursorConfig {
style: CursorStyle::Japanese,
blink: true,
color: Rgb888::WHITE,
color: Rgb888::WHITE,

},
..Default::default()
};
Expand Down Expand Up @@ -299,6 +299,65 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {

See the full embedded example at [`examples/epd-waveshare-demo`](https://github.com/ratatui/mousefood/tree/main/examples/epd-waveshare-demo).

#### Lilygo T5 e-paper

Support for the lilygo T5 e-paper produced by Lilygo with an esp32s3 and the EDO47TC1 panel driver.
(`lilygo-epd47` driver) can be enabled using `lilygo-epd47` feature.

<details>
<summary>Setup example</summary>

The lilygo-epd47 driver include its own internal buffers, so the mousefood framebuffer
adds memory overhead with no benefit. Disable default features to turn it off:

```toml
[dependencies]
mousefood = { version = "*", default-features = false, features = ["lilygo-epd47"] }
```

```rust,ignore
use mousefood::prelude::*;

#[main]
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Setup all that is required for your board and get the peripherals.
// let peripherals = ...;

let mut display = Display::new(
pin_config!(peripherals),
peripherals.DMA_CH0,
peripherals.LCD_CAM,
peripherals.RMT,
)?;

let theme = ColorTheme {
background: Rgb888::WHITE,
foreground: Rgb888::BLACK,
..ColorTheme::ansi()
};

// setup mousefood
let backend = EmbeddedBackendConfig {
color_theme: theme,
font_regular: mousefood::fonts::mono_10x20_atlas(),
flush_callback: Box::new(move |display: &mut Display| {
display
.flush(DrawMode::BlackOnWhite)
.expect("to flush to the display")
}),
..Default::default()
};

let backend = EmbeddedBackend::new(&mut display, backend);
let _terminal = Terminal::new(backend)?;
Ok(())
}
```

</details>

See the full embedded example at [`examples/lilygo-epd47-demo`](https://github.com/ratatui/mousefood/tree/main/examples/lilygo-epd47-demo).

## Performance and hardware support

Flash memory on most embedded devices is very limited. Additionally,
Expand All @@ -312,6 +371,7 @@ Successfully tested on:
### Microcontrollers

- ESP32 (Xtensa)
- ESP32-S3 (Xtensa)
- ESP32-C6 (RISC-V)
- STM32
- RP2040
Expand All @@ -327,6 +387,8 @@ For every driver, the list of displays is not exhaustive.
(requires enabling `epd-waveshare` feature)
- [weact-studio-epd](https://crates.io/crates/weact-studio-epd) for e-paper displays
from WeAct Studio (requires enabling `epd-weact` feature)
- [lilygo-epd47](https://crates.io/crates/lilygo-epd47) for the Lilygo T5 e-paper
from Lilygo (requires enabling `lilygo-epd47` feature)

Send a pull request to add your microcontroller or display driver here!

Expand Down
18 changes: 18 additions & 0 deletions examples/lilygo-epd47-demo/.cargo/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[target.xtensa-esp32s3-none-elf]
runner = "espflash flash --monitor --chip esp32s3"

[env]
ESP_LOG = "DEBUG"
ESP_HAL_CONFIG_PSRAM_MODE = "octal"

[build]
rustflags = [
"-C", "link-arg=-nostartfiles",
]
target = "xtensa-esp32s3-none-elf"

[unstable]
build-std = ["core", "alloc"]

[profile.release]
debug = true
27 changes: 27 additions & 0 deletions examples/lilygo-epd47-demo/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
[package]
name = "lilygo-epd47-demo"
version = "0.1.0"
edition = "2024"
rust-version = "1.90"
publish = false

[dependencies]
esp-bootloader-esp-idf = { version = "0.4.0", features = ["esp32s3"] }
esp-hal = { version = "1.0.0", features = ["esp32s3", "unstable", "psram"] }

critical-section = "1.2.0"
esp-alloc = "0.9.0"
lilygo-epd47 = "1.0.0"

ratatui = { workspace = true }
ratatui-core = { workspace = true }
mousefood = { path = "../../mousefood/", default-features = false, features = ["fonts", "lilygo-epd47"] }
embedded-graphics = "0.8.2"

esp-println = { version = "0.16.1", features = ["esp32s3", "log-04"] }
esp-backtrace = { version = "0.18.1", features = [
"esp32s3",
"panic-handler",
"println",
] }

23 changes: 23 additions & 0 deletions examples/lilygo-epd47-demo/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Lilygo T5 e-paper

This example showcases the use of mouse food on the Lilygo T5 e-paper, in a `no_std` context.

## Pinmap

![./assets/T5-E-Paper-pin-en.jpg]

## Wiring

No wiring really necessary as all that's required is already on the PCB

## Notes

There are some gotchas regarding the screen refresh.

The driver either draw black on white or white on black.
Thus, superposing the updated chars which is not ideal.

To solve this you need to:

- Update the `flush_callback` to add a screen clear in it.
- Add a `terminal.clear()` to force a full redraw from mousefood.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions examples/lilygo-epd47-demo/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
fn main() {
println!("cargo:rustc-link-arg=-Tlinkall.x");
}
2 changes: 2 additions & 0 deletions examples/lilygo-epd47-demo/rust-toolchain.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[toolchain]
channel = "esp"
78 changes: 78 additions & 0 deletions examples/lilygo-epd47-demo/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#![no_std]
#![no_main]

extern crate alloc;
extern crate lilygo_epd47;

use alloc::boxed::Box;

use embedded_graphics::prelude::RgbColor;

#[allow(unused_imports)]
use esp_backtrace as _;
use esp_hal::{delay::Delay, main};
use lilygo_epd47::{Display, DrawMode, pin_config};

use mousefood::prelude::*;
use ratatui::style::Stylize;
use ratatui::widgets::{Block, Paragraph, Wrap};
use ratatui::{Frame, Terminal};

esp_bootloader_esp_idf::esp_app_desc!();

#[main]
fn main() -> ! {
esp_println::logger::init_logger_from_env();

let config = esp_hal::Config::default();
let config = config.with_cpu_clock(esp_hal::clock::CpuClock::_240MHz);
let peripherals = esp_hal::init(config);

// Create PSRAM allocator
esp_alloc::psram_allocator!(peripherals.PSRAM, esp_hal::psram);

let mut display = Display::new(
pin_config!(peripherals),
peripherals.DMA_CH0,
peripherals.LCD_CAM,
peripherals.RMT,
)
.expect("to initialize correctly");

let delay = Delay::new();
display.power_on();
delay.delay_millis(10);
display.clear().expect("to clear display");

let theme = ColorTheme {
background: Rgb888::WHITE,
foreground: Rgb888::BLACK,
..ColorTheme::ansi()
};

// setup mousefood
let backend = EmbeddedBackendConfig {
color_theme: theme,
font_regular: mousefood::fonts::mono_10x20_atlas(),
flush_callback: Box::new(move |display: &mut Display| {
display
.flush(DrawMode::BlackOnWhite)
.expect("to flush to the display")
}),
..Default::default()
};

let backend = EmbeddedBackend::new(&mut display, backend);
let mut terminal = Terminal::new(backend).unwrap();
terminal.draw(draw).unwrap();

#[allow(clippy::empty_loop)]
loop {}
}

fn draw(frame: &mut Frame) {
let text = "Ratatui on embedded devices!";
let paragraph = Paragraph::new(text.black()).wrap(Wrap { trim: true });
let bordered_block = Block::bordered().title("Mousefood");
frame.render_widget(paragraph.block(bordered_block), frame.area());
}
1 change: 1 addition & 0 deletions mousefood/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ std = ["thiserror/std", "ratatui-core/std"]
fonts = ["dep:embedded-graphics-unicodefonts"]
epd-weact = ["dep:weact-studio-epd"]
epd-waveshare = ["dep:epd-waveshare"]
lilygo-epd47 = []
framebuffer = []
blink = []
underline-color = ["ratatui-core/underline-color"]
Expand Down
10 changes: 10 additions & 0 deletions mousefood/src/colors.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use crate::macros::for_all_rgb_colors;
#[cfg(feature = "lilygo-epd47")]
use embedded_graphics::pixelcolor::Gray4;
use embedded_graphics::pixelcolor::{
Bgr555, Bgr565, Bgr666, Bgr888, BinaryColor, Rgb555, Rgb565, Rgb666, Rgb888, RgbColor,
};
Expand Down Expand Up @@ -241,6 +243,14 @@ impl From<TermColor<'_>> for epd_waveshare::color::TriColor {
}
}

#[cfg(feature = "lilygo-epd47")]
impl<'a> From<TermColor<'a>> for Gray4 {
fn from(color: TermColor<'a>) -> Self {
let rgb: Rgb888 = color.into();
rgb.into()
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
Loading