Skip to content

About

No description, website, or topics provided.

Resources

Stars

4 stars

Watchers

2 watching

Forks

Repository files navigation

ST77916_QSPI Compile Sketches

This is an Arduino library for 360×360 round ST77916 QSPI panels on ESP32-S3. It is designed specifically to work with Adafruit_GFX, so any sketch written against a normal Adafruit display driver already knows most of this one's API.

The panel talks QSPI (4 data lines) rather than the usual 8/16-bit parallel or single-line SPI, and the driver is built around a framebuffer in PSRAM with dirty-rectangle tracking and queued DMA, so it stays fast enough for GIFs, MJPEG video and generative/sketch-style drawing rather than just static UI.

Please note this is a community driver, not an official Adafruit or Espressif product. It targets one panel family (ST77916, 360×360, QSPI) on one MCU family (ESP32-S3, for the PSRAM + QSPI peripheral).

Features

  • Drop-in Adafruit_GFX subclass — drawPixel, fillRect, text, existing sketches, all work unmodified.
  • PSRAM framebuffer with dirty-rectangle tracking, so display() only sends the pixels that changed.
  • Ping-pong DMA push with an optional second-core task (present()) for tear-free double buffering.
  • Blitting: RGB565, 8-bit palettised, colour-keyed, integer-scaled, and a direct-to-panel path that bypasses the framebuffer for streaming video.
  • Alpha blending and anti-aliased primitives (Wu lines, round-capped strokes, circles, arcs, scanline polygons).
  • P5.h, an optional p5.js-shaped drawing layer (transform stack, stroke/fill, Perlin noise(), map/lerp/dist) for sketches that read like p5.js.
  • ST77916_Sprite, a standalone offscreen RGB565 canvas for compositing HUDs and sprite frames.
  • 12 example sketches, from a benchmark and a bring-up-style geometry demo through GIF/MJPEG playback to generative pointillism and 3D-illusion typography.
  • An off-target test suite (test/hostcheck/run.sh) that builds and runs the driver's rotation, clipping, blitting and buffer-management logic on your dev machine, no hardware required.

Hardware

Any ESP32-S3 board with a free QSPI bus (four data lines) and three spare GPIOs for reset/chip-select/backlight will work — the wiring is not fixed to one carrier board. Each example sketch has its pin numbers at the top as named #defines:

// ---- wiring ------------------------------------------------------------
// Edit these to match your board. Any ESP32-S3 with a free QSPI bus (4 data
// lines) plus RST/CS/BL pins works; only the numbers change.
#define TFT_SCLK 17
#define TFT_IO0  18
#define TFT_IO1  21
#define TFT_IO2  14
#define TFT_IO3  13
#define TFT_RST  4
#define TFT_CS   7
#define TFT_BL   5

Edit those eight numbers to match your board's silkscreen/schematic and everything else in the sketch stays the same.

Installing

Arduino Library Manager (recommended, once published)

Sketch → Include Library → Manage Libraries..., search for ST77916_QSPI, click Install. This also installs the required Adafruit GFX Library dependency automatically.

Manual install

  1. Download this repository as a ZIP (Code → Download ZIP on GitHub).

  2. In the Arduino IDE: Sketch → Include Library → Add .ZIP Library..., and select the downloaded file.

    Or unzip it directly into your sketchbook's libraries folder (~/Documents/Arduino/libraries/ on macOS/Linux, Documents\Arduino\libraries\ on Windows) — rename the extracted folder to ST77916_QSPI if GitHub added a branch suffix.

  3. Restart the Arduino IDE.

Dependencies

  • Adafruit GFX Library — install via Library Manager, this library builds on top of it.
  • Board support: ESP32 by Espressif Systems, installed via Boards Manager, with an "ESP32S3 Dev Module" (or your board's specific entry) selected, PSRAM enabled.
  • Optional, only for the matching examples: AnimatedGIF (GifPlayer), JPEGDEC (MjpegPlayer) — both by bitbank2, both in Library Manager.

Quick start

#include <ST77916_QSPI.h>
#include <P5.h>

#define TFT_SCLK 17
#define TFT_IO0  18
#define TFT_IO1  21
#define TFT_IO2  14
#define TFT_IO3  13
#define TFT_RST  4
#define TFT_CS   7
#define TFT_BL   5

ST77916_QSPI_GFX tft(TFT_SCLK, TFT_IO0, TFT_IO1, TFT_IO2, TFT_IO3, TFT_RST, TFT_CS, TFT_BL);
P5 p5(tft);

void setup() {
  ST77916_QSPI_GFX::Config cfg;
  cfg.doubleBuffer = true;
  cfg.pushTask     = true;
  tft.begin(cfg);
}

void loop() {
  p5.background(ST77916_WHITE);
  p5.stroke(ST77916_BLACK);
  p5.strokeWeight(2);
  p5.noFill();
  p5.push();
  p5.translate(180, 180);
  p5.rotate(millis() * 0.0005f);
  for (int i = 3; i < 9; i++) p5.polygon(0, 0, 20.0f * i, i);
  p5.pop();
  tft.present();
}

Check begin()'s return value in real code — see tft.lastError() if it returns false.

Examples

Open via File → Examples → ST77916_QSPI in the Arduino IDE.

Example What it shows
Benchmark Timing for every push path; run this first on new hardware to pick chunkBytes/clockHz.
Geometry p5-layer generative geometry, six movements, anti-aliased.
bw_geometry The same idea via the raw ST77916_Draw primitives, no p5 layer.
SpriteHUD Offscreen ST77916_Sprite HUD composited over an animated background with colour-key transparency.
GifPlayer Animated GIF playback from an SD card via AnimatedGIF.
MjpegPlayer Motion JPEG video playback from an SD card via JPEGDEC.
RadialGrid Port of a Generative Gestaltung p5.js sketch (distance-driven radial grid).
BhujodiMotifs Generative homage to Bhujodi extra-weft weaving patterns.
PhotoPointillism, SunsetPointillism Pointillism renders of a photo, preprocessed offline into a point-cloud header (script included under image/).
PointillismText Particle field that carves out static text as negative space.
TypographicIllusion3D Extruded 3D-illusion wordmark built from a text mask.

Presenting a frame

present() is the call to reach for; it does the right thing in every configuration. Single buffered, it is a blocking push of the dirty region. Double buffered with a push task (cfg.doubleBuffer = true; cfg.pushTask = true;), it flips buffers and transmits the frame you just drew on the other core while you draw the next one.

The manual controls are still there if you want them: display(), displayFull(), displayAsync(), waitDisplay(), swapBuffers().

Performance notes

A full frame is 360 × 360 × 2 = 259,200 bytes. At 70 MHz across four data lines that's 2.07 Mbit, so ~7.4 ms is the wire floor — nothing gets a full-panel refresh above roughly 135 fps on this bus, whatever the driver does.

Everything above that floor is CPU work: the framebuffer is kept in the panel's own byte order so a push is a straight memcpy, chunks are queued so copy and transfer overlap, and dirty-rectangle tracking means a small update (say, a 120×120 region) only pushes about a ninth of a full frame.

Run examples/Benchmark and read the numbers off your own board before tuning anything. Useful knobs, roughly in order of effect: doubleBuffer + pushTask, chunkBytes (try 32768), and clockHz.

Video and GIF playback

Both decoders can emit pixels in the panel's byte order, so playback costs little beyond the decode itself.

gif.begin(GIF_PALETTE_RGB565_BE);
// in GIFDraw:
tft.pushImage8(x, y, pDraw->iWidth, 1, pDraw->pPixels, pDraw->pPalette,
               pDraw->ucHasTransparency ? pDraw->ucTransparent : -1,
               ST77916_PIXELS_BE);
jpeg.setPixelType(RGB565_BIG_ENDIAN);
// in JPEGDraw:
tft.pushImage(pDraw->x, pDraw->y, pDraw->iWidth, pDraw->iHeight,
              pDraw->pPixels, ST77916_PIXELS_BE);

pushRectDirect() streams straight to the panel without touching the framebuffer, for when a decoder already produces full rows in display order and there is no compositing to do.

Testing

test/hostcheck/run.sh

Builds the driver against stub Arduino/ESP-IDF headers and runs it on your machine: rotation mapping in all four orientations, dirty-rectangle arithmetic, the clip window, palettised/RGB565 blits in both byte orders, edge clipping, blend saturation, and the double-buffered present path. It also renders a test card to /tmp/frame.ppm, so antialiasing regressions are visible without flashing anything. No hardware required; run it after any change to src/ST77916_QSPI.cpp.

Caveats

  • Check begin()'s return value and lastError() before assuming the panel is up.
  • If colours look swapped (red/blue reversed), set Config::bgr = true.
  • If you see tearing or garbage on the wire, lower clockHz before suspecting anything else in the driver.
  • setRotation() is supported (handled in software, not via panel MADCTL), but on a round panel it mostly just costs a per-pixel branch — leave it at the default unless you need it.

License

MIT. See LICENSE.

Contributing

Issues and pull requests are welcome at github.com/Studio-Poetics/ST77916_QSPI. Please run test/hostcheck/run.sh before opening a PR that touches src/ST77916_QSPI.cpp.

Written by Studio Poetics.

About

No description, website, or topics provided.

Resources

Stars

4 stars

Watchers

2 watching

Forks

Releases

Packages

Contributors

Languages