【rust/esp32】初识slint ui框架并在st7789 lcd上显示

文章目录

  • 说在前面
  • 关于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自动编译ui代码
slint::include_modules!();
#[entry]
fn main() -> ! {init_heap();// slint 设置默认backendslint::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();// 由于我的lcd不支持触屏 这里模拟了下按钮点击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;// 初始化spilet 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();// spi interfacelet di = SPIInterfaceNoCS::new(spi, dc);// st7789 驱动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();// 这里的大致流程是:// slint会计算出当前帧需要变化的像素// 结果会暂时存放在buffer_provider// 然后将buffer_provider中的数据传给spiif 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::LineBufferProviderfor &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);// We send empty data just to get the device in the right windowself.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();}
}

结果

  • 还是有卡顿的感觉
    在这里插入图片描述

参考

  • slint mcu

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/130751.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【音视频 | opus】opus编码的Ogg封装文件详解

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; &#x1f923;本文内容&#x1f923;&a…

汇编语言(举个栗子)

汇编语言&#xff08;Assembly Language&#xff09;是任何一种用于电子计算机、微处理器、微控制器或其他可编程器件的低级语言&#xff0c;亦称为符号语言。在汇编语言中&#xff0c;用助记符代替机器指令的操作码&#xff0c;用地址符号或标号代替指令或操作数的地址。在不同…

基于51单片机土壤湿度检测及自动浇花系统仿真(带时间显示)

wx供重浩&#xff1a;创享日记 对话框发送&#xff1a;单片机浇花 获取完整源码源文件仿真源文件原理图源文件论文报告等 单片机土壤湿度检测及自动浇花系统仿真&#xff08;带时间显示&#xff09; 具体功能&#xff1a; &#xff08;1&#xff09;液晶第一行显示实际湿度&am…

信道编码译码及MATLAB仿真

文章目录 前言一、什么是信道编码&#xff1f;二、信道编码的基本逻辑—冗余数据1、奇偶检验码2、重复码 三、编码率四、4G 和 5G 的信道编码1、卷积码2、维特比译码&#xff08;Viterbi&#xff09;—— 概率译码3、LTE 的咬尾卷积码4、LTE 的 turbo 码 五、MATLAB 仿真1、plo…

0008Java安卓程序设计-ssm基于Android平台的健康管理系统

文章目录 **摘要**目录系统实现开发环境 编程技术交流、源码分享、模板分享、网课教程 &#x1f427;裙&#xff1a;776871563 摘要 首先,论文一开始便是清楚的论述了系统的研究内容。其次,剖析系统需求分析,弄明白“做什么”,分析包括业务分析和业务流程的分析以及用例分析,…

Git 的基本操作 ——命令行

Git 的工作流程 详解如下&#xff1a; 本地仓库&#xff1a;是在开发人员自己电脑上的Git仓库,存放我们的代码(.git 隐藏文件夹就是我们的本地仓库) 远程仓库&#xff1a;是在远程服务器上的Git仓库,存放代码(可以是github.com或者gitee.com 上的仓库,或者自己该公司的服务器…

【ElasticSearch系列-05】SpringBoot整合elasticSearch

ElasticSearch系列整体栏目 内容链接地址【一】ElasticSearch下载和安装https://zhenghuisheng.blog.csdn.net/article/details/129260827【二】ElasticSearch概念和基本操作https://blog.csdn.net/zhenghuishengq/article/details/134121631【三】ElasticSearch的高级查询Quer…

PTA:前序序列创建二叉树

前序序列创建二叉树 题目输入格式输出格式输入样例&#xff08;及其对应的二叉树&#xff09;输出样例 代码 题目 编一个程序&#xff0c;读入用户输入的一串先序遍历字符串&#xff0c;根据此字符串建立一个二叉树&#xff08;以二叉链表存储&#xff09;。 例如如下的先序遍…

SpringCloudAlibaba - 项目完整搭建(Nacos + OpenFeign + Getway + Sentinel)

目录 一、SpringCloudAlibaba 项目完整搭建 1.1、初始化项目 1.1.1、创建工程 1.1.2、配置父工程的 pom.xml 1.1.3、创建子模块 1.2、user 微服务 1.2.1、配置 pom.xml 1.2.2、创建 application.yml 配置文件 1.2.3、创建启动类 1.2.4、测试 1.3、product 微服务 1…

如何使用CodeceptJS、Playwright和GitHub Actions构建端到端测试流水线

介绍 端到端测试是软件开发的一个重要方面&#xff0c;因为它确保系统的所有组件都能正确运行。CodeceptJS是一个高效且强大的端到端自动化框架&#xff0c;与Playwright 结合使用时&#xff0c;它成为自动化Web、移动甚至桌面 (Electron.js) 应用程序比较好用的工具。 在本文中…

代码随想录算法训练营第23期day38|动态规划理论基础、509. 斐波那契数、70. 爬楼梯、746. 使用最小花费爬楼梯

目录 一、动态规划理论基础 1.动态规划的解题步骤 2.动态规划应该如何debug 二、&#xff08;leetcode 509&#xff09;斐波那契数 1.递归解法 2.动态规划 1&#xff09;确定dp数组以及下标的含义 2&#xff09;确定递推公式 3&#xff09;dp数组如何初始化 4&#x…

C++虚表与虚表指针详解

类的虚表 每个包含了虚函数的类都包含一个虚表。 当一个类&#xff08;B&#xff09;继承另一个类&#xff08;A&#xff09;时&#xff0c;类B会继承类A的函数的调用权。所以如果一个基类包含了虚函数&#xff0c;那么其继承类也可调用这些虚函数&#xff0c;换句话说&…

基于ASP.NET MVC + Bootstrap的仓库管理系统

基于ASP.NET MVC Bootstrap的仓库管理系统。源码亲测可用&#xff0c;含有简单的说明文档。 适合单仓库&#xff0c;基本的仓库入库管理&#xff0c;出库管理&#xff0c;盘点&#xff0c;报损&#xff0c;移库&#xff0c;库位等管理&#xff0c;有着可视化图表。 系统采用Bo…

MySQL导入数据库报错Error Code: 2006

Error Code: 2006 - MySQL server has gone away 因为导入的某张表数据过大导致导入中途失败 , 修改max_allowed_packet 即可解决。 SET GLOBAL max_allowed_packet 1024*1024*200;

【数据结构】数组和字符串(十五):字符串匹配2:KMP算法(Knuth-Morris-Pratt)

文章目录 4.3 字符串4.3.1 字符串的定义与存储4.3.2 字符串的基本操作4.3.3 模式匹配算法0. 朴素模式匹配算法1. ADL语言2. KMP算法分析3. 手动求失败函数定义例1例2例3 4. 自动求失败函数&#xff08;C语言&#xff09;5. KMP算法&#xff08;C语言&#xff09;6. 失败函数答案…

STM32F103C8T6第二天:按键点灯轮询法和中断法、RCC、电动车报警器(振动传感器、继电器、喇叭、433M无线接收发射模块)

1. 点亮LED灯详解&#xff08;307.11&#xff09; 标号一样的导线在物理上是连接在一起的。 将 PB8 或 PB9 拉低&#xff0c;就可以实现将对应的 LED 灯点亮。常用的GPIO HAL库函数&#xff1a; void HAL_GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_Init);//I/…

产品经理入门学习(二):产品经理问题思考维度

参考引用 黑马-产品经理入门基础课程 1. 抓住核心用户 1.1 为什么要抓住核心用户 什么是用户&#xff1f; 所有和产品有关系的群体就是用户&#xff0c;他们是一群既有共性&#xff0c;又有差异的群体组合 做产品为什么要了解用户&#xff1f; 了解用户的付费点、更好的优化产…

【软考中级】软件设计师-下午题

下午题 试题一 黑洞&#xff1a;加工有输入无输出 白洞(奇迹)&#xff1a;加工有输出无输入 灰洞&#xff1a;数据流输入的加工不足以产生输出 结构化语言&#xff1a; IF *** THEN ELSE IF *** THEN ******* END IF END IF 数据流的父子图平衡&#xff0c;如果父子图平衡就不…

【CIO人物展】黄淮学院副CIO周鹏:构建数智化平台赋能学校高质量发展

周鹏 本文由黄淮学院副CIO周鹏投递并参与《2023中国数智化转型升级优秀CIO》榜单/奖项评选。丨推荐企业—锐捷网络 大数据产业创新服务媒体 ——聚焦数据 改变商业 黄淮学院是2004年经教育部批准成立的一所省属全日制普通本科高校。学校位于素有“豫州之腹地、天下之最中”之美…

地理信息系统原理-空间数据结构(7)

​四叉树编码 1.四叉树编码定义 四叉树数据结构是一种对栅格数据的压缩编码方法&#xff0c;其基本思想是将一幅栅格数据层或图像等分为四部分&#xff0c;逐块检查其格网属性值&#xff08;或灰度&#xff09;&#xff1b;如果某个子区的所有格网值都具有相同的值&#xff0…