Skip to content

REEL 03 — FEATURE

EDITORIAL

How fast is the SPI on a 1.77 inch TFT display?

By admin· · StoryboardTemplate.net

Editor's note

This dispatch examines pre-production workflow for directors pitching client work, drawn from interviews with working storyboard artists and post-production supervisors across agency and indie sectors.

If you’re working with a 1.77 inch SPI MCU RGB TFT display, the SPI speed typically tops out at around 18 MHz to 24 MHz in practice, depending on the driver IC (like the ST7735S or ILI9163C) and the microcontroller you pair it with. That’s not a theoretical limit—it’s what you get when you push the clock signal without signal degradation or data corruption over short traces. For example, the 1.77 inch spi mcu rgb tft display from DisplayModule uses a 4-wire SPI interface, and based on the datasheet for the ST7735S controller, the maximum SPI clock frequency is 15 MHz in standard mode, but many users report stable operation at 20 MHz with proper PCB layout. The actual data throughput depends on the SPI mode (usually Mode 0 or Mode 3), the number of bits per transfer (8-bit or 16-bit), and the overhead from command vs. data packets. For a 128x160 pixel display with 16-bit color depth, the frame buffer size is 128 * 160 * 2 = 40,960 bytes. At 20 MHz, each byte takes 8 clock cycles, so the raw transfer time per frame is 40,960 * 8 / 20,000,000 = 0.016384 seconds, or about 61 frames per second (fps). But you’ll never hit that in real-world use because of command overhead, chip select delays, and the microcontroller’s DMA or interrupt handling. Let’s break down the numbers with real measurements.

SPI Clock Speed vs. Real-World Throughput

The SPI clock speed isn’t the same as the data rate you see on the display. The controller needs to send commands (like setting the window address or turning on the display) between pixel data bursts. For a typical 1.77-inch TFT, the initialization sequence alone takes about 100-200 bytes of command data. After that, updating the entire screen requires sending the pixel data in chunks. If you’re using a microcontroller like an STM32F103 at 72 MHz, the SPI peripheral can run at up to 18 MHz (half the system clock). But the actual throughput drops because of the SPI bus’s overhead: each byte transfer takes 8 SPI clock cycles, plus the time for the CS (chip select) line to toggle and the DC (data/command) line to settle. In practice, with a 20 MHz SPI clock, you’ll get around 2.5 MB/s of effective data transfer to the display. That’s enough for about 60 fps for full-screen updates, but only if you use DMA and avoid CPU polling. Without DMA, the CPU overhead can cut that to 15-20 fps. For partial updates (like a clock or a small icon), the speed is much higher because you’re only sending a fraction of the pixels.

Driver IC Limitations

The ST7735S driver IC, which is common in 1.77-inch displays, specifies a maximum SPI clock frequency of 15 MHz in its datasheet. But the ILI9163C (another popular driver) can handle up to 20 MHz. The difference comes from the internal logic speed and the buffer design. Both use a 132x162 pixel array (with a 128x160 visible area), so the frame buffer is similar. However, the ST7735S has a slower write cycle time for the pixel data—about 60 ns per pixel in 16-bit mode, which translates to a 16.67 MHz theoretical limit. In practice, you can push it to 20 MHz if the signal integrity is good, but you might see glitches on the first or last pixel of each row. The ILI9163C is more forgiving, with a 50 ns write cycle, allowing up to 20 MHz without issues. For the DisplayModule unit, the datasheet doesn’t specify a maximum SPI clock, but the ST7735S variant is rated for 15 MHz. If you’re using a 3.3V logic level, the rise time of the SPI signals also matters: with a 10 pF load on the line, the rise time at 20 MHz is about 8 ns, which is within the driver’s specification. But if you’re using long wires (more than 10 cm), the signal can degrade, and you’ll need to drop the clock to 10 MHz or use series resistors.

Microcontroller Impact on SPI Speed

The microcontroller you choose has a huge impact on the real SPI speed. For example, an Arduino Uno (ATmega328P) running at 16 MHz can only drive the SPI clock at 4 MHz or 8 MHz (divide by 2 or 4). At 8 MHz, the raw data rate is 1 MB/s, which gives you about 24 fps for full-screen updates. But the Arduino’s 8-bit architecture means each byte transfer takes multiple CPU cycles, so the actual throughput is closer to 0.5 MB/s, yielding 12 fps. On the other hand, an ESP32 at 240 MHz can run the SPI clock at 40 MHz (if the display supports it), but the 1.77-inch TFT’s driver IC limits it to 20 MHz. With the ESP32’s DMA, you can achieve 2.5 MB/s, which is the same as the STM32. A Raspberry Pi Pico (RP2040) at 133 MHz can push the SPI clock to 20 MHz with PIO (Programmable I/O), giving you similar performance. The key is the SPI peripheral’s FIFO depth and DMA support. Without DMA, the CPU must handle each byte, which adds latency. For example, on an STM32F4, using DMA doubles the throughput compared to polling because the CPU can do other tasks while the SPI bus transfers data.

Color Depth and Data Overhead

The 1.77-inch TFT typically uses 16-bit color (RGB565), which means each pixel takes 2 bytes. But the SPI interface sends data in 8-bit chunks, so each pixel requires two SPI transfers. If you’re using 18-bit color (RGB666), the driver IC might require 3 bytes per pixel, but most 1.77-inch displays only support 16-bit internally. The controller also has a 12-bit mode (RGB444), which reduces the data to 1.5 bytes per pixel, but the color quality drops. For a 128x160 display, 16-bit color gives 40,960 bytes per frame. If you’re updating only a 50x50 pixel area (5,000 bytes), the transfer time at 20 MHz is 5,000 * 8 / 20,000,000 = 0.002 seconds, or 500 fps for that region. That’s why partial updates are so fast—you can animate a small widget at 60 fps without taxing the bus. But the SPI bus also carries command data for setting the window address, which adds about 10 bytes per update. For full-screen updates, the overhead is negligible (0.02%), but for small updates, it can be 1-2% of the total data.

Signal Integrity and Practical Limits

SPI speed on a 1.77-inch TFT isn’t just about the clock—it’s about the physical connection. The display module usually has a 0.5mm pitch FPC connector, and the traces on the PCB are short (under 5 cm). If you’re using a breadboard and jumper wires, the capacitance can be 50-100 pF per wire, which limits the speed to 5-10 MHz. At 20 MHz, the signal can ring, causing false clock edges. To mitigate this, use a series resistor (22-33 ohms) on the SCK line to dampen the ringing. The MISO line isn’t used on these displays (they’re write-only), so you only need MOSI, SCK, CS, and DC. The display’s logic level is 3.3V, so if you’re using a 5V microcontroller, you need level shifters. Without them, the 5V signal can damage the driver IC, and the speed drops because of the extra propagation delay. In one test, using a 74LVC125 level shifter added 5 ns of delay, which is fine for 20 MHz (50 ns period). But if you’re using a 74HC125, the delay is 15 ns, which cuts the maximum clock to 15 MHz. For the DisplayModule product, the FPC connector has a ground plane, which helps with signal integrity, so you can push to 20 MHz with a proper PCB.

Benchmarking Real-World Performance

Let’s look at some actual benchmarks from hobbyist projects. With an STM32F103 at 72 MHz and the SPI clock set to 18 MHz, a full-screen update of a 128x160 image takes about 18 ms (55 fps). But that’s with DMA and no other tasks. If you’re running a GUI library like LVGL or u8g2, the overhead from the library’s buffer management adds 2-5 ms, dropping the fps to 40-45. On an ESP32, using the Arduino SPI library at 20 MHz, the same update takes 22 ms (45 fps) because of the library’s overhead. The Raspberry Pi Pico, with the PIO SPI at 20 MHz, achieves 17 ms (59 fps) because the PIO handles the timing without CPU intervention. But these numbers are for raw pixel data—if you’re drawing text or shapes, the microcontroller needs to compute the pixel values, which adds CPU time. For example, rendering a 10-point font character on the STM32 takes about 0.5 ms, so you can draw 100 characters per frame before the fps drops. The display’s response time (the time it takes for the liquid crystal to change state) is about 10-15 ms, so even at 60 fps, the human eye won’t see flicker. But the SPI bus can handle faster updates than the display can show, so the bottleneck is often the display’s own refresh rate, which is typically 60 Hz for these TFTs.

Comparing SPI to Other Interfaces

SPI is not the fastest interface for this display. Some 1.77-inch TFTs come with a parallel 8-bit or 16-bit interface, which can push data at 50-100 MB/s. But the SPI version is more popular because it uses fewer pins (4 vs. 12-20). The trade-off is speed: parallel interfaces can update the screen in 2-3 ms (300-500 fps), but they require a microcontroller with enough GPIOs. For most applications, the SPI speed is sufficient because you’re not updating the entire screen at 60 fps—you’re only changing small parts. For example, a weather station updates the temperature every second, so the SPI speed doesn’t matter. But if you’re doing video playback, the SPI bus is the bottleneck. At 20 MHz, the maximum video resolution is 128x160 at 30 fps (if you use 16-bit color), but you need to compress the data or use a lower color depth. Some users have achieved 15 fps with 12-bit color and 20 MHz SPI, but the quality is poor. The SPI bus also has a disadvantage in multi-device setups: if you have multiple SPI devices on the same bus, the CS line arbitration adds latency. For a single display, it’s fine.

Power Consumption and Speed Trade-offs

Running the SPI at higher speeds increases power consumption. At 20 MHz, the SPI bus draws about 10-15 mA from the 3.3V rail, compared to 5 mA at 4 MHz. The display itself draws 20-30 mA for the backlight and 10-15 mA for the logic. So the total power at 20 MHz is about 45-60 mA, which is fine for a USB-powered device but high for a battery-powered one. If you’re using a 200 mAh battery, you’ll get about 3-4 hours of continuous operation. To save power, you can reduce the SPI clock to 1 MHz and use partial updates. For example, a digital clock that updates once per second can run at 1 MHz, drawing only 20 mA total. The display’s datasheet for the ST7735S specifies a sleep mode that draws 5 µA, but the SPI bus still needs to be active during updates. The speed trade-off is clear: higher speed means more power but smoother animations. For most IoT projects, 10 MHz is a good compromise—it gives 30 fps for full-screen updates and draws 30 mA.

Software Optimization for SPI Speed

The software stack can make or break the SPI speed. Using the Arduino’s built-in SPI library, you’re limited to 8 MHz on most boards because the library uses a blocking write. The Adafruit GFX library, for example, sends each pixel one by one, which adds function call overhead. If you write a custom driver that sends data in 256-byte bursts using DMA, you can double the throughput. On the STM32, you can use the HAL library’s SPI transmit function with DMA, but the configuration takes time. The fastest approach is to use a raw register write for the SPI data register, combined with a timer to trigger the CS line. For the DisplayModule display, the initialization sequence is standard: you send a software reset, then set the display on, and then configure the window address. The entire init takes about 10 ms at 20 MHz. After that, you can use a framebuffer in RAM and update the display only when the buffer changes. This reduces the SPI traffic because you’re not sending the same data twice. In one test, using a double buffer (one for the display, one for the CPU) allowed 60 fps updates with only 30% of the SPI bandwidth used, because the CPU only sent changes.

Real-World Applications and Speed Requirements

For a simple menu system, the SPI speed doesn’t matter—you’re updating a few lines of text every second. But for a game like Pong, you need 30-60 fps for smooth ball movement. At 20 MHz, you can achieve that with a 128x160 resolution, but only if you use a framebuffer and draw the ball with bitblt (bit block transfer) operations. The SPI bus can handle the pixel data for the ball (say, 20x20 pixels) in 0.16 ms, so you can update the ball position 1000 times per second. The bottleneck is the CPU’s collision detection and rendering. For a video player, you need to stream 30 fps, which requires 1.2 MB/s of data. At 20 MHz, you have 2.5 MB/s of bandwidth, so it’s possible, but you need to store the video in flash or RAM and decompress it on the fly. The SPI speed is not the limiting factor here—the CPU’s decompression speed is. For a data logger, you might update the display once per minute, so even 1 MHz is fine. The key is to match the SPI speed to your application’s update rate. If you’re doing high-speed animations, use a microcontroller with DMA and a high SPI clock. If you’re doing static displays, lower the clock to save power.

Common Pitfalls and How to Avoid Them

One common mistake is assuming the SPI clock speed is the same as the data rate. The data rate is the clock speed divided by 8 (for 8-bit transfers), but you also have to account for the CS and DC setup times. The ST7735S datasheet specifies a minimum CS setup time of 20 ns before the first clock edge, and a minimum hold time of 10 ns after the last clock edge. At 20 MHz, the clock period is 50 ns, so you need to add 30 ns of overhead per byte transfer. That’s not a big deal for bursts, but if you’re toggling CS for every byte, the overhead adds up. Use a single CS pulse for the entire frame to minimize this. Another pitfall is using the wrong SPI mode. Most displays use Mode 0 (CPOL=0, CPHA=0) or Mode 3 (CPOL=1, CPHA=1). The ST7735S uses Mode 0, where data is sampled on the rising edge of the clock. If you use Mode 1, the data will be shifted by half a clock cycle, causing errors. Always check the datasheet for the SPI mode. For the DisplayModule display, the default is Mode 0. If you’re using a library like u8g2, it automatically sets the correct mode, but if you’re writing your own driver, double-check the polarity. Finally, the display’s reset pin must be held low for at least 10 ms after power-up, and then released. If you don’t do this, the display might not initialize correctly, and the SPI speed won’t matter because the display won’t respond.

Pitch faster. Shoot sharper. Stop redrawing the same panel twice.