Skip to main content

Display Fundamentals and Interfaces

Pixels, color depth, framebuffers, orientation, and coordinate systems apply to every display technology. The connection between the display and the microcontroller determines refresh bandwidth and GPIO requirements. This page introduces both areas using interfaces commonly found in the ESP32 ecosystem.

1. Concepts Shared by All Displays

1.1 Pixels and Resolution

An image is made up of pixels. Resolution specifies the number of pixels along each axis. For example, a resolution of 240×320 means 240 pixels horizontally and 320 pixels vertically. At the lowest level, driving a display means assigning a color to each pixel.

1.2 Color Depth

Color depth is the number of bits used to represent one pixel. It directly determines the amount of pixel data:

Color depthData per pixelAvailable colorsTypical applications
1 bpp (monochrome)1 bitBlack / whiteMonochrome OLED, RLCD, black-and-white e-paper
RGB56516 bits (2 bytes)65,536 colorsMost embedded full-color displays
RGB88824 bits (3 bytes)Approximately 16.77 million colorsApplications requiring greater color fidelity

RGB565 assigns 5 bits to red, 6 bits to green, and 5 bits to blue. It balances color quality and data size and is the format most commonly used for full-color displays in ESP32 projects.

Why RGB565 uses 5, 6, and 5 bits

RGB565 fits one pixel into exactly 16 bits, or 2 bytes. Compared with 24-bit RGB888, it reduces framebuffer storage and transfer bandwidth by one third. Sending one less byte per pixel directly reduces the refresh workload on interfaces such as SPI and I80, which is why many small and medium LCD examples and graphics libraries use RGB565 by default.

Green receives 6 bits because human vision is more sensitive to changes in green luminance. The extra bit gives the green channel finer brightness gradation while keeping the complete pixel at 16 bits.


Multiply the resolution by the color depth to calculate the data in one complete frame:

Example displayResolutionColor depthData per frame
0.96-inch monochrome OLED128×641 bpp1 KB
1.28-inch round LCD240×240RGB565112.5 KB
2.4-inch LCD240×320RGB565150 KB
4.3-inch RGB display800×480RGB565750 KB

The frame size determines both how much data must be transferred for an update, which affects frame rate, and how much memory is required to buffer a frame.

1.3 Framebuffers and Display RAM (GRAM)

A display that is scanned continuously needs the current pixel data to remain in memory. This memory is called a framebuffer and can be located in either of two places:

  • On the display: Most SPI and I80 display controllers include graphics RAM (GRAM). After the microcontroller writes pixels to GRAM, the controller continuously scans the panel on its own. The microcontroller does not need to retain a complete frame and can remain idle while the image is unchanged.
  • On the microcontroller: An RGB-interface panel has no GRAM. The microcontroller must maintain a complete framebuffer and continuously output it with the required timing. If internal RAM cannot hold the framebuffer, external PSRAM is required. One 800×480 RGB565 frame occupies 750 KB, more than the internal RAM available for this purpose on most ESP32 devices, so large RGB displays generally require PSRAM. A lower-resolution RGB display may not require PSRAM if its framebuffer fits in internal RAM.
QSPI and MIPI-DSI displays

Either arrangement is possible, depending on the display controller and operating mode. Some QSPI controllers include GRAM and behave much like SPI controllers, while others require a continuous pixel stream. The ESP32-P4 MIPI-DSI peripheral uses Video Mode, with the framebuffer stored on the microcontroller side.

This is one of the most important interface distinctions: SPI displays require little memory on the microcontroller, while an RGB display's memory requirement is determined by its framebuffer size. Large, high-resolution RGB displays usually require PSRAM.

1.4 Refreshing and Tearing

Pixels do not appear on the panel immediately after they are written. The display controller scans GRAM to the panel at a fixed refresh rate, such as 60 Hz. If the microcontroller updates GRAM while a scan is in progress, the panel can show parts of both the old and new frames. This artifact is called tearing.

Some controllers with GRAM expose a TE (Tearing Effect) pin that outputs a synchronization pulse between scans. The microcontroller can wait for this signal before writing. Completely avoiding tearing also requires the write direction to match the scan direction and the write operation to keep pace with the scan. Applications that display mostly static content and update only occasionally generally do not need TE synchronization.

For more information, see Espressif's LCD Screen Tearing guide.

1.5 Full-Screen and Window Updates

A controller with GRAM supports window addressing. The host first specifies a rectangular region, and subsequent pixel data is written only to that region. An application can therefore update only the area that changed instead of retransmitting the entire frame. Graphics libraries such as LVGL use this mechanism for partial updates.

info

An e-paper “partial refresh” is a different operation involving the drive waveform for the electrophoretic particles. See E-paper.

1.6 Orientation and Coordinate Systems

The panel and display controller's row-and-column arrangement defines the native orientation. For a display with native width W and height H, the top-left corner is normally the origin (0, 0). X increases to the right and Y increases downward. A panel may be mounted in a different physical orientation, requiring the image to be rotated.

The logical coordinate system used by the graphics library changes with the orientation. For a clockwise rotation from the native orientation, coordinates map as follows:

Clockwise rotationLogical width × heightNative (x, y) mapped to rotated coordinates
W × H(x, y)
90°H × W(H - 1 - y, x)
180°W × H(W - 1 - x, H - 1 - y)
270°H × W(y, W - 1 - x)

You normally do not need to calculate these mappings yourself. Display drivers and graphics libraries provide an orientation setting. Rotation can occur in one of two places:

Rotation methodHow it worksCharacteristics
Controller-side rotation, often called hardware rotationA controller with GRAM changes pixel addressing by swapping rows and columns and mirroring axes. Some controllers use a register such as MADCTL.Uses the display controller's addressing hardware, so the microcontroller does not rearrange an entire frame or allocate a full rotation buffer. Available orientations depend on the controller.
Microcontroller-side software rotationThe CPU, a software canvas, or a GUI framework transforms the framebuffer before sending the pixels.Does not depend on the controller's rotation features, but increases memory use, data movement, and processing time.

For rotations of 0°, 90°, 180°, and 270°, use controller-side rotation when the controller supports the required orientation. Drawing can then continue in the rotated logical coordinate system. Use software rotation when the controller cannot swap rows and columns or when the application requires another angle or image transformation.

Functions such as Arduino_GFX setRotation() and the U8G2_R0 through U8G2_R3 constructor arguments set the display orientation. The library adjusts its logical dimensions and coordinates. Whether the controller remaps the pixels or the microcontroller transforms them depends on the specific driver and buffering mode.

Follow the library and driver definitions

Rotation numbering and the initial orientation vary among graphics libraries. Some display controllers can mirror axes but cannot swap rows and columns for 90° and 270° rotation. Check the graphics-library and driver documentation before selecting a value. After setting the orientation, read the library's logical width and height and verify that graphics in all four corners are complete. A custom driver must also account for window-address offsets in each orientation.

Touch controllers generally continue reporting coordinates in the touch panel's native orientation. After rotating the display, apply the same axis swap and mirroring to the touch coordinates or the reported point will not align with the image. See Aligning Touch and Display Coordinates.

2. Display Interface Comparison

The following table compares common connections between a display and a microcontroller. The main differences are the number of data lines, which affects bandwidth; the total number of GPIOs, which affects pin availability; and whether the display contains GRAM, which affects memory requirements. Approximate GPIO counts include the clock, chip-select, command, and synchronization signals but exclude optional reset and backlight pins.

InterfaceData linesApproximate GPIO countTypical bandwidthDisplay-side GRAMTypical applications
I2C1 bidirectional2, shared with other I2C devices≤ 1 MbpsYesSmall monochrome OLEDs, such as 0.96-inch modules
4-wire SPI14–540–80 MbpsYesFull-color displays below 3.5 inches, e-paper, RLCD
QSPI46–7Theoretical peak of four times SPIController-dependentHigh-resolution 1–2-inch AMOLED
I80 (8080 parallel)8 / 1611–20HighYesSmall and medium LCDs
RGB parallel8 / 16 / 18 / 2412–28HighNoDisplays of 3.5 inches and larger
MIPI-DSI1–2 data lanes plus 1 clock lane4–6 pins, or 2–3 differential pairsVery highNo in Video ModeHigh-resolution displays with ESP32-P4

2.1 SPI: The Most Common Interface

SPI is the most common display interface for ESP32 boards. It requires few pins, is easy to wire, and is supported across the ESP32 family. A typical 4-wire SPI display module uses the following pins, matching the labels found on Waveshare modules:

PinDescription
VCC / GNDPower
DIN (MOSI)Data from the microcontroller to the display
CLK (SCLK)Clock
CSActive-low chip select
DCCommand/data selection: low for commands and high for pixel data
SDO (MISO)Optional data from the display to the microcontroller for reading an ID, status, or GRAM. It may remain disconnected in write-only applications.
RSTActive-low reset. Some modules allow this signal to be omitted; pass -1 as the reset-pin argument when supported by the driver.
BLLCD backlight control; connect to PWM for brightness adjustment

The DC signal distinguishes display SPI from an ordinary SPI device. The display controller uses its level to determine whether each byte is a command or data. Whether RST can be omitted depends on the module schematic and the driver.

2.2 Three Factors That Limit Frame Rate

What is commonly called “frame rate” consists of three independent stages. The slowest one limits the perceived result:

  1. Rendering frame rate: How quickly the microcontroller generates pixels. It depends on CPU performance and scene complexity and varies over time. Updating a small region is usually faster than rendering a complete frame.

  2. Interface frame rate: How quickly the interface can transfer complete frames. It is determined by interface bandwidth and frame size:

    Maximum interface frame rate ≈ interface bandwidth ÷ data per frame

    This is a theoretical limit. Protocol overhead reduces the practical result, so leave margin in an estimate.

  3. Panel refresh rate: How quickly the display controller scans GRAM to the panel, as described in Refreshing and Tearing. A controller determines this rate independently of the transfer rate for SPI and I80 displays. An RGB panel has no such separation: the microcontroller's output timing is the panel scan timing.

Why measured frame rate is lower than the estimate

SPI, QSPI, and I80 transactions include command, transaction-gap, and DMA-block overhead. RGB and MIPI-DSI Video Mode also include blanking intervals outside the active image. Memory and DMA bandwidth can introduce additional limits.

Interface frame rate is the most important estimate when selecting an interface. Consider a 240×320 RGB565 display over 40 MHz SPI. One frame is approximately 1.23 Mbit, so the theoretical interface limit is about 40 Mbps ÷ 1.23 Mbit ≈ 32 frames per second. Command and protocol overhead reduce the actual rate. This calculation explains several common design choices:

  • SPI normally provides enough bandwidth for basic GUIs at resolutions such as 240×240 and 240×320. At higher resolutions, full-screen transfers quickly become the bottleneck.
  • Compact, high-resolution AMOLED modules in the ESP32 ecosystem, such as 410×502 and 466×466 panels, often use QSPI to reduce the bandwidth limitation of single-data-line SPI.
  • One 800×480 RGB565 frame occupies 750 KB. Transferring complete frames over single-data-line SPI is too slow for a fluid GUI, so these panels commonly use RGB, QSPI, or MIPI-DSI.

If the interface estimate is sufficient but the result remains slow, rendering is likely the bottleneck. Optimize the drawing logic or reduce scene complexity before increasing the interface clock.

2.3 Interface Summary

  • I2C: Uses the fewest pins and shares the bus with other I2C devices, but provides the lowest bandwidth. It is suitable only for small monochrome OLEDs.
  • SPI: Uses only 4–5 GPIOs and is supported by every ESP32 family. It is the most broadly applicable choice, but higher resolutions require a faster interface.
  • QSPI: Expands SPI from one data line to four. During pixel transfers, each clock can carry up to 4 bits, giving a theoretical peak of four times single-data-line SPI. It is widely used by high-resolution AMOLED modules.
  • I80: Uses an 8- or 16-bit parallel bus and provides greater bandwidth than SPI. Including WR, DC, CS, and other control signals, it normally requires 11–20 GPIOs, so it is less common on pin-constrained ESP32 designs.
  • RGB: The microcontroller generates the panel timing directly. It provides high bandwidth and reduces display-side cost, but uses many GPIOs and requires a complete framebuffer on the microcontroller. Large displays generally depend on PSRAM.
  • MIPI-DSI: A high-speed differential serial interface for high-resolution, high-refresh-rate panels. It combines high bandwidth with a low pin count and is currently supported only by ESP32-P4.

3. Display Interfaces Supported by ESP32 Devices

Interface support varies across ESP32 families. Confirm the microcontroller's capabilities before choosing a panel:

InterfaceSupported ESP32 families
I2C / SPI / QSPIAll families through the general-purpose I2C and SPI peripherals
I80Native support: ESP32 through I2S LCD mode, ESP32-S2, ESP32-S3, ESP32-S31, and ESP32-P4 through dedicated LCD peripherals.
Emulated support: devices without a native I80 peripheral, such as ESP32-C5, C6, and H2, can generate I80 timing with the Parallel IO (PARLIO) peripheral.
RGBESP32-S3, ESP32-S31, ESP32-P4
MIPI-DSIESP32-P4

For the current interface matrix, see Supported Interface Types in the ESP-IoT-Solution LCD Development Guide.

The following general guidance applies:

  • ESP32-P4 supports the broadest set of display interfaces and is intended for high-resolution displays. It does not include a wireless radio, so development boards often add a device such as ESP32-C6 for Wi-Fi and Bluetooth.
  • ESP32-S3 is widely used in display products because it combines a dedicated LCD peripheral with optional high-capacity PSRAM.
  • ESP32-S31 supports the same display-interface types as ESP32-S3 and delivers higher measured frame rates with comparable RGB panels.
  • ESP32-C3 and ESP32-C6 designs primarily use general-purpose SPI and are a good fit for small and medium SPI displays.

For measured frame rates at different resolutions and interfaces, see the LVGL Benchmark table in Espressif's LCD Application Note.

In the Arduino ecosystem, graphics libraries abstract most differences among SPI, QSPI, I80, and RGB displays:

LibraryIntended use
GFX Library for Arduino (Arduino_GFX)General-purpose full-color graphics library supporting SPI, QSPI, I80, RGB, and many display controllers
LovyanGFXHigh-performance full-color graphics library with touch and multiple bus types
TFT_eSPIEstablished SPI graphics library configured for a specific display
u8g2Monochrome graphics library commonly used with OLED and RLCD panels, with an extensive font collection
GxEPD2E-paper driver library
Waveshare example packagesOfficial board- and module-specific drivers and examples with the correct pins and parameters

The pages for each display type and GUI Frameworks explain which libraries are appropriate. Newer interfaces such as MIPI-DSI currently rely primarily on ESP-IDF and its display components.

tip

On a Waveshare development board with an integrated display, such as an ESP32-S3-Touch-LCD model, the display is already connected to the microcontroller. Use the pins and initialization parameters from the board's official example package.

4. General Driver Sequence for Displays with GRAM

A display with a controller and GRAM, connected over SPI, I2C, or I80, normally follows this sequence:

  1. Initialize the bus: Configure the SPI or I2C pins and clock frequency.
  2. Reset the display: Hold RST low briefly, then release it to place the controller in a known state.
  3. Send the initialization sequence: Write commands that configure power, scan direction, pixel format, and other controller settings. The display manufacturer tunes this sequence for the specific panel. Use the existing initialization code from the Waveshare example or driver library instead of creating a sequence from scratch.
  4. Set the write window: Select the rectangular region to update, either the complete display or a smaller area.
  5. Write pixel data: Send pixels in the selected format, such as RGB565, for the chosen region.

Later updates repeat steps 4 and 5. With Arduino_GFX or u8g2, begin() handles steps 1 through 3, while functions such as drawPixel(), fillRect(), and drawBitmap() implement steps 4 and 5. Depending on the library and buffering mode, a drawing function may transfer pixels immediately or place them in a microcontroller-side buffer for a later flush() or sendBuffer().

Other display types differ from this sequence. RGB panels and MIPI-DSI panels in Video Mode do not use a write window and display-side GRAM. The application draws into a microcontroller-side framebuffer, and the LCD peripheral continuously outputs it with the pixel clock and synchronization timing. E-paper controllers accept data into display RAM but then require a refresh command and a wait for the BUSY signal to be released.

5. Further Reading


Continue with a specific display technology, or return to the display overview to compare the available options.