Difficulty: Intermediate | Time: 45 Minutes | Cost: ~$18 USD

Driving a color display from a microcontroller is a rite of passage, but the lcd tft arduino ecosystem is littered with cheap, poorly documented clones that lead straight to the dreaded "White Screen of Death." If you are trying to push pixels to a TFT LCD on an Arduino, you need to make a hard decision on which controller chip to use, wire it to the correct hardware SPI pins, and manage the severe SRAM limitations of 8-bit AVR boards.

This guide cuts through the outdated 8-bit parallel shield tutorials and gives you a modern, decision-forward path to building a reliable TFT dashboard using the ST7789 controller.

The Verdict: Which LCD TFT Arduino Display Should You Buy?

Before wiring anything, you must choose the right display architecture. The market is flooded with three main types of TFT displays for Arduino. Here is the decision matrix to terminate your search.

Display Type Controller / Resolution Wiring & Pin Count AVR SRAM Impact Verdict
8-Bit Parallel Shield MCUFRIEND / ILI9341 (320x240) 12+ pins (blocks almost all Uno I/O) High (requires line-buffering) SKIP: Legacy tech, slow refresh, pin-hog.
SPI TFT (Older) ILI9341 (320x240) 5-6 pins (SPI + CS/DC) Medium (direct draw only) OKAY: Good, but slower SPI clock limits.
SPI TFT (Modern) ST7789 (240x240 IPS) 5-6 pins (Hardware SPI) Low (fast direct draw, no buffer needed) DEFAULT PICK: Fast, vibrant, efficient.
The Concrete Pick: Buy a 2.0-inch 240x240 ST7789 SPI IPS Display. Crucially, ensure the product listing explicitly states it has an onboard 3.3V LDO and logic level shifting. The ST7789 chip's internal I/O runs at 1.8V; feeding it raw 5V from an Arduino Uno's MOSI pin without a level shifter will permanently brick the silicon.

Parts List & Pin Mapping for the ST7789 Build

This build targets the Arduino Uno R3 (ATmega328P). While the Uno R4 Minima is excellent, the R3 remains the most common board on workbenches, and its 2KB SRAM limit makes display optimization a necessary skill.

Bill of Materials

  • Microcontroller: Arduino Uno R3 (or genuine clone with ATmega16U2 USB IC)
  • Display: 2.0" 240x240 IPS ST7789 SPI Module (with onboard LDO/Level Shifter, ~$9-$12)
  • Wiring: 22 AWG solid-core jumper wires (female-to-male)
  • Power: 5V 2A USB power supply (TFT backlights draw up to 80mA; do not rely on a weak laptop USB port)

Hardware SPI Pin Mapping Table

Never use software (bit-banged) SPI for a TFT display. It will cap your refresh rate at roughly 4 FPS. Always use the Uno's hardware SPI pins.

ST7789 Display Pin Arduino Uno R3 Pin Function & Notes
VCC 5V Powers the onboard LDO (which steps down to 3.3V for the chip)
GND GND Common ground reference
SCL (SCK) D13 Hardware SPI Clock (Max 8MHz on Uno R3 5V logic)
SDA (MOSI) D11 Hardware SPI Data (Master Out Slave In)
CS D10 Chip Select (Active LOW)
DC (A0) D8 Data/Command toggle pin
RES (RST) D9 Hardware Reset (Active LOW)
BLK (LED) 3.3V or D7 Backlight. Tie to 3.3V for always-on, or D7 for PWM dimming.

Compilable Code: ST7789 Sensor Dashboard

The following code uses the Adafruit GFX and Adafruit_ST7789 libraries. Install both via the Arduino Library Manager before compiling.

Target Board: Arduino Uno R3 (ATmega328P).
Memory Note: A 240x240 16-bit color frame requires 115,200 bytes of RAM. The Uno only has 2,048 bytes. Therefore, this code uses direct-draw methods (pushing pixels directly to the display controller's internal GRAM) rather than a local framebuffer.


#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_ST7789.h>

// --- PIN DEFINITIONS (Arduino Uno R3) ---
#define TFT_CS    10  // Chip Select
#define TFT_DC     8  // Data/Command
#define TFT_RST    9  // Reset
#define TFT_BLK    7  // Backlight control (PWM capable)

// Initialize Hardware SPI instance
Adafruit_ST7789 tft = Adafruit_ST7789(TFT_CS, TFT_DC, TFT_RST);

// UI Colors (16-bit RGB565)
#define COLOR_BG      0x0000 // Black
#define COLOR_TEXT    0xFFFF // White
#define COLOR_ACCENT  0xF800 // Red
#define COLOR_GRID    0x2104 // Dark Grey

void setup() {
  Serial.begin(115200);
  
  // Backlight setup
  pinMode(TFT_BLK, OUTPUT);
  digitalWrite(TFT_BLK, HIGH); // Turn on backlight immediately

  // Initialize ST7789 240x240 display
  // Note: Hardware SPI speed is set to 8MHz for safe 5V logic operation
  tft.init(240, 240, SPI_MODE0);
  tft.setSPISpeed(8000000); 
  tft.setRotation(1); // Landscape mode

  // Error handling: Check if display is responding (basic software check)
  // Hardware SPI doesn't return MISO errors easily, so we rely on visual init
  tft.fillScreen(COLOR_BG);
  
  drawStaticUI();
}

void loop() {
  // Simulate sensor data (e.g., reading from an A0 analog pin)
  int sensorVal = analogRead(A0);
  float voltage = sensorVal * (5.0 / 1023.0);
  
  updateDynamicUI(voltage);
  
  // Throttle updates to prevent SPI bus flooding and flickering
  delay(150); 
}

void drawStaticUI() {
  tft.setTextWrap(false);
  
  // Header
  tft.fillRect(0, 0, 240, 30, COLOR_ACCENT);
  tft.setTextColor(COLOR_TEXT);
  tft.setTextSize(2);
  tft.setCursor(10, 7);
  tft.print("FLUX DASHBOARD");
  
  // Grid lines for graph area
  for(int i=40; i<240; i+=40) {
    tft.drawFastVLine(i, 40, 160, COLOR_GRID);
  }
}

void updateDynamicUI(float val) {
  // Clear previous value area
  tft.fillRect(10, 210, 220, 25, COLOR_BG);
  
  // Draw new value
  tft.setTextColor(COLOR_TEXT);
  tft.setTextSize(2);
  tft.setCursor(10, 212);
  tft.print("Voltage: ");
  tft.setTextColor(COLOR_ACCENT);
  tft.print(val, 2);
  tft.print(" V");
}

Debugging the "White Screen of Death" & Compiler Errors

TFT displays fail in two distinct ways: at compile time (software) or at runtime (hardware). When your display fails to initialize, do not blindly swap wires. Follow this ranked diagnostic path.

The First Three Things to Check When It Fails

  1. The Backlight Pin (BLK/LED): If the screen looks completely black and dead, the display might actually be rendering, but the backlight is off. Use a multimeter to verify 3.3V on the BLK pin. If your module doesn't have a BLK pin broken out, check if it requires a physical jumper soldered on the back of the PCB.
  2. The 3.3V LDO Output: Measure the voltage on the display module's 3.3V output pad (if exposed) or check the VCC input. If you fed 5V into a module without an onboard LDO, you have likely overvolted the 1.8V internal core of the ST7789. The chip is dead; replace the module.
  3. Chip Select (CS) Logic: The ST7789 ignores all SPI clock/data signals unless CS is pulled LOW. Use an oscilloscope or logic analyzer to verify the Arduino's D10 pin is dropping to 0V during the tft.init() sequence.

Exact Error Strings & Ranked Causes

Error String 1: fatal error: Adafruit_ST7789.h: No such file or directory
Cause: Missing library dependencies.
Fix: Open Arduino IDE → Sketch → Include Library → Manage Libraries. Search for and install Adafruit ST7735 and ST7789 Library. It will prompt you to install the Adafruit GFX Library dependency; click "Install All".
Error String 2: Sketch uses 34512 bytes (106%) of program storage space. Maximum is 32256 bytes.
Cause: Flash memory overflow. The Adafruit GFX library plus font data easily exceeds the Uno R3's 32KB flash limit, especially if you include bitmap arrays.
Fix:
  • Move all bitmap arrays to flash memory using the PROGMEM keyword.
  • Use tft.setTextSize(1) and avoid loading custom fonts if flash is tight.
  • If your project requires heavy graphics, migrate the build to an Arduino Nano Every (48KB Flash) or Arduino Uno R4 Minima (256KB Flash).

The Hardware "White Screen of Death" (WSoD)

If the code compiles, uploads, the backlight turns on, but the screen is a harsh, glowing white (or static noise), the SPI initialization failed. The display controller never received the "Sleep Out" and "Display Inversion Off" commands.

Ranked Cause Diagnostic Test Solution
1. SPI Speed Too High Check tft.setSPISpeed() value. Drop SPI speed to 8000000 (8MHz). 5V Arduino clones often fail at 16MHz+ on breadboards due to parasitic capacitance.
2. Wrong Display Dimensions Check tft.init() arguments. Ensure you pass (240, 240). Passing (135, 240) or (320, 240) offsets the internal GRAM pointer, resulting in white/shifted screens.
3. MISO Short / Conflict Disconnect D12 (MISO). The ST7789 is write-only. If D12 is tied to another sensor (like an SD card) that isn't properly tri-stated, it will corrupt the SPI bus.

Extending and Simplifying the Build

Once your baseline dashboard is rendering cleanly, you will inevitably want to push the hardware further. Here is how to scale the project up or down based on your final application.

How to Extend: Adding Capacitive/Resistive Touch

Most 2.0" ST7789 displays do not include touch layers. If you need touch, you must add an XPT2046 resistive touch controller overlay.
Wiring Rule: The XPT2046 shares the SPI bus (MOSI, MISO, SCK) but must have its own dedicated Chip Select pin (e.g., Arduino D6). Never tie the TFT CS and Touch CS together. Furthermore, the XPT2046 requires the MISO line (D12), which the TFT display ignores. Ensure your touch module properly tri-states its MISO output when its CS is HIGH, or it will corrupt the TFT data stream.

How to Simplify: Switching to TFT_eSPI for ESP32 Migration

If you decide the Arduino Uno R3's 8MHz SPI bottleneck is too slow for smooth animations, migrate the exact same hardware to an ESP32-WROOM-32.
The Software Swap: Ditch the Adafruit libraries and use the TFT_eSPI library. By configuring the User_Setup.h file to define the ESP32's hardware SPI pins and pushing the clock to 40MHz, you will see a 5x to 8x increase in frame rendering speed. The ST7789 controller can easily handle 40MHz SPI when driven by the ESP32's native 3.3V logic, eliminating the need for level shifters entirely.

Stick to the ST7789 SPI architecture, respect the 3.3V logic boundaries, and manage your AVR memory footprint. Do that, and your LCD TFT Arduino project will survive long past the initial prototyping phase.