st7789v2
A no_std Rust driver for the Sitronix ST7789V2 TFT-LCD display controller
(240x320, 262K color).
The ST7789V2 is a widely used single-chip controller for small TFT panels, commonly driven over SPI. It is found in boards such as the Waveshare ESP32-C6 1.69" LCD (240x240, SPI) and many other hobbyist and commercial display modules.
Features
- Generic over communication interface — implement
ControllerInterfacefor SPI, parallel, or any other bus. - Generic over reset pin — GPIO, I2C expander, or any other mechanism via
ResetInterface. - Three buffering modes selected at compile-time via a generic parameter
(requires the
embedded-graphicsfeature):- Unbuffered DrawTarget — zero RAM, each draw is a hardware transaction.
- Single-buffered — internal framebuffer with
DrawTargetsupport and automatic dirty band tracking (only changed rows are flushed). - Double-buffered — two framebuffers for overlapping render and flush on hardware with separate CPU/DMA memory buses.
- Builder pattern with
with_init_commands()for vendor-specific panel init sequences. - Static or heap-allocated framebuffer.
- RGB565, RGB888, and Gray8 color formats.
- Full ST7789V2 command set from the datasheet (V1.0, Sitronix, 2016/11), including Command Table 2 (manufacturer registers).
Cargo features
| Feature | Default | Description |
|---|---|---|
embedded-graphics |
yes | DrawTarget support, buffering modes, color trait |
Without the feature the crate provides the core driver (commands, set_window,
send_pixels, sleep, MADCTL, brightness) with zero dependency on
embedded-graphics-core.
# Default — includes embedded-graphics integration
[]
= "0.1"
# Without embedded-graphics (raw driver only)
[]
= { = "0.1", = false }
Usage
Unbuffered (no DrawTarget)
The caller owns the pixel data and streams it directly.
use ;
const SIZE: DisplaySize = new;
let mut display = builder
.with_init_commands
.build?;
display.set_window?;
display.send_pixels?;
Single-buffered (recommended)
Internal framebuffer with embedded-graphics DrawTarget. Draw operations
write to RAM; flush() sends only the changed rows to the display.
use ;
use Rgb565;
use *;
use ;
const SIZE: DisplaySize = new;
const FB_SIZE: usize = framebuffer_size;
let mut display = builder
.with_init_commands
.
.build?;
new
.into_styled
.draw?;
// Flush only the dirty rows to the display
display.flush?;
// Or force a full refresh (e.g. after wake from sleep)
display.full_flush?;
Double-buffered
Two framebuffers allow overlapping render and flush on hardware with separate CPU and DMA memory buses.
use ;
use Rgb565;
const SIZE: DisplaySize = new;
const FB_SIZE: usize = framebuffer_size;
let mut display = builder
.with_init_commands
.
.build?;
loop
Direct framebuffer access
For advanced use cases, the framebuffer can be accessed directly. After writing
pixels manually, call mark_dirty() so the next flush() includes the
modified rows.
let fb = display.framebuffer_mut;
fb.fill; // Write to first row (240 pixels x 2 bytes)
display.mark_dirty; // Mark row 0 as dirty
display.flush?;
Implementing ControllerInterface for SPI
The ST7789V2 uses a standard SPI interface with a DC (data/command) pin. Here is a typical implementation pattern:
use ControllerInterface;
Dirty band tracking
The single-buffered mode automatically tracks which rows have been modified by
DrawTarget operations (draw_iter, fill_solid, fill_contiguous, clear).
When flush() is called:
- If nothing changed since the last flush, it returns immediately (no SPI traffic).
- Otherwise, only the contiguous band of modified rows is sent — a single
set_window+send_pixelscall with no allocation.
This is transparent to all callers — the DrawTarget API is unchanged. For UIs
where only a small region updates each frame (e.g. a clock or status bar), this
can reduce flush time from ~12ms (full screen) to <1ms.
Use full_flush() to bypass dirty tracking when needed (e.g. after wake from
sleep or direct framebuffer writes without mark_dirty()).
SPI protocol
The ST7789V2 uses standard 4-line SPI with a DC (data/command) pin:
- DC low = command byte
- DC high = data / pixel bytes
- Commands:
CASET(0x2A),RASET(0x2B),RAMWR(0x2C) - Pixel format set via
COLMOD(0x3A):0x55= RGB565,0x66= RGB666
Datasheet
ST7789V2 Datasheet V1.0, Sitronix Technology Corporation, 2016/11 (319 pages).
License
Licensed under either of
- Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT License (LICENSE-MIT or http://opensource.org/licenses/MIT)
at your option.