#lvgl #embedded-graphics #graphics

no-std bin+lib rlvgl

A modular, idiomatic Rust reimplementation of the LVGL graphics library for embedded and simulator use

10 releases

Uses new Rust 2024

0.2.5 Jul 14, 2026
0.2.4 Jun 18, 2026
0.1.9 Apr 11, 2026
0.1.7 Aug 27, 2025
0.1.3 Jul 31, 2025

#198 in Embedded development

MIT license

7MB
107K SLoC

rlvgl

rlvgl is a modular, idiomatic Rust reimplementation of LVGL (Light and Versatile Graphics Library).

rlvgl preserves the widget-based UI paradigm of LVGL while eliminating unsafe C-style memory management and global state. This library is structured to support no_std environments, embedded targets (e.g., STM32H7), and simulator backends for rapid prototyping.

The C version of LVGL is included as a git submodule for reference and test vector extraction, but not linked or compiled into this library.

Goals

Package: rlvgl

  • Preserve LVGL architecture and layout system
  • Replace C memory handling with idiomatic Rust ownership
  • Support embedded display flush/input via embedded-hal
  • Enable widget hierarchy, styles, and events using Rust traits
  • Use existing Rust crates where possible (e.g., embedded-graphics, heapless, tinybmp)

Features

  • no_std + allocator support with simulator-friendly std features
  • Modular workspace crates for core widgets, platform backends, UI helpers, API bindings, and i18n
  • rlvgl-creator support for asset preparation, vendor database browsing, and STM32 BSP generation from CubeMX .ioc files
  • Application Schema (rlvgl-app/v0) — declarative app.yaml manifest plus rlvgl-creator app from-yaml orchestrator emit a buildable Cargo crate from one source of truth (BSP, assets, state machine, i18n, theme, layouts, per-prong main glue). See docs/app-schema/.
  • Vendor chip database crates and generated STM BSP crates for board-aware tooling
  • Flagship STM32H747I-DISCO demo covering DSI display, touch, SDRAM, SD/MMC, audio, and DMA2D-assisted rendering
  • Motion, compositor, dirty-region, and accelerated blitting primitives for richer embedded UIs
  • Pluggable display and input backends for both embedded targets and host simulation
  • Optional Lottie support for dynamic playback and offline asset conversion workflows

Project Structure

  • core – Widget base trait, layout, event dispatch
  • widgets – Rust-native reimplementations of LVGL widgets
  • platform – Display/input traits and HAL adapters
  • ui – Higher-level UI components
  • examples/apps/demo – Packaged demo application crate
  • api – Shared ABI types for bindings and coprocessor integrations
  • i18n – Compile-time translations with runtime-selectable locale blobs
  • chipdb – Vendor chip databases used by creator and BSP generation
  • chips/stm/bsps – Generated STM32 BSP modules
  • rlvgl-creator – Asset and BSP workflows for command-line and UI tooling
  • examples – Sample applications and board demos
  • docs – Project documentation and task lists
  • docs/disco-tutorial – Progressive, chapter-by-chapter guide to building the STM32H747I-DISCO demo from scratch
  • docs/disco-platform-guide – Volume II: bare-metal STM32H747I-DISCO platform bring-up, SVD/PAC limits, AXI holdoff, and the star crawl in full detail
  • docs/disco-test-and-debug – Volume III: how to test and debug across the host simulator, UEFI/QEMU, and hardware, including playit automation and VS Code + probe-rs + GDB
  • docs/disco-freertos-guide – Volume IV: FreeRTOS preemptive tasks, interrupt-driven I2C4 touch, single-buffer rendering, joystick navigation
  • docs/disco-zephyr-guide – Volume V: Zephyr C+Rust hybrid, video mode vs adapted command mode, DMA2D pipeline, CSleep/LPENR fix
  • docs/sctd-tutorial – State Chart Tutorial Demo guide: SCXML machines, Qt media-player graphics, and reactive bindings
  • docs/ratatui-tutorial – Ratatui ↔ rlvgl integration from retained cells through the STM32H747I-DISCO bare-metal display path
  • lvgl – upstream C library (vendored as a git submodule under lvgl/; not mirrored on the site)

Building Binary Targets

The workspace ships several user-facing binaries. Their package names, required targets, and applicable feature flags differ enough that it is best to treat them individually instead of relying on cargo build --workspace. Common binaries have top-level make targets — run make help to see them all, or make build-all-bins to build the main binary set in one command.

Host tools and simulators

Binary Package Make target Cargo command
rlvgl-creator rlvgl make build-creator cargo build -p rlvgl --bin rlvgl-creator --features creator
rlvgl-sim rlvgl-example-sim make build-sim cargo build -p rlvgl-example-sim --bin rlvgl-sim --features png,jpeg,gif,qrcode,fontdue
rlvgl-disco-sim rlvgl-example-disco-sim make build-disco-sim cargo build -p rlvgl-example-disco-sim --bin rlvgl-disco-sim
rlvgl-sctd-sim rlvgl-example-disco-sim n/a cargo build -p rlvgl-example-disco-sim --bin rlvgl-sctd-sim
rlvgl-uefi-disco rlvgl-example-uefi-disco make build-uefi-disco cargo build --manifest-path examples/uefi-disco/Cargo.toml --target aarch64-unknown-uefi --bin rlvgl-uefi-disco
rlvgl-uefi-sctd rlvgl-example-uefi-disco n/a cargo build -p rlvgl-example-uefi-disco --bin rlvgl-uefi-sctd --target aarch64-unknown-uefi

Notes: rlvgl-creator is gated behind the creator feature; add creator_ui for the desktop UI. rlvgl-sim accepts --no-default-features for a lean build. rlvgl-uefi-disco is intentionally excluded from the workspace.

STM32H747I-DISCO firmware

The firmware package is rlvgl-example-disco and it produces three binaries from the same crate:

Binary Required target Required feature Make target Cargo command
rlvgl-stm32h747i-disco thumbv7em-none-eabihf cm7 make build-disco RUSTFLAGS="-C target-cpu=cortex-m7" cargo build --target thumbv7em-none-eabihf -p rlvgl-example-disco --bin rlvgl-stm32h747i-disco --features cm7,splash,desktop,dma2d,cpu_stats,qspi_flash,sd_storage,audio
rlvgl-stm32h747i-sctd thumbv7em-none-eabihf cm7,sctd n/a RUSTFLAGS="-C target-cpu=cortex-m7" cargo build --target thumbv7em-none-eabihf -p rlvgl-example-disco --bin rlvgl-stm32h747i-sctd --features cm7,sctd,dma2d
rlvgl-stm32h747i-disco-cm4 thumbv7em-none-eabihf cm4 make build-disco-cm4 RUSTFLAGS="-C target-cpu=cortex-m7" cargo build --target thumbv7em-none-eabihf -p rlvgl-example-disco --bin rlvgl-stm32h747i-disco-cm4 --features cm4

make build-disco{,-release} also runs rust-objcopy to emit .hex and .bin artifacts beside the ELF.

Playit test runners

Every binary that supports the playit automation protocol has a matching make target that builds it (where applicable) and runs the playit test suite against it:

Target Make target Description
Disco-demo controller (no_std) make test-disco-demo cargo test -p rlvgl-app-disco-demo — 26 unit tests
Disco simulator (host) make test-disco-sim Builds rlvgl-disco-sim and runs the Rust + Node.js suites over a TCP playit socket
UEFI disco (QEMU) make test-uefi-disco Builds rlvgl-uefi-disco, boots it headless under QEMU, and runs the Node.js suite over the pl011 UART
STM32H747I-DISCO hardware make test-stm32h747i-disco Bridges /dev/cu.usbmodem* (ST-Link VCP) to TCP and runs the Node.js suite against live firmware
All of the above make test-playit-all Runs every suite in sequence

The hardware runner depends on flashing make build-disco first; the UEFI runner depends on qemu-system-aarch64 plus EDK2 firmware (brew install qemu on macOS provides both). See playit/README.md for the full wire protocol.

Only the STM32H747I-DISCO package understands the following board-specific feature flags: splash, desktop, dma2d, cpu_stats, audio, qspi_flash, sd_storage, c_hal, c_hal_cm4, pac_sdram_init, sdram_ramtest, hal_sdram, backlight_pwm, semihosting, and bsp_log. They are all opt-in; default = [].

Where to find feature details

Every crate in the workspace now has an OPTIONS.md file next to its Cargo.toml. Start with the umbrella crate's OPTIONS.md, then use the crate-local file for the package you are building:

What's New in 0.2.5

  • rlvgl-creator qt emit --target rlvgl --scxml-context now emits reactive bindings from Qt/QML screens to iState-generated machines.
  • The SCTD demo brings SCXML Tutorial state machines and Bolero media-player graphics into a shared no_std app with Setup, DP, and Media Player slots.
  • The SCTD payload mounts on host simulator, STM32H747I-DISCO bare-metal, UEFI, and the FireBeetle-2 ESP32-P4 ESP-IDF hybrid.
  • ratatui-rlvgl adds a no_std + alloc Ratatui backend and an rlvgl-hosted RatatuiView; the Dining Philosophers hero demonstrates both composition directions on the host and through the Rust-only STM32H747I-DISCO path.
  • RGB565 RLE assets now support transparent-key conversion for Qt-derived icon artwork.

Vendor chip databases

Vendor-specific board definitions live in the chipdb/ crates. The tools/gen_pins.py helper aggregates raw vendor inputs into JSON blobs, while tools/build_vendor.sh orchestrates generation and stamps license files. When building a vendor crate, set RLVGL_CHIP_SRC to the directory containing these JSON files so the build script can embed them via include_bytes!.

STM32CubeMX BSP generation 🆕

rlvgl-creator 🆕 converts STM32 CubeMX .ioc projects into board support stubs. Generated modules ship in rlvgl-bsps-stm 🆕. The older board overlay support remains but is deprecated.

BSP Generator (rlvgl-creator 🆕)

rlvgl-creator 🆕 offers a two-stage pipeline for board support packages:

  1. Import vendor project files (e.g., STM32CubeMX .ioc, NXP .mex, RP2040 YAML). Each adapter mines the vendor data and emits a small, vendor-neutral YAML IR describing clocks, pins, DMA and peripherals.
  2. Generate Rust initialization code by rendering MiniJinja templates against the IR. Users may choose from built-in template packs or provide their own.

The STM32CubeMX adapter also parses PLL multipliers and peripheral kernel clock selections so that clock setup can be generated alongside pin configuration.

No per-chip tables are maintained. Class-level rules are reused across instances and vendors. Alternate functions are derived from embedded vendor databases generated from the official XML sources; no external JSON is required at generation time. Reserved SWD pins (PA13, PA14) are rejected unless explicitly allowed.

Typical flow:

rlvgl-creator platform import --vendor st --input board.ioc --out board.yaml
rlvgl-creator platform gen --spec board.yaml --templates templates/stm32h7 \
  --out src/generated.rs

Alternate-function numbers are computed from the embedded database at runtime by rlvgl-creator, so there is no need to generate or pass a JSON file.

To package vendor chip databases for testing or publishing, run:

tools/build_vendor.sh
RLVGL_CHIP_SRC=chipdb/rlvgl-chips-stm/generated cargo build -p rlvgl-chips-stm

For a full asset workflow overview see the rlvgl-creator 🆕 README. Command details live in docs/creator/CLI.md.

IR schema

The import step emits a concise YAML specification describing the board:

mcu: STM32H747XIHx
package: LQFP176
power: { supply: smps, vos: scale1 }
clocks:
  sources: { hse_hz: 25000000 }
  pll:
    pll1: { m: 5, n: 400, p: 2, q: 4, r: 2 }
  kernels: { usart1: pclk2 }
pinctrl:
  - group: usart1-default
    signals:
      - { pin: PA9,  func: USART1_TX, af: 7, pull: none, speed: veryhigh }
      - { pin: PA10, func: USART1_RX, af: 7, pull: up,   speed: veryhigh }
peripherals:
  usart1:
    class: serial
    params: { baud: 115200, parity: none, stop_bits: 1 }
    pinctrl: [ usart1-default ]
reserved_pins: [ PA13, PA14 ]

Field summary:

  • mcu, package – identifiers from the vendor project.
  • power – supply configuration; values map directly to HAL calls.
  • clocks – input frequencies (sources), PLL multipliers (pll) and per‑peripheral kernel selections (kernels).
  • pinctrl – groups of pins with their functions, alternate functions, pulls and speeds.
  • peripherals – map of peripheral instances keyed by name (usart1), each with a class (e.g. serial) and optional params.
  • dma, interrupts – optional arrays describing DMA requests and IRQ priorities.
  • reserved_pins – pins that must not be reconfigured (e.g. SWD).

Template helpers

MiniJinja templates can use the following filters:

  • pin_var – convert a pin like PA9 into the variable name pa9.
  • periph_num – extract trailing digits from a peripheral name (usart1212).
  • af_alt – render an alternate-function number for into_alternate::<AF>() (7<7>).

Users may supply custom templates by pointing --templates at any directory; the filters above are always available.

See docs/creator/BSP-STATUS.md for remaining work.

Status

As-built. See docs for component-by-component progress and outstanding tasks.

v0.2.5 extends the embedded UI product stack with reactive Qt/QML emission, SCXML Tutorial Demo payloads, and the release documentation needed to build the same SCTD app across simulator, STM32H747I-DISCO, UEFI, and ESP32-P4 hosts.

Quick Example

use rlvgl_core::widget::Rect;
use rlvgl_widgets::label::Label;

fn main() {
    let mut label = Label::new(
        "hello",
        Rect {
            x: 0,
            y: 0,
            width: 100,
            height: 20,
        },
    );
    label.style.bg_color = rlvgl_core::widget::Color(0, 0, 255, 255);
    // Rendering would use a DisplayDriver implementation.
}

Testing

Run host-based tests with the default toolchain:

cargo test --workspace

Cross-target tests (e.g., thumbv7em-none-eabihf) require a linker. Cargo defaults to arm-none-eabi-gcc, but you can avoid installing GCC by adding the rust-lld component and configuring:

rustup component add rust-lld
[target.thumbv7em-none-eabihf]
linker = "rust-lld"

See docs/CROSS-TESTING.md for troubleshooting tips.

Coverage

LLVM coverage instrumentation is configured via .cargo/config.toml and the coverage target in the Makefile. Run make coverage to execute the tests with instrumentation and generate an HTML report under ./coverage/.

rlvgl crate

Run the following Cargo command in your project directory:

cargo add rlvgl

Or add the following line to your Cargo.toml:

rlvgl = "0.2.5"

Community

Dockerhub

The build image used by the Github worflow for this repo is publiclly available on Dockerhub.

docker pull iraa/rlvgl:latest

Consult the Dockerfile for details on the build environment.

Other useful helper scripts may be found in /scripts.

License

rlvgl is licensed under the MIT license. See LICENSE for more details. Third-party license notices are summarized in NOTICES.md.

More Information

For more information, visit softoboros.com.

Softoboros

Dependencies

~3–58MB
~872K SLoC