33
44extern crate alloc;
55use alloc:: boxed:: Box ;
6+ use embedded_graphics_framebuf:: backends:: FrameBufferBackend ;
67
8+ use bevy_ecs:: prelude:: * ;
79use core:: fmt:: Write ;
8- use embedded_hal:: delay:: DelayNs ;
910use embedded_graphics:: {
10- mono_font:: { ascii:: FONT_8X13 , MonoTextStyle } ,
11+ Drawable ,
12+ mono_font:: { MonoTextStyle , ascii:: FONT_8X13 } ,
1113 pixelcolor:: Rgb565 ,
1214 prelude:: * ,
1315 primitives:: { PrimitiveStyle , Rectangle } ,
1416 text:: Text ,
15- Drawable ,
1617} ;
1718use embedded_graphics_framebuf:: FrameBuf ;
19+ use embedded_hal:: delay:: DelayNs ;
20+ use embedded_hal_bus:: spi:: ExclusiveDevice ;
1821use esp_hal:: delay:: Delay ;
22+ use esp_hal:: dma:: { DmaRxBuf , DmaTxBuf } ;
23+ use esp_hal:: dma_buffers;
1924use esp_hal:: {
20- gpio:: { Level , Output , OutputConfig , DriveMode } ,
21- rng:: Rng ,
22- spi:: master:: { Spi , SpiDmaBus } ,
2325 Blocking ,
26+ gpio:: { DriveMode , Level , Output , OutputConfig } ,
2427 main,
28+ rng:: Rng ,
29+ spi:: master:: { Spi , SpiDmaBus } ,
2530 time:: Rate ,
2631} ;
27- use esp_hal:: dma:: { DmaRxBuf , DmaTxBuf } ;
28- use esp_hal:: dma_buffers;
29- use embedded_hal_bus:: spi:: ExclusiveDevice ;
3032use esp_println:: { logger:: init_logger_from_env, println} ;
3133use log:: info;
32- use mipidsi:: { interface:: SpiInterface , options:: { ColorInversion , Orientation , ColorOrder } } ;
33- use mipidsi:: { models:: ILI9486Rgb565 , Builder } ;
34- use bevy_ecs:: prelude:: * ; // includes NonSend and NonSendMut
34+ use mipidsi:: { Builder , models:: ILI9486Rgb565 } ;
35+ use mipidsi:: {
36+ interface:: SpiInterface ,
37+ options:: { ColorInversion , ColorOrder , Orientation } ,
38+ } ; // includes NonSend and NonSendMut
3539
3640#[ panic_handler]
3741fn panic ( _info : & core:: panic:: PanicInfo ) -> ! {
3842 println ! ( "Panic: {}" , _info) ;
3943 loop { }
4044}
4145
46+ /// A wrapper around a boxed array that implements FrameBufferBackend.
47+ /// This allows the framebuffer to be allocated on the heap.
48+ pub struct HeapBuffer < C : PixelColor , const N : usize > ( Box < [ C ; N ] > ) ;
49+
50+ impl < C : PixelColor , const N : usize > HeapBuffer < C , N > {
51+ pub fn new ( data : Box < [ C ; N ] > ) -> Self {
52+ Self ( data)
53+ }
54+ }
55+
56+ impl < C : PixelColor , const N : usize > core:: ops:: Deref for HeapBuffer < C , N > {
57+ type Target = [ C ; N ] ;
58+ fn deref ( & self ) -> & Self :: Target {
59+ & * self . 0
60+ }
61+ }
62+
63+ impl < C : PixelColor , const N : usize > core:: ops:: DerefMut for HeapBuffer < C , N > {
64+ fn deref_mut ( & mut self ) -> & mut Self :: Target {
65+ & mut * self . 0
66+ }
67+ }
68+
69+ impl < C : PixelColor , const N : usize > FrameBufferBackend for HeapBuffer < C , N > {
70+ type Color = C ;
71+ fn set ( & mut self , index : usize , color : Self :: Color ) {
72+ self . 0 [ index] = color;
73+ }
74+ fn get ( & self , index : usize ) -> Self :: Color {
75+ self . 0 [ index]
76+ }
77+ fn nr_elements ( & self ) -> usize {
78+ N
79+ }
80+ }
81+
4282// --- Type Alias for the Concrete Display ---
4383// Use the DMA-enabled SPI bus type.
4484type MyDisplay = mipidsi:: Display <
4585 SpiInterface <
4686 ' static ,
4787 ExclusiveDevice < SpiDmaBus < ' static , Blocking > , Output < ' static > , Delay > ,
48- Output < ' static >
88+ Output < ' static > ,
4989 > ,
5090 ILI9486Rgb565 ,
51- Output < ' static >
91+ Output < ' static > ,
5292> ;
5393
5494// --- LCD Resolution and FrameBuffer Type Aliases ---
@@ -57,7 +97,7 @@ const LCD_V_RES: usize = 240;
5797const LCD_BUFFER_SIZE : usize = LCD_H_RES * LCD_V_RES ;
5898
5999// We want our pixels stored as Rgb565.
60- type FbBuffer = [ Rgb565 ; LCD_BUFFER_SIZE ] ;
100+ type FbBuffer = HeapBuffer < Rgb565 , LCD_BUFFER_SIZE > ;
61101// Define a type alias for the complete FrameBuf.
62102type MyFrameBuf = FrameBuf < Rgb565 , FbBuffer > ;
63103
@@ -68,9 +108,10 @@ struct FrameBufferResource {
68108
69109impl FrameBufferResource {
70110 fn new ( ) -> Self {
71- // Allocate the framebuffer data as an owned array of Rgb565.
72- let fb_data: FbBuffer = * Box :: new ( [ Rgb565 :: BLACK ; LCD_BUFFER_SIZE ] ) ;
73- let frame_buf = MyFrameBuf :: new ( fb_data, LCD_H_RES , LCD_V_RES ) ;
111+ // Allocate the framebuffer data on the heap.
112+ let fb_data: Box < [ Rgb565 ; LCD_BUFFER_SIZE ] > = Box :: new ( [ Rgb565 :: BLACK ; LCD_BUFFER_SIZE ] ) ;
113+ let heap_buffer = HeapBuffer :: new ( fb_data) ;
114+ let frame_buf = MyFrameBuf :: new ( heap_buffer, LCD_H_RES , LCD_V_RES ) ;
74115 Self { frame_buf }
75116 }
76117}
@@ -100,7 +141,9 @@ fn update_game_of_life(grid: &mut [[u8; GRID_WIDTH]; GRID_HEIGHT]) {
100141 let mut alive_neighbors = 0 ;
101142 for i in 0 ..3 {
102143 for j in 0 ..3 {
103- if i == 1 && j == 1 { continue ; }
144+ if i == 1 && j == 1 {
145+ continue ;
146+ }
104147 let nx = ( x + i + GRID_WIDTH - 1 ) % GRID_WIDTH ;
105148 let ny = ( y + j + GRID_HEIGHT - 1 ) % GRID_HEIGHT ;
106149 if grid[ ny] [ nx] > 0 {
@@ -128,7 +171,7 @@ fn update_game_of_life(grid: &mut [[u8; GRID_WIDTH]; GRID_HEIGHT]) {
128171 * grid = new_grid;
129172}
130173
131- /// Maps cell age (1..=max_age) to a color. Newborn cells are dark blue and older cells become brighter (toward white).
174+ /// Maps cell age (1... =max_age) to a color. Newborn cells are dark blue and older cells become brighter (toward white).
132175fn age_to_color ( age : u8 ) -> Rgb565 {
133176 if age == 0 {
134177 Rgb565 :: BLACK
@@ -315,7 +358,11 @@ fn main() -> ! {
315358 display_delay. delay_ns ( 500_000u32 ) ;
316359
317360 // Reset pin: OpenDrain required for ESP32-S3-BOX! Tricky setting.
318- let reset = Output :: new ( peripherals. GPIO48 , Level :: High , OutputConfig :: default ( ) . with_drive_mode ( DriveMode :: OpenDrain ) ) ;
361+ let reset = Output :: new (
362+ peripherals. GPIO48 ,
363+ Level :: High ,
364+ OutputConfig :: default ( ) . with_drive_mode ( DriveMode :: OpenDrain ) ,
365+ ) ;
319366 // Initialize the display using mipidsi's builder.
320367 let mut display: MyDisplay = Builder :: new ( ILI9486Rgb565 , di)
321368 . reset_pin ( reset)
0 commit comments