Skip to content
SF · NYC · LDN · SGP
Strategic Communications — Field Note

What is a SPI display exporter and how does it work in embedded systems?

Published
Authoraadmin
PublisherMegalith Communications

An SPI display exporter is a hardware or software component that takes graphical data from a microcontroller or processor and sends it over a Serial Peripheral Interface (SPI) bus to a display module, like an LCD or OLED screen. In embedded systems, this exporter acts as a bridge that converts pixel data—often stored in a frame buffer—into SPI-compatible signals, including clock, data, chip select, and sometimes data/command lines. The core function is to offload display rendering from the main CPU, allowing it to handle other tasks while the exporter manages the timing and protocol specifics. For example, a typical 128x64 OLED display using SPI requires a clock speed of 10 MHz to 20 MHz, and the exporter must handle command sequences like setting contrast (0x81) or turning the display on (0xAF). The exporter can be built into the display controller chip, like the SSD1306 for OLEDs, or implemented as a separate peripheral in a microcontroller, such as the STM32’s SPI peripheral with DMA. Without an exporter, the CPU would have to bit-bang the SPI protocol, which eats up processing cycles—often 30% to 50% of CPU time for a 320x240 display at 60 Hz refresh. The exporter ensures data flows efficiently, using FIFO buffers to handle bursts, and supports multiple displays by toggling chip select lines. In practice, an SPI display exporter is critical for real-time systems like medical devices or industrial controls, where screen updates must happen without lag.

The SPI bus itself is a synchronous serial interface, using four wires: MOSI (Master Out Slave In), MISO (Master In Slave Out), SCK (Serial Clock), and CS (Chip Select). For a display exporter, MISO is often unused because displays are typically write-only, so the exporter only sends data. The clock frequency determines how fast pixels are transmitted. For a 240x240 pixel display with 16-bit color (RGB565), each frame requires 240 * 240 * 2 = 115,200 bytes. At 20 MHz SPI clock, with 8 bits per clock cycle, the theoretical transfer time is 115,200 / (20e6 / 8) = 0.046 seconds, or about 21.7 frames per second. But real-world overhead—like command bytes, delays, and protocol overhead—drops this to around 15 to 18 fps. The exporter manages this by packing data into bursts and using DMA (Direct Memory Access) to move data from RAM to the SPI shift register without CPU intervention. For instance, the ESP32 microcontroller has two SPI controllers, each with dedicated DMA channels, capable of transferring up to 64 KB per burst. The exporter configures the SPI registers—like setting the clock polarity (CPOL) and phase (CPHA) to match the display’s datasheet. Most displays use mode 0 (CPOL=0, CPHA=0) or mode 3 (CPOL=1, CPHA=1). The exporter also handles the data/command (DC) pin, which tells the display whether the byte is an instruction (e.g., set column address) or pixel data. A typical initialization sequence for an ILI9341 TFT display involves sending 30+ commands, like 0x11 (sleep out) followed by a 120 ms delay, then 0x29 (display on). The exporter automates this sequence, often using a lookup table stored in flash memory.

From a hardware perspective, the exporter can be integrated into the display module’s driver IC. For example, the ST7735S driver for 1.8-inch TFTs includes a built-in SPI interface that handles 262K colors and supports 132x162 pixel resolution. The exporter on the microcontroller side must match the driver’s timing: setup time (tSU) for data before clock edge is typically 5 ns, and hold time (tH) is 10 ns. If the exporter violates these, the display shows glitches or ghosting. The exporter also manages power sequencing—some displays require a reset pulse (low for 10 µs) before SPI communication starts. In battery-powered systems, the exporter can put the display into sleep mode (command 0x10) with a 0.1 µA current draw, compared to 20 mA when active. The exporter’s firmware must handle partial updates, where only a region of the screen is refreshed, reducing SPI traffic by 50% to 80% for static UIs. For example, updating a 50x50 pixel icon on a 320x240 display requires only 5,000 bytes instead of 153,600 bytes for a full frame. The exporter uses the display’s windowing commands (e.g., 0x2A for column address, 0x2B for row address) to set the update region. This is critical for high-frequency data logging, like plotting sensor readings at 100 Hz, where the exporter must sync the SPI transfer with the display’s internal refresh rate, typically 60 Hz to 120 Hz.

Data density plays a huge role in exporter performance. A 16-bit color depth per pixel means the exporter sends 2 bytes per pixel. For a 480x320 display, that’s 307,200 bytes per frame. At 40 MHz SPI clock, the theoretical max frame rate is 307,200 / (40e6 / 8) = 0.0614 seconds, or 16.3 fps. But the exporter must also send command bytes—like setting the write memory command (0x2C) before each burst—which adds 5% to 10% overhead. The exporter can use a technique called “command mode” where it sends a command then a stream of data without re-asserting the command byte. For example, the ILI9341 supports continuous write mode, where the exporter sends 0x2C once, then 307,200 bytes of pixel data, reducing overhead to near zero. The exporter’s DMA engine must be configured for this, using a circular buffer if the display is updated continuously. In practice, the exporter’s throughput is limited by the display’s internal pixel clock, which for a 320x240 TFT is typically 6.5 MHz to 10 MHz. So even if the SPI bus runs at 40 MHz, the display’s driver IC buffers the data and writes it to the pixel matrix at its own pace. The exporter must handle this with flow control—some drivers have a busy pin (BUSY) that signals when they’re ready for more data. The exporter can poll this pin or use an interrupt, but polling wastes CPU cycles, so interrupt-driven transfers are better for real-time systems.

In embedded systems, the exporter is often part of a larger graphics stack. For example, in a FreeRTOS-based system, the exporter runs as a task with priority 2, while the main application runs at priority 1. The exporter task uses a queue to receive frame buffers from the application, then sends them via SPI using DMA. The queue depth is typically 2 to 3 buffers to avoid underflow. The exporter must also handle double buffering—one buffer is being sent over SPI while the other is being filled by the application. This doubles memory usage but eliminates tearing artifacts. For a 320x240 display with 16-bit color, each buffer is 153,600 bytes, so double buffering uses 307,200 bytes of RAM. On a microcontroller like the STM32F4 with 192 KB RAM, this is tight, so the exporter might use a single buffer with a partial update strategy. The exporter’s performance is also affected by the SPI peripheral’s FIFO depth. The STM32F4’s SPI has a 16-bit FIFO, meaning it can store 2 bytes before the DMA must refill it. If the DMA is busy, the FIFO empties, causing underrun and data corruption. The exporter mitigates this by using a higher DMA priority or enabling FIFO threshold interrupts. For displays with higher resolutions, like 800x480, the exporter might use a parallel interface (RGB or MCU) instead of SPI, because SPI’s serial nature becomes a bottleneck. At 40 MHz, 800x480 with 24-bit color requires 1,152,000 bytes per frame, taking 0.23 seconds per frame—only 4.3 fps. So for such displays, the exporter switches to a parallel interface, but that requires more GPIO pins (16 to 24 vs. 4 for SPI).

The exporter’s software stack often includes a graphics library like LVGL or uGFX. These libraries abstract the hardware, so the exporter implements a driver that matches the library’s API. For LVGL, the exporter must provide a flush callback that takes a buffer of pixels and sends it to the display. The callback uses the SPI exporter to set the window and send the data. The callback’s execution time must be under 16 ms for 60 fps, which is achievable with DMA. The exporter also handles rotation—flipping the display orientation by remapping the column and row addresses. For example, the ILI9341 has a memory access control command (0x36) that sets the scan direction. The exporter writes 0x36 with a byte like 0x48 for landscape mode. The exporter must also handle color depth conversion—if the application uses 24-bit RGB888 but the display only supports 16-bit RGB565, the exporter converts each pixel by dropping the least significant bits. For 300,000 pixels, this conversion takes about 2 ms on a 168 MHz Cortex-M4, assuming 1.5 cycles per pixel. The exporter can optimize this with SIMD instructions or lookup tables. For monochrome displays, like 128x64 OLEDs, the exporter packs 8 pixels into 1 byte (1-bit per pixel), so a full frame is only 1,024 bytes. This allows SPI speeds as low as 1 MHz, reducing power consumption to 0.5 mW compared to 50 mW for a color TFT.

Real-world examples show the exporter’s impact. In a portable ECG monitor, the exporter updates a 240x240 display at 30 fps, using an STM32L4 with 80 MHz clock. The SPI runs at 20 MHz, and the exporter uses DMA with a 2 KB FIFO. The CPU load for display updates is under 5%, leaving 95% for signal processing. In a smart thermostat, the exporter drives a 320x240 TFT at 15 fps, using an ESP32 with dual-core. The exporter runs on core 1, while the Wi-Fi stack runs on core 0. The SPI bus shares the same pins as the SD card, so the exporter uses a mutex to prevent conflicts. The exporter’s initialization sequence includes setting the display’s gamma curve (command 0xE0) with 15 bytes of correction values, which improves color accuracy by 10% to 15%. In a drone flight controller, the exporter sends telemetry data to a 128x64 OLED at 10 fps, using a 1 MHz SPI to minimize EMI. The exporter uses a 128-byte buffer and sends the entire frame in 1.024 ms, leaving the CPU free for PID loops. The exporter also handles sleep mode—when the drone is idle, it sends command 0xAE to turn off the display, reducing power from 10 mA to 0.1 mA.

Technical specifications vary by display. The following table shows common display modules and their SPI exporter requirements:

Display Type Resolution Color Depth SPI Clock (MHz) Frame Buffer (KB) Max FPS (Theoretical)
OLED (SSD1306) 128x64 1-bit 1-10 1 60-120
TFT (ST7735) 160x128 16-bit 10-20 40 30-50
TFT (ILI9341) 320x240 16-bit 20-40 150 15-30
TFT (RA8875) 800x480 24-bit 40-80 1,125 4-10

The exporter’s firmware must handle error conditions like SPI bus contention or display timeout. If the display doesn’t respond to a command, the exporter retries three times with a 10 ms delay. If the display’s busy pin stays high for more than 100 ms, the exporter resets the display by toggling the reset pin. The exporter also monitors the SPI’s error flags—like overrun or mode fault—and clears them by reading the status register. In multi-display systems, the exporter uses separate chip select lines for each display, but shares the MOSI and SCK lines. The exporter must ensure that only one display is selected at a time, with a 1 µs delay between chip select toggles to avoid bus contention. The exporter’s driver code is typically written in C, with inline assembly for critical sections. For example, the SPI write function on an ARM Cortex-M uses a loop that checks the TXE (transmit empty) flag before writing to the data register. With DMA, the exporter uses a linked list of descriptors, each pointing to a buffer of pixel data. The DMA controller generates an interrupt when a descriptor is complete, and the exporter’s ISR (interrupt service routine) queues the next buffer. The ISR must be short—under 10 µs—to avoid starving lower-priority tasks.

Power consumption is a key metric for the exporter. At 20 MHz SPI, the bus consumes about 0.5 mA per MHz, or 10 mA total, plus the display’s 20 mA to 50 mA. The exporter can reduce power by lowering the SPI clock when the display is static—e.g., 1 MHz for a still image, then 20 MHz for an animation. The exporter also uses the display’s sleep mode, which cuts power to 0.1 mA. In battery-powered devices, the exporter might update the display only when data changes, using a frame buffer comparison. If the new buffer matches the old one, the exporter skips the SPI transfer, saving 99% of power. The exporter’s firmware must be careful with the comparison—using a CRC32 check on the buffer, which takes 0.5 ms for 150 KB on a 168 MHz CPU. The exporter also supports partial updates, where only a 10x10 pixel region changes, reducing SPI traffic to 200 bytes. This is useful for digital clocks, where only the seconds digit changes every second.

Latency is another critical factor. The exporter’s end-to-end latency—from the application writing to the frame buffer to the pixel appearing on the display—must be under 16 ms for 60 fps. The SPI transfer itself takes 5 ms to 10 ms for a full frame, but the DMA setup and interrupt handling add 0.5 ms to 1 ms. The display’s internal latency is another 5 ms to 10 ms, depending on the driver IC. The exporter can reduce latency by using a smaller update window—e.g., updating only the top 10 rows of the display, which takes 0.5 ms. In gaming applications, the exporter might use a technique called “tear-free” update, where it waits for the display’s vertical blanking period before sending data. This requires the exporter to read the display’s status register (e.g., 0x09 on the ILI9341) to check if the display is in the vertical sync period. If the exporter sends data during the active display period, it causes tearing—a horizontal line where the image splits. The exporter waits for the status bit to go low, then sends the frame. This adds up to 16 ms of delay, but eliminates artifacts.

The exporter’s development process involves verifying timing with an oscilloscope. The SPI clock must have a duty cycle of 50% ±5%, and the setup and hold times must meet the display’s datasheet. For example, the ST7735 requires tSU of 5 ns and tH of 10 ns, which is easy to meet at 20 MHz (50 ns period). But at 40 MHz (25 ns period), the margin is tight. The exporter might need to adjust the SPI’s clock phase or add a delay in the firmware. The exporter also needs to handle the display’s reset sequence—some displays require a 10 ms delay after power-up before SPI communication. The exporter’s initialization code is often stored in a const array, with each element being a command byte and a delay value. For example, the ILI9341 initialization sequence has 40 commands, each with a delay of 0 to 120 ms. The exporter loops through the array, sending each command and waiting the specified delay. The exporter also handles the display’s orientation—by default, the display is in portrait mode, but the exporter can rotate it by setting the MADCTL register (0x36). For a 90-degree rotation, the exporter sets the MX and MY bits, and swaps the column and row counts. The exporter must also update the windowing commands to match the new orientation.

In multi-processor systems, the exporter might run on a dedicated graphics coprocessor, like the FT800 or FT813 from FTDI. These chips have their own SPI interface and handle the entire display pipeline, including touch input. The main CPU sends high-level commands—like “draw a rectangle at (x,y)”—over SPI, and the coprocessor renders the pixels. This reduces the main CPU’s workload by 80% to 90%. The exporter in this case is the SPI master on the main CPU, sending commands at 30 MHz to 60 MHz. The coprocessor’s SPI slave interface has a 256-byte

01 — Next Step

Move from commentary to category leadership.

Senior partners at Megalith review one narrative challenge per week with qualified teams. No deck, no pitch — a working session.