lcd-async
This crate is an async
-first driver for TFT displays that implement the MIPI Display Command Set.
This project is a fork of the excellent mipidsi crate, but with a fundamentally different, async
-native architecture. It is heavily inspired by the designs of st7735-embassy and embedded-graphics-framebuf.
The key architectural changes are:
- Fully Asynchronous: The entire communication interface (
interface::Interface
) has been redesigned withasync
traits, making it directly compatible withasync
runtimes like embassy. - Framebuffer-Based Drawing: Instead of drawing primitives directly to the display, this crate uses an "off-screen rendering" workflow. You draw a complete frame into an in-memory buffer (
RawFrameBuf
) and then send the entire buffer to the display in one efficient, asynchronous operation.
Performance and Architecture Benefits
The design of lcd-async
offers significant advantages over traditional direct-drawing drivers:
- Improved Performance: The
RawFrameBuf
stores pixel data directly in the display's native byte format. Color conversion fromembedded-graphics
types (e.g.,Rgb565
) to raw bytes only happens for the pixels that are actually drawn. In contrast, drivers that draw directly to the display often need to convert every pixel of a shape or fill area, even those that are ultimately overwritten. - Decoupled Drawing and Sending: Drawing operations are entirely synchronous and CPU-bound, while sending the framebuffer to the display is an asynchronous, I/O-bound operation. This clean separation allows for advanced patterns like double buffering: you can begin rendering the next frame into a second buffer while the hardware is still busy sending the previous frame via DMA.
- Async-Native Integration: By being
async
from the ground up, the driver integrates seamlessly into modern embeddedasync
ecosystems without blocking the executor.
Workflow: Draw, then Show
Drawing is performed in a two-step process:
- Draw: You create a buffer (e.g., a static array) and wrap it in a
RawFrameBuf
. This framebuffer implements theembedded-graphics
DrawTarget
trait. All your drawing operations—clearing, drawing text, shapes, and images—are performed on this in-memory framebuffer. - Show: Once your scene is fully rendered in the buffer, you pass a slice of the buffer to the
display.show_raw_data()
method. Thisasync
method handles sending the complete, raw pixel data to the display controller.
This workflow is demonstrated in the example below.
Example
This example demonstrates the typical usage pattern with a static buffer and an async
runtime like embassy
.
use Spawner;
use Delay;
use StaticCell;
use *;
use Rgb565;
use ;
// This crate's framebuffer and async display interface
use *;
use RawFrameBuf;
// In a real application, these would come from your HAL and BSP
use ;
const WIDTH: usize = 240;
const HEIGHT: usize = 240;
// Rgb565 uses 2 bytes per pixel
const FRAME_BUFFER_SIZE: usize = WIDTH * HEIGHT * 2;
// Use StaticCell to create a static, zero-initialized buffer.
static FRAME_BUFFER: = new;
async
Supported Models
This fork inherits the excellent model support from mipidsi
. The following models are supported:
- GC9107
- GC9A01
- ILI9341
- ILI9342C
- ILI9486
- ILI9488
- RM67162
- ST7735
- ST7789
- ST7796
Relationship to mipidsi
This is a friendly fork of mipidsi
, created to explore a fully async
and framebuffer-centric design. All credit for the original models, command sequences, and architecture goes to the mipidsi
authors and contributors.
License
Licensed under the MIT license (LICENSE or http://opensource.org/licenses/MIT), same as the original mipidsi
crate.