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. |
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
- 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.
- 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.
- 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
fatal error: Adafruit_ST7789.h: No such file or directoryCause: 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".
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
PROGMEMkeyword. - 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.






