Display lab
Wire, initialise and feed 18 common microcontroller displays — SSD1306/SH1106 OLEDs, ST7735/ST7789/ILI9341/GC9A01 TFTs, SSD1680/UC8151 e-paper, HD44780 LCDs, MAX7219, TM1637 and HUB75 panels — with each init sequence decoded, the frame memory drawn, frame rates against the bus clock, library code for your wiring, and an image converter, font converter, LCD character designer and Adafruit GFX simulator.
Added
Works with
- Pixel and bitmap editor Images and retro graphicsdraw a sprite or icon by hand there, convert a photo for the same OLED here
- Retro bitmap font editor Retro computinghand-draw an 8×8 bitmap font there, rasterise a TTF into a GFXfont here
- Board pinouts IoT and embeddedcheck which board pins the default I²C and SPI wiring here uses, and what else they do
- Bus protocols, simulated IoT and embeddedsee the I²C or SPI waveform of the init bytes decoded here, bit by bit
- Microcontroller timing calculator IoT and embeddedSPI clock dividers and I²C pull-ups for the display bus
- ESPHome config builder IoT and embeddedthe display: YAML generated here drops into a device config built there
How to use it
Pick a display and a board, and the page shows how to wire it, what the driver sends to start it, how its frame memory is laid out, how fast you can update it over the bus you chose, and the code to drive it with the usual libraries — generated for that wiring. Four workbenches cover the jobs that come next: converting an image to the display’s pixel format, turning a TrueType font into an Adafruit GFX or u8g2 font, designing HD44780 custom characters, and trying out Adafruit GFX drawing code on a simulated panel.
How to use it
-
Displays. Choose the display, the board (ESP32 DevKit, Raspberry Pi Pico or Arduino Uno) and, where there is a choice, the bus (I²C or SPI; for HD44780 modules the PCF8574 I²C backpack, 4-bit or 8-bit parallel). The page then shows:
-
Wiring — a diagram and a pin table using the board’s hardware I²C or SPI pins, and notes on level shifting for that pair: a 5 V Uno into 3.3 V TFT logic, a 5 V HD44780 backpack’s pull-ups on a 3.3 V bus, a MAX7219’s 3.5 V input threshold.
-
Init sequence, decoded — every command byte the usual driver sends, what it does and the datasheet section or table it comes from, plus what each frame write looks like. Copy commands as a C array copies the bytes.
-
Frame memory — the layout drawn for that controller: SSD1306 pages and columns, the RGB565 bit fields and byte order (with a colour picker), e-paper RAM planes with their row padding, HD44780 DDRAM and CGRAM addresses, MAX7219 digit registers, TM1637 segment bits, and the HUB75 row-pair scan. Hover or tap a pixel to see which byte and bit it is.
-
Frame rate and bandwidth — bytes per frame, transfer time and frame rate for your bus clock (I²C at 100 kHz–1 MHz with the transaction size your library uses; SPI up to 80 MHz with DMA or CPU-loop efficiency; the area updated), the e-paper refresh times, HD44780 character times over GPIO or the backpack, and the HUB75 refresh rate, colour depth, brightness duty and DMA memory for a clock and bit depth.
-
Libraries and example code — u8g2, Adafruit GFX and its drivers, TFT_eSPI (the User_Setup.h defines and a sketch), LVGL 9, GxEPD2, MicroPython, LiquidCrystal, MD_Parola, LedControl, TM1637Display, ESP32-HUB75-MatrixPanel-DMA, Protomatter and ESPHome YAML, all with your pins.
-
-
Image converter. Drop an image (a sample loads first), pick the display, how to fit it (fill and crop, letterbox or stretch) and how the panel is mounted, and adjust brightness, contrast and gamma. Choose the output format — 1-bit rows MSB- or LSB-first (Adafruit drawBitmap or XBM for u8g2), SSD1306 pages, vertical columns, RGB565 as values or big/little-endian bytes, RGB332, 4-bit greyscale, or e-paper black/white and red planes — and a dither: Floyd–Steinberg, Atkinson, ordered (Bayer 4×4 or 8×8) or a plain threshold. The preview is a simulated panel (glowing OLED pixels, LED dots, paper). Export a C array (with or without PROGMEM), MicroPython bytes with the matching framebuf format, or a binary file. The Displays tab’s code examples then draw that array.
-
Font converter. Open a TTF, OTF, WOFF or WOFF2 file (or start with a system font), set the pixel size, the ink threshold and the character range, and download an Adafruit GFX font (
.h, aGFXfontwith its glyph table) or a BDF file for u8g2’sbdfconv. The preview renders your sample text from the generated glyphs. -
HD44780 characters. Draw the eight 5×8 CGRAM characters (or start from icons or bar-graph segments), type the lines with
{0}…{7}where the custom characters go, and see it on a 16×2 or 20×4 module. The code tab gives the Arduino (LiquidCrystal or LiquidCrystal_I2C), MicroPython, ESPHomeuser_charactersand raw CGRAM bytes. -
Simulator. Type Adafruit GFX drawing code in JavaScript —
display.fillCircle(…),setCursor,print— and see it on the chosen display; defineloop()to animate it. Arduino sketch translates it into a complete sketch for the display and board, with the library, constructor and pins filled in.
Settings are saved in your browser, and the Share link button carries the display, board and bus.
Method and assumptions
Init sequences are the ones the common drivers send (Adafruit, u8g2, the GxEPD2 and vendor examples), annotated from the controllers' datasheets: SSD1306 rev 1.1 §10, the SH1106, SSD1351 and SSD1680 command tables, the ST7735S, ST7789V, ILI9341 and GC9A01A MIPI-style command lists, UC8151D, the HD44780U instruction table (Table 6) and initialisation flow charts (Figures 23 and 24), MAX7219 register tables and the TM1637 command description. The GC9A01’s long vendor table is mostly undocumented panel tuning, so it is summarised rather than listed.
Pixel formats. RGB565 uses Adafruit’s color565() truncation for the simulator’s colours and
rounds to the nearest level when converting images; expanding back replicates the top bits
(r5 << 3 | r5 >> 2). Error diffusion works in floating point on luma (Rec. 601) for 1-bit and
greyscale, and per channel for colour targets, with the working value clamped so the error can’t
run away where the palette can’t reach. Ordered dithering uses the standard recursive Bayer
matrices. Everything is deterministic: the same image and settings always give the same bytes.
Frame rates count clocks: every I²C byte is 9 clocks (8 data + ACK), each transaction adds the address byte, a control byte and about 2 bit times for START and STOP; SPI is 8 clocks per byte divided by an efficiency for the gaps between bytes. These are upper bounds — the library’s own work (clearing and drawing into the buffer) comes on top. HUB75 refresh uses binary code modulation: each bit plane is shown for 2^b times the least significant bit’s time while the next plane shifts in, and a plane can’t be shorter than its shift time, so
refresh = 1 / (scan × Σb max(tshift, tlsb × 2b)), with tshift = (width × chain + overhead) / fCLK.
With 64 pixels, 1/16 scan, 8 bits and a 20 MHz clock that is 20 MHz / (64 × 16 × 255) ≈ 77 Hz, which is why HUB75 libraries default to fewer bits or show the low planes less often.
Simulator. The GFX class implements Adafruit GFX’s own algorithms — Bresenham lines, the midpoint
circle loop and its fillCircleHelper, rounded rectangles, scan-line triangles, setRotation,
text wrapping and size scaling — so shapes come out pixel for pixel as on the hardware. The text
uses the public-domain X11 5×8 font in the same 6×8 cell as Adafruit’s classic font: layout and
metrics match, a few glyph shapes differ. The sketch export is a line-by-line translation (let
→ int or float, Math.sin → sin, top-level declarations as globals): check it before
compiling.
Fonts are rasterised by the browser’s own font engine through the FontFace API and thresholded,
so hinting and anti-aliasing follow your browser. GFXfont glyph bitmaps are packed as one
continuous bit stream per glyph (MSB first, padded only at the end), as Adafruit’s
fontconvert does; BDF rows are padded to whole bytes, as the format requires.
Related tools: draw sprites and OLED icons by hand in the pixel and bitmap editor, 8×8 fonts in the retro font editor, check a board’s pins in Board pinouts, see the bus waveforms in Bus protocols, work out SPI dividers and I²C pull-ups in the MCU timing calculator, and build a whole ESPHome device in the ESPHome config builder.
Feedback is a gift. Something to improve, a feature to add, or a bug? Tell me.
Runs entirely in your browser; nothing you type leaves this page.