Using the ILI9341 TFT Display with an ESP32

This is a short ‘how-to’ on interfacing a colour ILI9341 TFT display with the ESP32 including code for using resistive touch screen using the TFT_eSPI Library.

This example uses the 3.2inch display with 240×320 pixel resolution, and should work with any other size screen as long as it has the ILI9341 display driver IC and the XPT2046 touch driver IC.

The connection is via the SPI bus, so this example will not work for parallel connection.

Likewise, this example will not work with an Arduino. I’m sure it’s possible with a logic-level converter, but the display has a total of 76,800 pixels. So a full-frame, full-16-bit colour image would require 153,600 bytes of memory. The ATMega328p chip used for Unos and Nanos only has 32,000 bytes of memory.


Hardware

Interestingly, I’ve found that this display will work with 5V power as well as 3.3V power.

Supplying the LED backlight with 5V produces a brighter image, but putting 5V into the VCC causes inaccuracies with the touch screen.

I don’t know if running the display has a negative effect on longevity, so proceed with caution.

Please note the logic is 3.3V. (I’ve never tested this with 5V logic and don’t intend to)

The connections are as follows:

  • ILI9341 VCC -> ESP32 3.3V (if it’s unstable then use 5V)
  • ILI9341 GND -> ESP32 GND
  • ILI9341 CS -> ESP32 D15
  • ILI9341 RST -> ESP32 D4
  • ILI9341 D/C -> ESP32 D2
  • ILI9341 SDI/MOSI -> ESP32 D23 (SPI BUS)
  • ILI9341 SCK -> ESP32 D18 (SPI BUS)
  • ILI9341 LED -> ESP32 3.3V
  • ILI9341 SDO/MISO -> ESP32 19 (SPI BUS)
  • ILI9341 T_CLK -> ESP32 D18 (SPI BUS)
  • ILI9341 T_CS -> ESP32 D21
  • ILI9341 T_DIN -> ESP32 D23 (SPI BUS)
  • ILI9341 T_OUT -> ESP32 D19 (SPI BUS)
  • ILI9341 T_IRQ -> (not connected)

User_Setup.h

The joys of using the TFT_eSPI library (link to Bodmer’s GitHub here) is that many different types of the displays are supported; the downside of this is the User_Setup.h file which must be configured for each individual MCU & Display option.

To save explaining it; just CTRL + C the below, and CTRL + V it into your User_Setup.h file and hit CTRL+S.

#define USER_SETUP_INFO "User_Setup"
#define ILI9341_DRIVER       // Generic driver for common displays
#define TFT_SDA_READ      // This option is for ESP32 ONLY, tested with ST7789 and GC9A01 display only
#define TFT_RGB_ORDER TFT_BGR  // Colour order Blue-Green-Red
#define TFT_MISO 19
#define TFT_MOSI 23		//changed TO this pin on 2023 01 06
#define TFT_SCLK 18		//changed TO this pin on 2023 01 06
#define TFT_CS   15  // Chip select control pin
#define TFT_DC    2  // Data Command control pin
#define TFT_RST   4  // Reset pin (could connect to RST pin)
//#define TFT_RST  -1  // Set TFT_RST to -1 if display RESET is connected to ESP32 board RST
#define TOUCH_CS 21     // Chip select pin (T_CS) of touch screen
#define LOAD_GLCD   // Font 1. Original Adafruit 8 pixel font needs ~1820 bytes in FLASH
#define LOAD_FONT2  // Font 2. Small 16 pixel high font, needs ~3534 bytes in FLASH, 96 characters
#define LOAD_FONT4  // Font 4. Medium 26 pixel high font, needs ~5848 bytes in FLASH, 96 characters
#define LOAD_FONT6  // Font 6. Large 48 pixel font, needs ~2666 bytes in FLASH, only characters 1234567890:-.apm
#define LOAD_FONT7  // Font 7. 7 segment 48 pixel font, needs ~2438 bytes in FLASH, only characters 1234567890:-.
#define LOAD_FONT8  // Font 8. Large 75 pixel font needs ~3256 bytes in FLASH, only characters 1234567890:-.
//#define LOAD_FONT8N // Font 8. Alternative to Font 8 above, slightly narrower, so 3 digits fit a 160 pixel TFT
#define LOAD_GFXFF  // FreeFonts. Include access to the 48 Adafruit_GFX free fonts FF1 to FF48 and custom fonts
#define SMOOTH_FONT
#define SPI_FREQUENCY  27000000
// #define SPI_FREQUENCY  40000000
#define SPI_READ_FREQUENCY  20000000
#define SPI_TOUCH_FREQUENCY  2500000
#define USE_HSPI_PORT
#define SUPPORT_TRANSACTIONS

This is the abridged version; I would recommend reading the original file as it includes a lot of hints for troubleshooting problems.


Software

This sketch simply detects when the display has been touched, takes a selection of samples and draws a pixel at the mean-average point. The sketch also draws a bounding rectangle to evidence the display as working.

#include <SPI.h>
#include <TFT_eSPI.h>

TFT_eSPI tft = TFT_eSPI();

uint16_t x, y;
int averageX = 0;
int averageY = 0;

void setup() {
  Serial.begin(115200);
  tft.init();
  tft.setRotation(1);
  tft.fillScreen(TFT_BLACK);
  tft.setTextColor(TFT_WHITE, TFT_BLACK);
  tft.drawRect(10, 10, 300, 220, TFT_WHITE);
}

void loop() {
  if (tft.getTouchRawZ() > 500) {
    getAverageReading(15);
    printPixel();
  }
}

void getAverageReading(int readings) {
  unsigned int cumulativeX = 0;
  unsigned int cumulativeY = 0;
  for (int i = 0; i < readings; i++) {
    tft.getTouchRaw(&x, &y);
    cumulativeX = cumulativeX + x;
    cumulativeY = cumulativeY + y;
    delay(1);
  }
  averageX = (cumulativeX / readings);
  averageY = (cumulativeY / readings);
  Serial.print("Average X value: "); Serial.println(averageX);
  Serial.print("Average Y value: "); Serial.println(averageY);
}

void printPixel() {
  int mapX = map(averageY, 3644, 685, 10, 310);
  int mapY = map(averageX, 3321, 270, 10, 230);
  tft.drawPixel(mapX, mapY, TFT_WHITE);
}

The accuracy of the touch screen is a bit shit to be honest. We’ve been spoilt by the sheer quality of the capacitive touch screens on mobile phones. There is also no support for multi-touch.

That being said; the accuracy of the touch display is better if you use 3.3V instead of 5V.


Page created: 09/07/2024
Page last edited: 28/01/2025