Preview build — page text is a draft awaiting human review. Code badges come from real compiles. The flasher is real but not yet hardware-tested; the Playground is still a preview.

ILI9341 2.8″ TFT with ESP32 DevKit V1 — 40 MHz SPI wiring

Wire a 2.4–2.8″ ILI9341 SPI TFT to an ESP32 DevKit V1 on VSPI with MISO for read-back, power it from VIN, and run it at 40 MHz with the Adafruit ILI9341 library.

Arduino C++Verified — core esp32 3.3.12, Adafruit ILI9341 1.7.0, 3 Nov 2026Compile-only

Community draft — report a mistake

The 2.4- and 2.8-inch ILI9341 panels are the step up from small TFTs: 320×240 pixels, often with a touch layer and an SD slot on the back, around ₹450–700 in India.

The ESP32 DevKit V1 suits them well. The panel’s signals are 3.3 V, the same as the ESP32, and the VSPI bus (D18, D19, D23) runs it at 40 MHz. Only VCC wants 5 V, from VIN. The sketch first reads the panel’s status registers back over MISO — a quick proof that every SPI wire is right — then times a full-screen fill and shows a flicker-free clock.

Wiring

ESP32 DevKit V1Only the pins used are shown · 3.3 V logicILI9341 TFT 2.4″ / 2.8″ (240×320, SPI, touch)D26D27GNDVIND23D19D18D43V3VCCGNDCSRESETDCSDI(MOSI)SCKLEDSDO(MISO)T_CLK (not connected)T_CS (not connected)T_DIN (not connected)T_DO (not connected)T_IRQ (not connected)
Every connection
ESP32 DevKit V1ILI9341 TFT 2.4″ / 2.8″ (240×320, SPI, touch)WireNotes
VINVCCred5 V with jumper J1 open (the board’s regulator makes 3.3 V). Only with J1 bridged may VCC go to 3V3.
GNDGNDblack
3V3LEDredBacklight. Left open, the screen stays dark.
D18SCKyellowVSPI clock
D23SDI(MOSI)greenVSPI MOSI
D19SDO(MISO)blueOnly needed to read the panel back; the sketch uses it to confirm the wiring.
D4CSpurpleNot D5 or D15 — both are strapping pins.
D26DCorange
D27RESETwhite

5 V with J1 open (on-board regulator) or 3.3 V with J1 bridged part, 3.3 V board. VCC can be 5 V, but every signal pin is 3.3 V only. ESP32 and Pico connect directly. On an Uno use a level shifter (74LVC245 / CD4050) or 1 kΩ / 2 kΩ dividers on CS, RESET, DC, SDI and SCK — 5 V signals give a white screen or a dead panel.

Board quirks

  • VCC may be 5 V, the signals may not. The ESP32’s 3.3 V signals are exactly right, which is why this panel is so much easier on an ESP32 than on an Uno (no level shifter needed).
  • The ESP32’s VSPI runs the panel at 40 MHz. A full-screen fill takes a few tens of milliseconds — fast enough for gauges and menus. If you see garbage, shorten the wires or lower tft.begin() to 27 MHz.
  • The touch controller (T_CLK, T_CS, T_DIN, T_DO, T_IRQ) is a separate SPI chip. It can share D18/D23/D19 with its own chip-select on a free pin such as D32; it isn’t used in this sketch.
  • An ILI9341 with backlight draws 80–100 mA. From a USB port that is fine; if you add Wi-Fi, a servo or LEDs, use a proper 5 V 1 A supply on VIN.
  • Bodmer’s TFT_eSPI library is faster again on the ESP32, but it is configured by editing a file inside the library. Adafruit_ILI9341 keeps the pins in your sketch.

Code

ili9341-esp32.inoArduino C++Open in PlaygroundOpen in PlaygroundFlash
// 2.4"/2.8" ILI9341 SPI TFT (240×320) on an ESP32 DevKit V1.
// VCC → VIN (5 V, J1 open), GND → GND, LED → 3V3, SCK → D18, SDI(MOSI) → D23,
// SDO(MISO) → D19, CS → D4, DC → D26, RESET → D27. Touch pins (T_*) not used here.
// Reads the panel's status registers back (proves MISO works), times a full-screen
// fill at 40 MHz SPI, then shows a live clock.
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_ILI9341.h>

constexpr int8_t TFT_CS = 4;
constexpr int8_t TFT_DC = 26;
constexpr int8_t TFT_RST = 27;
Adafruit_ILI9341 tft(TFT_CS, TFT_DC, TFT_RST);

void setup() {
  Serial.begin(115200);
  tft.begin(40000000);  // 40 MHz SPI; drop to 27 MHz if long wires give garbage
  uint8_t mode = tft.readcommand8(ILI9341_RDMODE);
  uint8_t diag = tft.readcommand8(ILI9341_RDSELFDIAG);
  Serial.printf("Power mode 0x%02X, self-diagnostic 0x%02X%s\n", mode, diag,
                (mode == 0x00 || mode == 0xFF) ? "  (no reply — MISO not wired? drawing still works)" : "");

  uint32_t t0 = millis();
  tft.fillScreen(ILI9341_BLUE);
  Serial.printf("Full-screen fill: %lu ms\n", (unsigned long)(millis() - t0));

  tft.setRotation(1);  // landscape, 320×240
  tft.fillScreen(ILI9341_BLACK);
  tft.setTextColor(ILI9341_WHITE);
  tft.setTextSize(3);
  tft.setCursor(10, 10);
  tft.print("FlashReady");
  tft.setTextSize(2);
  tft.setCursor(10, 50);
  tft.print("ILI9341 on ESP32 DevKit V1");
  tft.drawRect(0, 0, tft.width(), tft.height(), ILI9341_YELLOW);
}

void loop() {
  static uint32_t last = 0;
  if (millis() - last < 1000) return;
  last = millis();

  uint32_t s = millis() / 1000;
  tft.setTextSize(5);
  tft.setTextColor(ILI9341_GREEN, ILI9341_BLACK);  // background colour: overwrite, no flicker
  tft.setCursor(40, 120);
  tft.printf("%02lu:%02lu:%02lu", (unsigned long)(s / 3600), (unsigned long)(s / 60 % 60), (unsigned long)(s % 60));
}

Library: Adafruit ILI9341 (Adafruit (also install Adafruit GFX Library; on ESP32, TFT_eSPI by Bodmer is faster)) — compiled with Adafruit ILI9341 1.7.0.

Expected serial output

Serial Monitor · 115200Output
Power mode 0x9C, self-diagnostic 0xC0
Full-screen fill: 37 ms

Common errors

White screen

Power is on but no data arrives. Check SDI(MOSI) on D23, SCK on D18, CS on D4, DC on D26, RESET on D27. Make sure VCC isn’t on 3V3 with J1 open (too little voltage for the regulator).

“no reply — MISO not wired?” but the screen works

Only the read-back failed. Connect SDO(MISO) to D19, or ignore it: drawing doesn’t need MISO. Some cheap panels never answer reads.

Screen flickers when Wi-Fi or a motor starts

Supply dips. Use a 5 V 1–2 A supply on VIN and a 100 µF capacitor across VCC–GND at the display.

↑↓ to move · Enter to open