文章目录 说在前面 关于slint 关于no-std 关于dma 准备工作 相关依赖 代码 结果 参考
说在前面
esp32版本:s3 运行环境:no-std 开发环境:wsl2 LCD模块:ST7789V2 240*280 LCD Slint版本:master分支 github地址:这里
关于slint
官网 为啥不用lvgl
? 只能说rust的生态还是不太行,lvgl的rust binding似乎还在开发中,已经有仓库了,但是还在开发中。 slint
目前比较完善,但是相关资料也少。 反正已经在折腾rust
了,也不在乎再多折腾个小众点的。
关于no-std
上一篇还是std
环境,怎么就变成no-std
了? std
环境下也折腾了slint
,但是fps就是不怎么高 (可能哪里写的不对) ,然后就试了下no-std
,稍微丝滑点,并且编译也快。
关于dma
rust
生态下dma
的资料更是少的可怜,找了好久也没啥进展,所以本文不涉及dma
准备工作
引脚连接见上篇 开发环境部分,由于不需要esp idf
,简单很多,cargo
直接搞定
相关依赖
Cargo.toml[ dependencies]
hal = { package = "esp32s3- hal", version = "0.13.0"}
esp- backtrace = { version = "0.9.0", features = [ "esp32s3" , "panic-handler" , "exception-handler" , "print-uart" ] }
esp- println = { version = "0.7.0", features = [ "esp32s3" , "log" ] }
log = { version = "0.4.18" }
esp- alloc = { version = "0.3.0" }
embedded- hal = "0.2.7"
embedded- graphics- core = "0.4.0"
embedded- graphics = "0.8.1"
embedded- graphics- framebuf = "0.5.0"
display- interface = "0.4"
display- interface- spi = "0.4"
mipidsi = "0.7.1"
slint = { git = "https: //githubfast.com/slint- ui/slint", default- features = false, features = [ "compat-1-2" , "unsafe-single-threaded" , "libm" , "renderer-software" ] } [ build- dependencies]
slint- build = { git = "https: //githubfast.com/slint- ui/slint" }
代码
#![no_std]
#![no_main] extern crate alloc ;
use alloc:: boxed:: Box ;
use alloc:: rc:: Rc ;
use rs_esp32s3_no_std_st7789_demo:: dma:: DmaBackend ;
use core:: cell:: RefCell ;
use core:: mem:: MaybeUninit ;
use display_interface_spi:: SPIInterfaceNoCS ;
use embedded_graphics_core:: prelude:: { DrawTarget , Point , RgbColor , Size } ;
use embedded_graphics_core:: { pixelcolor:: raw:: RawU16 , primitives:: Rectangle } ;
use esp_backtrace as _;
use esp_println:: println;
use hal:: spi:: master:: { Spi , dma} ;
use hal:: { clock:: { ClockControl , CpuClock } , peripherals:: Peripherals , prelude:: * , spi:: SpiMode , systimer:: SystemTimer , timer:: TimerGroup , Delay , Rtc , IO ,
} ;
use mipidsi:: Display ; #[global_allocator]
static ALLOCATOR : esp_alloc:: EspHeap = esp_alloc:: EspHeap :: empty ( ) ;
fn init_heap ( ) { const HEAP_SIZE : usize = 250 * 1024 ; static mut HEAP : MaybeUninit < [ u8 ; HEAP_SIZE ] > = MaybeUninit :: uninit ( ) ; unsafe { ALLOCATOR . init ( HEAP . as_mut_ptr ( ) as * mut u8 , HEAP_SIZE ) ; }
}
slint:: include_modules! ( ) ;
#[entry]
fn main ( ) -> ! { init_heap ( ) ; slint:: platform:: set_platform ( Box :: new ( EspBackend :: default ( ) ) ) . expect ( "backend already initialized" ) ; let main_window = Recipe :: new ( ) . unwrap ( ) ; let strong = main_window. clone_strong ( ) ; let timer = slint:: Timer :: default ( ) ; timer. start ( slint:: TimerMode :: Repeated , core:: time:: Duration :: from_millis ( 1000 ) , move | | { if strong. get_counter ( ) <= 0 { strong. set_counter ( 25 ) ; } else { strong. set_counter ( 0 ) ; } } , ) ; main_window. run ( ) . unwrap ( ) ; panic! ( "The MCU demo should not quit" ) ;
} #[derive(Default)]
pub struct EspBackend { window: RefCell < Option < Rc < slint:: platform:: software_renderer:: MinimalSoftwareWindow >> > ,
} impl slint:: platform:: Platform for EspBackend { fn create_window_adapter ( & self , ) -> Result < Rc < dyn slint:: platform:: WindowAdapter > , slint:: PlatformError > { let window = slint:: platform:: software_renderer:: MinimalSoftwareWindow :: new ( slint:: platform:: software_renderer:: RepaintBufferType :: ReusedBuffer , ) ; self . window. replace ( Some ( window. clone ( ) ) ) ; Ok ( window) } fn duration_since_start ( & self ) -> core:: time:: Duration { core:: time:: Duration :: from_millis ( SystemTimer :: now ( ) / ( SystemTimer :: TICKS_PER_SECOND / 1000 ) , ) } fn run_event_loop ( & self ) -> Result < ( ) , slint:: PlatformError > { let peripherals = Peripherals :: take ( ) ; let mut system = peripherals. SYSTEM . split ( ) ; let clocks = ClockControl :: configure ( system. clock_control, CpuClock :: Clock240MHz ) . freeze ( ) ; let mut rtc = Rtc :: new ( peripherals. RTC_CNTL ) ; let timer_group0 = TimerGroup :: new ( peripherals. TIMG0 , & clocks) ; let mut wdt0 = timer_group0. wdt; let timer_group1 = TimerGroup :: new ( peripherals. TIMG1 , & clocks) ; let mut wdt1 = timer_group1. wdt; rtc. rwdt. disable ( ) ; wdt0. disable ( ) ; wdt1. disable ( ) ; let mut delay = Delay :: new ( & clocks) ; let io = IO :: new ( peripherals. GPIO , peripherals. IO_MUX ) ; let clk = io. pins. gpio18; let sdo = io. pins. gpio17; let cs = io. pins. gpio14; let spi = Spi :: new_no_miso ( peripherals. SPI2 , clk, sdo, cs, 60u32 . MHz ( ) , SpiMode :: Mode0 , & clocks, ) ; println! ( "spi init." ) ; let dc = io. pins. gpio15. into_push_pull_output ( ) ; let rst = io. pins. gpio16. into_push_pull_output ( ) ; let di = SPIInterfaceNoCS :: new ( spi, dc) ; let mut display = mipidsi:: Builder :: st7789 ( di) . with_display_size ( 240 , 280 ) . with_window_offset_handler ( | _| ( 0 , 20 ) ) . with_framebuffer_size ( 240 , 280 ) . with_invert_colors ( mipidsi:: ColorInversion :: Inverted ) . init ( & mut delay, Some ( rst) ) . unwrap ( ) ; println! ( "display init." ) ; let mut bl = io. pins. gpio13. into_push_pull_output ( ) ; bl. set_high ( ) . unwrap ( ) ; let size = slint:: PhysicalSize :: new ( 240 , 280 ) ; self . window. borrow ( ) . as_ref ( ) . unwrap ( ) . set_size ( size) ; let mut buffer_provider = DrawBuffer { display, buffer: & mut [ slint:: platform:: software_renderer:: Rgb565Pixel :: default ( ) ; 240 ] , } ; loop { slint:: platform:: update_timers_and_animations ( ) ; if let Some ( window) = self . window. borrow ( ) . clone ( ) { window. draw_if_needed ( | renderer| { renderer. render_by_line ( & mut buffer_provider) ; } ) ; if window. has_active_animations ( ) { continue ; } } } } fn debug_log ( & self , arguments: core:: fmt:: Arguments ) { println! ( "{}" , arguments) ; }
} struct DrawBuffer < 'a , Display > { display: Display , buffer: & 'a mut [ slint:: platform:: software_renderer:: Rgb565Pixel ] ,
} impl < DI : display_interface:: WriteOnlyDataCommand , RST : embedded_hal:: digital:: v2:: OutputPin > slint:: platform:: software_renderer:: LineBufferProvider for & mut DrawBuffer < '_ , Display < DI , mipidsi:: models:: ST7789 , RST >>
{ type TargetPixel = slint:: platform:: software_renderer:: Rgb565Pixel ; fn process_line ( & mut self , line: usize , range: core:: ops:: Range < usize > , render_fn: impl FnOnce ( & mut [ slint:: platform:: software_renderer:: Rgb565Pixel ] ) , ) { let buffer = & mut self . buffer[ range. clone ( ) ] ; render_fn ( buffer) ; self . display. set_pixels ( range. start as u16 , line as _, range. end as u16 , line as u16 , buffer. iter ( ) . map ( | x| embedded_graphics_core:: pixelcolor:: raw:: RawU16 :: new ( x.0 ) . into ( ) ) , ) . unwrap ( ) ; }
}
结果
还是有卡顿的感觉
参考