拓冰建站拓冰建站
首页 / 资讯中心 / 正文

Slint MCU 板级支持实战:在 Raspberry Pi Pico、STM32 与 ESP32-S3 上部署裸机 GUI

Slint MCU 板级支持实战在 Raspberry Pi Pico、STM32 与 ESP32-S3 上部署裸机 GUI【免费下载链接】slintSlint is an open-source declarative GUI toolkit to build native user interfaces for Rust, C, JavaScript, or Python apps.项目地址: https://gitcode.com/GitHub_Trending/sl/slint本篇指南以仓库中的 examples/mcu-board-support/README.md 为骨架完整讲解 Slint 的 MCU 后端mcu-board-supportcrate在无操作系统裸机环境下的使用方式从entry宏与init()的接入、Cargo.toml与build.rs的配置到 printerdemo_mcu 示例在模拟器、Raspberry Pi Pico/Pico2、STM32H735G-DK/STM32U5G9J-DK2 以及多款 ESP32-S3 开发板上的编译、烧录与调试全流程。读完本文你将能够把一个.slint界面工程移植到小屏 MCU 目标板上并理解底层软件渲染、触摸事件与事件循环的源码实现。更底层的裸机移植原理Platformtrait、软件渲染器、事件循环与LineBufferProvider参见配套文档 api/rs/slint/mcu.md本文会在最后一节结合源码作深入导读。mcu-board-support 是什么mcu-board-support是一个内部辅助 cratepublish false为 Slint 官方示例提供不同 MCU 的板级支持它封装了slint::platform::Platformtrait 的实现并附带触摸输入与系统定时器支持。它的核心价值在于——你不需要从头编写显示控制器驱动、触摸驱动和事件循环只需启用对应板的 feature 即可。从 examples/mcu-board-support/lib.rs 可以看到它的设计crate 根部用#[cfg(feature ...)]按板卡条件编译对应模块并为每个板卡导出entry宏和init()函数Pico 系与 STM32 系基于cortex-m-rtpub use cortex_m_rt::entry;ESP32-S3 系基于esp-halpub use esp_hal::main as entry;未启用任何板卡 feature 时如模拟器模式回退到i_slint_core_macros::identity as entryinit()为空实现。这就是为什么同样的main.rs可以不加修改地在模拟器与真机上运行——entry宏和init()的具体行为由编译期 feature 决定。同时 crate 还导出了一个prelude模块在 ESP32 场景下会 re-exportesp_hal便于应用代码直接使用。该 crate 拥有独立 workspace见 examples/mcu-board-support/Cargo.toml因为不同板卡的 HALesp-hal、rp235x-hal等对riscv-rt链接库的版本要求互不兼容无法在共享的 examples lock file 中同时解析独立 workspace 加上仓库根.cargo/config.toml共享target/目录保证同一时间只把单块板的依赖引入构建图。使用方式entry 宏与 init()该 crate re-export 一个entry属性宏应用在main函数上和一个init()函数必须在创建 Slint UI 之前调用。要使用这个后端最终程序必须同时依赖slint与mcu-board-support。典型的main.rs如下摘自原文档#![no_std] #![cfg_attr(not(feature simulator), no_main)] slint::include_modules!(); #[allow(unused_imports)] use mcu_board_support::prelude::*; #[mcu_board_support::entry] fn main() - ! { mcu_board_support::init(); MainWindow::new().run(); panic!(The event loop should not return); }几个关键点#![no_std]裸机环境下没有标准库#![cfg_attr(not(feature simulator), no_main)]使得除模拟器外都不使用main入口而是由entry宏生成的启动入口接管。slint::include_modules!()把build.rs编译生成的 Rust 代码对应.slint文件中的组件如MainWindow引入当前 crate。init()内部完成堆分配器初始化、时钟/外设配置、显示与触摸驱动初始化并调用slint::platform::set_platform(...)注册后端随后MainWindow::new().run()才会正常工作。panic!(The event loop should not return)run()内部的事件循环按设计不应返回一旦返回即视为错误。真实示例可以参考 demos/printerdemo_mcu/main.rs它在init()之后设置墨水量全局属性、用VecModel构建打印队列、通过slint::Timer每秒更新打印进度最后调用main_window.run().unwrap()——这与上面的最小骨架完全一致只是多了业务逻辑。依赖配置Cargo.toml 与 build.rs由于mcu-board-support目前是未上传到 crates.io 的内部 crate你必须使用 Slint 的 git 版本且slint、slint-build、mcu-board-support三者都要指向同一仓库原文档给出的配置[dependencies] slint { git https://github.com/slint-ui/slint, default-features false } mcu-board-support { git https://github.com/slint-ui/slint } # ... [build-dependencies] slint-build { git https://github.com/slint-ui/slint }注意slint必须关闭默认 featuredefault-features false因为默认 feature 面向宿主环境、包含std。裸机场景需要的是unsafe-single-threaded用 unsafe static 替代thread_local!存储全局数据要求仅在单线程、不在中断处理程序中调用 Slint API、libm提供浮点运算 trait 与函数与renderer-software内置软件渲染器等 feature——这些在 examples/mcu-board-support/Cargo.toml 的每个板卡 feature 里都通过slint/unsafe-single-threaded、slint/libm的形式被自动启用。在build.rs中必须调用slint_build::print_rustc_flags().unwrap()来设置部分编译/链接 flags。demos/printerdemo_mcu/build.rs 展示了完整写法fn main() { let config slint_build::CompilerConfiguration::new() .embed_resources(slint_build::EmbedResourcesKind::EmbedForSoftwareRenderer); slint_build::compile_with_config(ui/printerdemo.slint, config).unwrap(); slint_build::print_rustc_flags().unwrap(); }其中EmbedResourcesKind::EmbedForSoftwareRenderer让编译器把图片与字体以适合软件渲染器的格式内嵌进二进制。此外各 Pico/STM32 板卡目录下的board_config.toml如 examples/mcu-board-support/pico_st7789/board_config.toml还声明了链接参数link_args [--nmagic, -Tlink.x, -Tdefmt.x] link_search_path [.]运行示例模拟器先行示例 demo 位于demosworkspace与仓库根 workspace 相互独立。以下命令均需在Slint 仓库根目录执行。先在 PC 上跑模拟器验证界面逻辑cargo run --manifest-path demos/printerdemo_mcu/Cargo.toml --featuressimulator --release模拟器模式由 demos/printerdemo_mcu/Cargo.toml 中的 feature 定义[features] simulator [slint/renderer-software, slint/backend-winit, slint/std] default [simulator]default [simulator]意味着不带任何--no-default-features参数时构建的正是模拟器版本而真机构建一律要--no-default-features再显式指定板卡 feature。Raspberry Pi Pico 系列部署PicoRP2040ST7789 屏构建命令原文档cargo build --manifest-path demos/printerdemo_mcu/Cargo.toml --no-default-features --featuresmcu-board-support/pico-st7789 --targetthumbv6m-none-eabi --release生成的固件可用elf2uf2-rs便捷烧录先安装cargo install elf2uf2-rs上传到 Pico 的步骤按住设备上的白色 bootsel 按钮同时将 micro-usb 线连接到设备设备会以 USB 存储形式挂载把二进制文件拷入即可。Linux 命令行方式按住 bootsel 连接设备后# If youre on Linux: mount the device udisksctl mount -b /dev/sda1 # upload elf2uf2-rs -d target/thumbv6m-none-eabi/release/printerdemo_mcu从源码看这块板的实现examples/mcu-board-support/pico_st7789/pico_st7789.rs堆大小HEAP_SIZE 200 * 1024使用embedded_alloc::LlffHeap作为全局分配器#[global_allocator]。显示为 320x240ST7789 控制器SPI 时钟上限按数据手册取 62.5 MHz代码中注释引用了 Waveshare ST7789 数据手册第 43 页触摸为 XPT2046SPI 3 MHz通过 GPIO17 低电平中断唤醒。事件循环是典型的超循环super loopupdate_timers_and_animations()→ 读取 XPT2046 触摸并转换为PointerPressed/PointerMoved/PointerReleased事件 →draw_if_needed里用render_by_line逐行渲染并通过 DMA 发送到屏幕PioTransfer用 RP2040 的 PIO DMA 异步搬运行数据→ 没有动画且无待处理定时器时用ALARM0调度下一次唤醒时间并执行cortex_m::asm::wfe()低功耗等待中断。Pico2RP2350ST7789 屏cargo build --manifest-path demos/printerdemo_mcu/Cargo.toml --no-default-features --featuresmcu-board-support/pico2-st7789 --targetthumbv8m.main-none-eabihf --release烧录工具改用picotool建议从源码编译。上传方式同样是按住 bootsel 连接后拷入Linux 命令行# If youre on Linux: mount the device udisksctl mount -b /dev/sda1 # upload picotool load -u -v -x -t elf target/thumbv8m.main-none-eabihf/release/printerdemo_mcuWaveshare Pico2 Touch LCD 2.8Waveshare Pico2 Touch LCD 2.8 是一块集成 2.8 电容触摸屏320x240ST7789 控制器CST328 触摸控制器的 Pico2 开发板cargo build --manifest-path demos/printerdemo_mcu/Cargo.toml --no-default-features --featuresmcu-board-support/pico2-touch-lcd-2-8 --targetthumbv8m.main-none-eabihf --release使用picotool烧录picotool load -u -v -x -t elf target/thumbv8m.main-none-eabihf/release/printerdemo_mcu这块板与前两块不同走的是Embassy 异步运行时路线pico2-touch-lcd-2-8feature 会启用embassy-executor、embassy-rp、embassy-time等依赖。实现见 examples/mcu-board-support/pico2_touch_lcd_2_8/pico2_touch_lcd_2_8.rs触摸控制器 CST328 通过 I2C1400 kHz读取代码内实现了完整的 CST328 寄存器命令序列调试信息模式 → 读取芯片 ID → 普通模式 → 读触摸数据触摸中断引脚 GPIO18 通过wait_for_event()异步等待低电平渲染则用双行缓冲 DMACPU 渲染进line_buffer_a同时 DMA 把上一行的dma_buffer通过 SPI162.5 MHz发送并用RenderingRotation::Rotate90处理 240x320 竖屏与 320x240 横屏逻辑坐标的映射。通用的事件循环由 examples/mcu-board-support/embassy.rs 中的EmbassyBackendPlatformImpl提供——它在run_event_loop里创建 Embassy executor异步任务循环执行更新定时器与动画 →draw_async_if_needed渲染 → 分发触摸事件 → 无动画时用select同时等待下一个定时器到期或平台事件。用 probe-rs 调试 Pico使用 probe-rs 需要把 Pico 通过调试探针连接例如用另一块运行探针固件的 Pico 充当 probe然后可以直接cargo runCARGO_TARGET_THUMBV6M_NONE_EABI_LINKERflip-link CARGO_TARGET_THUMBV6M_NONE_EABI_RUNNERprobe-rs run --chip RP2040 cargo run --manifest-path demos/printerdemo_mcu/Cargo.toml --no-default-features --featuresmcu-board-support/pico-st7789 --targetthumbv6m-none-eabi --releaseprobe-rs 的 VSCode 插件烧录与调试安装probe-rs-debugger与 VSCode 插件后在.vscode/tasks.json中添加如下构建任务原文档{ version: 2.0.0, tasks: [ { type: cargo, command: build, args: [ --manifest-pathdemos/printerdemo_mcu/Cargo.toml, --no-default-features, --featuresmcu-board-support/pico-st7789, --targetthumbv6m-none-eabi, --profilerelease-with-debug ], problemMatcher: [ $rustc ], group: build, label: build mcu demo for pico }, ] }之所以用release-with-debugprofile是因为debug 构建体积太大放不进 flash。可以在demos/Cargo.tomlworkspace 清单中这样定义它原文档[profile.release-with-debug] inherits release debug true然后在.vscode/launch.json添加启动配置{ version: 0.2.0, configurations: [ { preLaunchTask: build mcu demo for pico, type: probe-rs-debug, request: launch, name: Flash and Debug MCU Demo, cwd: ${workspaceFolder}, connectUnderReset: false, chip: RP2040, flashingConfig: { flashingEnabled: true, resetAfterFlashing: true, haltAfterReset: true }, coreConfigs: [ { coreIndex: 0, rttEnabled: true, programBinary: ./target/thumbv6m-none-eabi/release-with-debug/printerdemo_mcu } ] }, ] }这一套流程经过仓库维护者的实测使用第二块 Raspberry Pi Pico 刷入 DapperMime 固件充当调试探针完成验证。STM32 开发板STM32H735G-DK同样借助 probe-rsCARGO_PROFILE_RELEASE_OPT_LEVELs CARGO_TARGET_THUMBV7EM_NONE_EABIHF_RUNNERprobe-rs run --chip STM32H735IGKx cargo run --manifest-path demos/printerdemo_mcu/Cargo.toml --no-default-features --featuresmcu-board-support/stm32h735g --targetthumbv7em-none-eabihf --release对应 feature 依赖stm32h7xx-hal/stm32h735、embedded-display-controller、ft5336电容触摸等见 examples/mcu-board-support/Cargo.toml实现位于 examples/mcu-board-support/stm32h735g/stm32h735g.rs。STM32U5G9J-DK2CARGO_PROFILE_RELEASE_OPT_LEVELs CARGO_TARGET_THUMBV8M_MAIN_NONE_EABIHF_RUNNERprobe-rs run --chip STM32U5G9ZJTxQ cargo run --manifest-path demos/printerdemo_mcu/Cargo.toml --no-default-features --featuresmcu-board-support/stm32u5g9j-dk2 --targetthumbv8m.main-none-eabihf --releaseSTM32U5G9J-DK2 与 Pico2 Touch LCD 2.8 一样基于 Embassyfeature 启用embassy-stm32/stm32u5g9zj、embassy-executor的 interrupt/thread executor、gt911触摸驱动、i-slint-renderer-software/experimental同样复用 examples/mcu-board-support/embassy.rs 中的EmbassyBackend其板级实现见 examples/mcu-board-support/stm32u5g9j_dk2/stm32u5g9j_dk2.rs。ESP32-S3 系列前置条件安装 ESP Rust 工具链见 esp-rs 官方安装文档通过cargo install espflash安装espflash。烧录时espflash会提示选择 USB 端口如果端口固定不变可以把它作为命令行参数直接传入以跳过交互提示。例如设备文件为/dev/ttyUSB1时命令改为espflash --monitor /dev/ttyUSB1 path/to/binary/to/flash_and_monitor。各 ESP32-S3 板卡的编译命令都会带上--config examples/mcu-board-support/board/cargo-config.toml这是为xtensa-esp32s3-none-elf目标准备的 Cargo 配置如 examples/mcu-board-support/esp32_s3_box_3/cargo-config.toml。同时所有 ESP32-S3 feature 都依赖esp-hal/unstablePSRAM 支持所需与esp-bootloader-esp-idf。ESP32-S3-BoxESP32-S3-Box 开发板特性原文档2.4 LCD 屏320x240 分辨率ILI9486 显示控制器GT911 电容触摸控制器集成 WiFi 与蓝牙的 ESP32-S3编译并运行 demoCARGO_PROFILE_RELEASE_OPT_LEVELs cargo esp run --manifest-path demos/printerdemo_mcu/Cargo.toml --target xtensa-esp32s3-none-elf --no-default-features --featuresmcu-board-support/esp32-s3-box-3 --release --config examples/mcu-board-support/esp32_s3_box_3/cargo-config.toml从 examples/mcu-board-support/esp32_s3_box_3/esp32_s3_box_3.rs 可以看到这块板的初始化细节CPU 时钟 240 MHz、PSRAM 以 OctalSpi 模式注册为堆GT911 触摸初始化前有一段完整的I²C 地址选择时序INT/复位引脚配合把 GT911 地址锁定在 0x14失败后回退备份地址 0x5D显示 SPI 40 MHz、mipidsi以 ILI9342C 模型初始化并旋转 180°。ESP32-S3-LCD-EV-BoardESP32-S3-LCD-EV-Board 开发板特性原文档4.3 LCD 屏480x480 分辨率RGB 接口显示FT5x06 电容触摸控制器集成 WiFi 与蓝牙的 ESP32-S3编译并运行 demoCARGO_PROFILE_RELEASE_OPT_LEVELs cargo esp run --manifest-path demos/printerdemo_mcu/Cargo.toml --target xtensa-esp32s3-none-elf --no-default-features --featuresmcu-board-support/esp32-s3-lcd-ev-board --release --config examples/mcu-board-support/esp32_s3_lcd_ev_board/cargo-config.tomlWaveshare ESP32-S3 Touch AMOLED 1.8Waveshare ESP32-S3 Touch AMOLED 1.8 开发板特性原文档1.8 AMOLED 屏368x448 分辨率SH8601 显示控制器FT3168 电容触摸控制器触摸支持 TODOESP32-S316MB flash 8MB PSRAM编译并运行 demoCARGO_PROFILE_RELEASE_OPT_LEVELs cargo esp run --manifest-path demos/printerdemo_mcu/Cargo.toml --target xtensa-esp32s3-none-elf --no-default-features --featuresmcu-board-support/waveshare-esp32-s3-touch-amoled-1-8 --release --config examples/mcu-board-support/waveshare_esp32_s3_touch_amoled_1_8/cargo-config.tomlM5Stack CoreS3M5Stack CoreS3 开发板特性原文档2.0 电容触摸 IPS 面板320x240 分辨率ILI9342C 显示控制器FT6336 电容触摸控制器当前禁用仅显示模式ESP32-S316MB flash 8MB PSRAMAXP2101 电源管理单元对正常运转至关重要内置摄像头、IMU、磁力计与 RTCM5Stack CoreS3 需要通过 AXP2101 PMU 做正确的电源管理初始化这一过程由板级支持自动完成。注意触摸支持因缺少合适的 FT6336U 驱动而暂时禁用当前板卡运行在仅显示模式。编译并运行 demoCARGO_PROFILE_RELEASE_OPT_LEVELs cargo esp run --manifest-path demos/printerdemo_mcu/Cargo.toml --target xtensa-esp32s3-none-elf --no-default-features --featuresmcu-board-support/m5stack-cores3 --release --config examples/mcu-board-support/m5stack_cores3/cargo-config.toml实现见 examples/mcu-board-support/m5stack_cores3/m5stack_cores3.rs其中包含一个基于 AW9523 I/O 扩展器的触摸复位驱动TouchResetDriverAW9523通过 I²C 寄存器操作0x02 端口 0 配置、0x04 端口 0 输出等控制 FT6336U兼容 FT3x68 驱动I²C 地址 0x38的复位引脚。ESoPe SLD_C_W_S3ESoPe SLD_C_W_S3 PCB 搭载 ESP32-S3用于配合 Schukat 的 Smartwin 显示屏CARGO_PROFILE_RELEASE_OPT_LEVELs cargo esp run --manifest-path demos/printerdemo_mcu/Cargo.toml --target xtensa-esp32s3-none-elf --no-default-features --featuresmcu-board-support/esope-sld-c-w-s3 --release --config examples/mcu-board-support/esope_sld_c_w_s3/cargo-config.toml板卡 feature 一览下表汇总各板卡对应的 feature、构建目标与关键技术依据 examples/mcu-board-support/Cargo.toml 与各板卡实现整理板卡feature目标三元组显示/触摸方案Raspberry Pi Picopico-st7789thumbv6m-none-eabiST7789 (SPI) XPT2046 电阻触摸Raspberry Pi Pico2pico2-st7789thumbv8m.main-none-eabihfST7789 (SPI)Waveshare Pico2 Touch LCD 2.8pico2-touch-lcd-2-8thumbv8m.main-none-eabihfST7789 (SPI) CST328 (I²C)Embassy 异步STM32H735G-DKstm32h735gthumbv7em-none-eabihfembedded-display-controller ft5336STM32U5G9J-DK2stm32u5g9j-dk2thumbv8m.main-none-eabihfEmbassy gt911ESP32-S3-Boxesp32-s3-box-3xtensa-esp32s3-none-elfILI9342C 系 GT911 (I²C)ESP32-S3-LCD-EV-Boardesp32-s3-lcd-ev-boardxtensa-esp32s3-none-elfRGB 接口 FT5x06Waveshare AMOLED 1.8waveshare-esp32-s3-touch-amoled-1-8xtensa-esp32s3-none-elfSH8601 (AMOLED)M5Stack CoreS3m5stack-cores3xtensa-esp32s3-none-elfILI9342C FT6336U触摸暂禁用ESoPe SLD_C_W_S3esope-sld-c-w-s3xtensa-esp32s3-none-elf配合 Smartwin 显示屏底层原理导读Platform、软件渲染与事件循环mcu-board-support的每个板卡实现本质上是 api/rs/slint/mcu.md 所描述的裸机移植三要素的具体落地slint::platform::Platformtrait实现create_window_adapter()返回MinimalSoftwareWindow即WindowAdapter的便捷实现和duration_since_start()为动画提供时间源Pico 用timer.get_counter()、ESP32 用Instant::now()、Embassy 后端用embassy_time::Instant。可选的run_event_loop()与debug_log()在板卡实现中都有覆盖。事件循环既可以在Platform::run_event_loop里实现pico_st7789、esp32_s3_box_3 的超循环均在各自后端内也可以在主函数里写超循环——核心是update_timers_and_animations()→ 触摸轮询并dispatch_event→draw_if_needed→ 无活动动画时进入低功耗等待wfe()/ 定时器中断 / 触摸中断唤醒。软件渲染所有板卡都使用MinimalSoftwareWindowSoftwareRenderer::render_by_line()逐行渲染RAM 只需存一行像素通常配合 DMA 异步发送并配合RepaintBufferType::ReusedBuffer——因为屏幕内容实际保存在显示控制器内部Slint 只需重绘变化部分。LineBufferProvidertrait 的process_line回调由各板卡实现pico_st7789 用 PIODMA、pico2_touch_lcd_2_8 用双行缓冲 DMA、ESP32 板卡用display.set_pixels同步发送。理解这一层之后即使目标板不在上表内也可以参照 api/rs/slint/mcu.md 中的Platform最小实现模板与render_by_line示例为自己的 HAL 显示驱动编写新的板级后端接入 Slint 的软件渲染管线。【免费下载链接】slintSlint is an open-source declarative GUI toolkit to build native user interfaces for Rust, C, JavaScript, or Python apps.项目地址: https://gitcode.com/GitHub_Trending/sl/slint创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门