embassy-st7789v-plot 0.3.0

Moteur de tracé de graphiques cartésiens (X, Y) adaptatifs et configurables pour écrans TFT LCD **ST7789V 240×320**, construit au-dessus de [`embassy-st7789v`](https://crates.io/crates/embassy-st7789v).
Documentation

embassy-st7789v-plot

Moteur de tracé de graphiques cartésiens (X, Y) adaptatifs et configurables pour écrans TFT LCD ST7789V 240×320, construit au-dessus de embassy-st7789v.

Caractéristiques

  • #![no_std] + #![forbid(unsafe_code)] : Entièrement sûr et embarqué
  • Zéro allocation dynamique : Buffers statiques uniquement (ring buffer fixe)
  • Historique circulaire : Jusqu'à 240 points (limite physique écran 240px)
  • Axes configurables : Graduations statiques avec pas personnalisable
  • Grille configurable : Grille horizontale/verticale avec labels personnalisés
  • Détection automatique du zéro : La ligne zéro est surlignée en vert
  • Protection stricte des bordures : Clamping des primitives à l'espace interne
  • Rendu ligne Bresenham : Courbes lisses entre points de données
  • Rendu intelligent (Double Phase) : Cadre, étiquettes et titres tracés une seule fois
  • Deux modes de rendu :
    • LineChart + render() : async, direct SPI
    • LineChartBuffered + render_buf() + flush() : sync RAM, zéro clignotement

Installation

[dependencies]
embassy-st7789v          = "0.3"
embassy-st7789v-graphics = "0.2"
embassy-st7789v-plot     = "0.2"
embedded-hal             = "1.0"
embedded-hal-async       = "1.0"

Utilisation rapide

Mode direct async (LineChart)

Simple mais peut produire un clignotement si le graphique est redessiné fréquemment.

use embassy_st7789v::{Color, St7789v, NoPin};
use embassy_st7789v_plot::{Graphics, AxisConfig, PlotConfig, LineChart};

let x_axis = AxisConfig::new(0.0, 10.0, 2.0, b"Time (s)");
let y_axis = AxisConfig::new(0.0, 100.0, 20.0, b"Temperature (C)");

let config = PlotConfig {
    x: 10, y: 10, width: 220, height: 200,
    margin_left: 40, margin_right: 10,
    margin_top: 10, margin_bottom: 30,
    x_axis, y_axis,
    bg_color:   Color::BLACK,
    line_color: Color::GREEN,
    axis_color: Color::WHITE,
    grid_color: Color::GRAY,
    text_color: Color::WHITE,
    label_color: Color::CYAN,
};

let mut chart: LineChart<100> = LineChart::new(config);
chart.push(45.2);
chart.push(47.8);

let mut gfx = Graphics::new_no_rst(&mut display);
chart.render(&mut gfx).await;

Mode framebuffer sync (LineChartBuffered) — zéro clignotement

Toutes les opérations de dessin écrivent en RAM. Un seul flush() envoie tout à l'écran. Nécessite St7789vBuffered du crate embassy-st7789v (150 Ko RAM).

use embassy_st7789v::{Color, St7789v, St7789vBuffered};
use embassy_st7789v_plot::{AxisConfig, PlotConfig, LineChartBuffered};

let mut ecran = St7789vBuffered::new(St7789v::new(spi_dev, dc, rst));
ecran.driver().init().await.unwrap();

let config = PlotConfig { /* ... */ };
let mut chart: LineChartBuffered<100> = LineChartBuffered::new(config);

loop {
    let value = sensor.read().await;
    chart.push(value);

    chart.render_buf(&mut ecran);   // tout en RAM, synchrone
    ecran.flush().await.unwrap();   // envoi unique → zéro clignotement
}

Configuration des axes

// Temps 0–60 s, graduation tous les 10 s
let time_axis = AxisConfig::new(0.0, 60.0, 10.0, b"Time (s)");

// Température -10 à +50 °C, graduation tous les 10 °C
let temp_axis = AxisConfig::new(-10.0, 50.0, 10.0, b"Temp (C)");

// Tension 0–3.3 V, graduation tous les 0.5 V
let volt_axis = AxisConfig::new(0.0, 3.3, 0.5, b"U (V)");

// Nombre de graduations
assert_eq!(time_axis.tick_count(), 7); // 0, 10, 20, 30, 40, 50, 60

Schéma de positionnement

(x, y) ┌──────────────────────────────────┐ │ margin_top │ │ ┌──────────────────────────┐ │ │ │ Label Y │ │ margin │ │ 50 ┼──────────• │ │ margin left │ │ 25 │ • • │ │ right │ │ 0 └────────────────── │ │ │ │ 0 2 4 6 8 10 │ │ │ │ Label X │ │ │ └──────────────────────────┘ │ │ margin_bottom │ └──────────────────────────────────┘


Workflow de rendu (Double Phase)

Phase d'initialisation (une seule fois) :

  1. Nettoyage global de l'espace d'affichage
  2. Labels Y — valeurs des graduations (vert si zéro détecté)
  3. Labels X — valeurs des graduations
  4. Titres des axes
  5. Bordures fixes (axis_color)

Phase dynamique (à chaque rendu) :

  1. Nettoyage intérieur strict (sans toucher aux bordures)
  2. Grille Y — lignes horizontales (vert pour le zéro)
  3. Grille X — lignes verticales
  4. Courbe — lignes Bresenham reliant les points

Ring buffer (historique circulaire)

array[100], head=3, count=100 (plein) data[0] = 97e valeur data[1] = 98e valeur data[2] = 99e valeur ← head (prochaine écriture) data[3] = 1ère valeur ← oldest ...


Cas d'usage

Oscilloscope 1 canal

let config = PlotConfig {
    x: 0, y: 0, width: 240, height: 320,
    margin_left: 40, margin_right: 10,
    margin_top: 10, margin_bottom: 30,
    x_axis: AxisConfig::new(0.0, 240.0, 30.0, b"Samples"),
    y_axis: AxisConfig::new(-5.0, 5.0, 1.0, b"Voltage (V)"),
    // ...
};
let mut osc: LineChartBuffered<240> = LineChartBuffered::new(config);

Moniteur de température

let config = PlotConfig {
    x: 10, y: 10, width: 220, height: 150,
    margin_left: 45, margin_right: 15,
    margin_top: 15, margin_bottom: 30,
    x_axis: AxisConfig::new(0.0, 120.0, 20.0, b"Time (min)"),
    y_axis: AxisConfig::new(15.0, 35.0, 5.0, b"T (C)"),
    // ...
};
let mut temp: LineChartBuffered<120> = LineChartBuffered::new(config);

Graphique de pression

let config = PlotConfig {
    x: 5, y: 5, width: 230, height: 310,
    margin_left: 35, margin_right: 5,
    margin_top: 5, margin_bottom: 30,
    x_axis: AxisConfig::new(0.0, 1000.0, 100.0, b"Pa"),
    y_axis: AxisConfig::new(900.0, 1050.0, 30.0, b"P (hPa)"),
    // ...
};
let mut pres: LineChartBuffered<100> = LineChartBuffered::new(config);

API complète

LineChart<N> et LineChartBuffered<N>

Méthode LineChart LineChartBuffered
new(config)
push(value)
clear()
config()
render(&mut gfx) ✓ async
render_buf(&mut ecran) ✓ sync

AxisConfig

Méthode Description
new(start, end, step, label) Crée une config d'axe
is_valid() Vérifie cohérence
tick_count() Nombre de graduations

Graphics<'a, SPI, DC, RST>

Méthode Description
new(display) Crée contexte avec RST
new_no_rst(display) Crée contexte sans RST
pixel(x, y, color) Trace pixel (async)

Fonctions globales

Fonction Mode Description
line(gfx, x0, y0, x1, y1, color) async Bresenham direct SPI

Limitations

  • Nombre de points : Maximum 240 (largeur physique écran)
  • Précision : Axes en virgule flottante, pixels en entier
  • Pas non-adaptatif : Graduations statiques, pas de zoom automatique
  • RAM framebuffer : LineChartBuffered nécessite 150 Ko (RP2350 ✓, RP2040 ✓, STM32F103 ✗)

Licence

GPL-2.0-or-later — Copyright (C) 2026 Jorge Andre Castro


Dépendances