Skip to content

Commit e9e4f3b

Browse files
committed
esp-wroverkit: add framebuffer on the heap
1 parent 8454a1b commit e9e4f3b

File tree

3 files changed

+64
-24
lines changed

3 files changed

+64
-24
lines changed

docs/README.md

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,21 @@ cd esp32-s3-box-3-minimal
1919
cargo run --release
2020
```
2121

22+
### ESP32-C6-LCD-1.47 Waveshare
23+
24+
[Rust Bare Metal no_std](https://developer.espressif.com/blog/2025/02/rust-esp-hal-beta/) with [Bevy ECS no_std](https://github.com/bevyengine/bevy/issues/15460) on 1.47 inch [ESP32-C6 LCD Waheshare](https://www.waveshare.com/esp32-c6-lcd-1.47.htm) with DMA and framebuffer - [Conway's Game of Life](https://github.com/georgik/esp32-conways-game-of-life-rs/tree/main/esp32-c6-waveshare-1_47):
25+
26+
<video src="https://github.com/user-attachments/assets/e9d48ff7-b14c-4874-9521-fe59e915bc76" controls width="640">
27+
View the video [here](https://github.com/user-attachments/assets/e9d48ff7-b14c-4874-9521-fe59e915bc76).
28+
</video>
29+
30+
The implementation is based on Rust no\_std and Bevy 0.15 no\_std, plus mipidsi crate
31+
32+
```
33+
cd esp32-c6-waveshare-1_47
34+
cargo run --release
35+
```
36+
2237
### ESP32-S3-BOX-3
2338

2439
![ESP32 Conways Game of Life in Rust - ESP32-S3-BOX-3 with Bevy ECS](esp32-s3-box-3-conway.jpg)
@@ -43,21 +58,6 @@ cd esp32-s3-box-3
4358
cargo run --release
4459
```
4560

46-
### ESP32-C6-LCD-1.47 Waveshare
47-
48-
[Rust Bare Metal no_std](https://developer.espressif.com/blog/2025/02/rust-esp-hal-beta/) with [Bevy ECS no_std](https://github.com/bevyengine/bevy/issues/15460) on 1.47 inch [ESP32-C6 LCD Waheshare](https://www.waveshare.com/esp32-c6-lcd-1.47.htm) with DMA and framebuffer - [Conway's Game of Life](https://github.com/georgik/esp32-conways-game-of-life-rs/tree/main/esp32-c6-waveshare-1_47):
49-
50-
<video src="https://github.com/user-attachments/assets/e9d48ff7-b14c-4874-9521-fe59e915bc76" controls width="640">
51-
View the video [here](https://github.com/user-attachments/assets/e9d48ff7-b14c-4874-9521-fe59e915bc76).
52-
</video>
53-
54-
The implementation is based on Rust no\_std and Bevy 0.15 no\_std, plus mipidsi crate
55-
56-
```
57-
cd esp32-c6-waveshare-1_47
58-
cargo run --release
59-
```
60-
6161
### ESP32-C3-LCDKit
6262

6363
Limitation: Framebuffer fits only to 240x190 pixels. Might be cause by allocation on stack instead of heap.
@@ -82,13 +82,11 @@ python3 -m http.server
8282

8383
This board is no longer in production, yet it's still used by many developers.
8484

85+
![ESP32 Conways Game of Life in Rust - ESP-WROVER-KIT with Bevy ECS](esp32-wrover-kit.jpg)
86+
8587
The implementation is based on Rust no\_std, using mipidsi crate and Bevy ECS.
8688
It requires es-rs toolchain for ESP32-S3 version at [least 1.85](https://github.com/esp-rs/rust-build/releases/tag/v1.85.0.0), because of edition 2024.
8789

88-
Limitation: Graphical buffer is limited to 320x100 pixels due to memory issue.
89-
PSRAM should work, but for some reason the buffer is not allocated there.
90-
Some previous examples were working with PSRAM fine, it needs further investigation
91-
9290
Installation of the toolchain:
9391

9492
```

docs/esp32-wrover-kit.jpg

99.2 KB
Loading

esp32-wrover-kit/src/main.rs

Lines changed: 47 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,51 @@ type MyDisplay = mipidsi::Display<
5555

5656
// --- LCD Resolution and FrameBuffer Type Aliases ---
5757
const LCD_H_RES: usize = 320;
58-
const LCD_V_RES: usize = 100;
58+
const LCD_V_RES: usize = 240;
5959
const LCD_BUFFER_SIZE: usize = LCD_H_RES * LCD_V_RES;
6060

61+
use embedded_graphics::pixelcolor::PixelColor;
62+
use embedded_graphics_framebuf::backends::FrameBufferBackend;
63+
64+
/// A wrapper around a boxed array that implements FrameBufferBackend.
65+
/// This allows the framebuffer to be allocated on the heap.
66+
pub struct HeapBuffer<C: PixelColor, const N: usize>(Box<[C; N]>);
67+
68+
impl<C: PixelColor, const N: usize> HeapBuffer<C, N> {
69+
pub fn new(data: Box<[C; N]>) -> Self {
70+
Self(data)
71+
}
72+
}
73+
74+
impl<C: PixelColor, const N: usize> core::ops::Deref for HeapBuffer<C, N> {
75+
type Target = [C; N];
76+
fn deref(&self) -> &Self::Target {
77+
&*self.0
78+
}
79+
}
80+
81+
impl<C: PixelColor, const N: usize> core::ops::DerefMut for HeapBuffer<C, N> {
82+
fn deref_mut(&mut self) -> &mut Self::Target {
83+
&mut *self.0
84+
}
85+
}
86+
87+
impl<C: PixelColor, const N: usize> FrameBufferBackend for HeapBuffer<C, N> {
88+
type Color = C;
89+
fn set(&mut self, index: usize, color: Self::Color) {
90+
self.0[index] = color;
91+
}
92+
fn get(&self, index: usize) -> Self::Color {
93+
self.0[index]
94+
}
95+
fn nr_elements(&self) -> usize {
96+
N
97+
}
98+
}
99+
100+
61101
// We want our pixels stored as Rgb565.
62-
type FbBuffer = [Rgb565; LCD_BUFFER_SIZE];
102+
type FbBuffer = HeapBuffer<Rgb565, LCD_BUFFER_SIZE>;
63103
// Define a type alias for the complete FrameBuf.
64104
type MyFrameBuf = FrameBuf<Rgb565, FbBuffer>;
65105

@@ -70,13 +110,15 @@ struct FrameBufferResource {
70110

71111
impl FrameBufferResource {
72112
fn new() -> Self {
73-
// Allocate the framebuffer data as an owned array of Rgb565.
74-
let fb_data: FbBuffer = *Box::new([Rgb565::BLACK; LCD_BUFFER_SIZE]);
75-
let frame_buf = MyFrameBuf::new(fb_data, LCD_H_RES, LCD_V_RES);
113+
// Allocate the framebuffer data on the heap.
114+
let fb_data: Box<[Rgb565; LCD_BUFFER_SIZE]> = Box::new([Rgb565::BLACK; LCD_BUFFER_SIZE]);
115+
let heap_buffer = HeapBuffer::new(fb_data);
116+
let frame_buf = MyFrameBuf::new(heap_buffer, LCD_H_RES, LCD_V_RES);
76117
Self { frame_buf }
77118
}
78119
}
79120

121+
80122
// --- Game of Life Definitions ---
81123
// Now each cell is a u8 (0 means dead; >0 indicates age)
82124
const GRID_WIDTH: usize = 64;

0 commit comments

Comments
 (0)