SPI TFT and XPT2046 touch screen controller driver for esp-idf.
ESP-IDF V5.0 or later.
ESP-IDF V4.4 release branch reached EOL in July 2024.
Note for ESP32-C6
ESP-IDF V5.1 is required when using ESP32-C6.
git clone https://github.com/nopnop2002/esp-idf-ili9340
cd esp-idf-ili9340/
idf.py set-target {esp32/esp32s2/esp32s3/esp32c2/esp32c3/esp32c6}
idf.py menuconfig
idf.py flash
Note for ESP32-S2/ESP32-C2
The tjpgd library is not included in the ESP32-S2/ESP32-C2 ROM.
However, you can use this IDF component registry.
JPEG files can be displayed.
Note for ESP32-C2
ESP32-C2 has less SRAM, so JPEG and PNG may not be displayed on higher resolution TFTs.
E (256560) decode_jpeg: Error allocating memory for line 251
E (260630) pngle_new: Error allocating memory for line 160
Note for ESP32-S2
ESP32-S2 has less SRAM, but some ESP32-S2 have PSRAM.
If your SoC has PSRAM, you can avoid running out of memory by enabling PSRAM.
You have to set this config value with menuconfig.
- CONFIG_WIDTH
- CONFIG_HEIGHT
- CONFIG_OFFSETX
- CONFIG_OFFSETY
- CONFIG_MOSI_GPIO
- CONFIG_SCLK_GPIO
- CONFIG_CS_GPIO
- CONFIG_DC_GPIO
- CONFIG_RESET_GPIO
- CONFIG_BL_GPIO
GPIO of ESP32 cannot supply too much current.
TFT backlight becomes brighter when powered by an external power source.
TFT MISO is not use.
- M5Stack
- Shenzhen Jingcal Intelligent 3.5" ST7796 320x480 (ESP32-3248S035)
- Shenzhen Jingcal Intelligent 2.8" ILI9341 240x320 (ESP32-2432S028R)
- 4.0" ST7796 320x480
- 3.2" ILI9341 240x320
- 2.8" ILI9341 240x320
- 2.8" ST7789 240x320
- 2.4" ILI9341 240x320
- 2.4" ST7789 240x320
- 2.2" ILI9340 240x320
- 2.0" ILI9225 176x220
- 1.8" ST7735 128x160
- 1.77" ST7735 128x160
- 1.44" ST7735 128x128
- 0.96" ST7735 80x160
A note about RESET
Pull Up of the RESET pin may be required. I inserted a 100 ohm resistor between Vcc and RESET.
ESP32-2432S032/ESP32-4827S043/ESP32-8048S043 doesn't work because it's an RGB panel, not SPI.
JPEG file(Cannot be displayed on ESP32S2)
Vendor part number is ESP32-3248S035.
Vendor part number is ESP32-2432S028R.
GRAM Offset may be different
The ESP-IDF component includes Tiny JPEG Decompressor.
The document of Tiny JPEG Decompressor is here.
This can reduce the image to 1/2 1/4 1/8.
The ESP-IDF component includes part of the miniz library, such as mz_crc32.
But it doesn't support all of the miniz.
The document of miniz library is here.
And I ported the pngle library from here.
This can reduce the image to any size.
This project uses the following as default fonts:
- font/ILGH16XB.FNT // 8x16Dot Gothic
- font/ILGH24XB.FNT // 12x24Dot Gothic
- font/ILGH32XB.FNT // 16x32Dot Gothic
- font/ILMH16XB.FNT // 8x16Dot Mincyo
- font/ILMH24XB.FNT // 12x24Dot Mincyo
- font/ILMH32XB.FNT // 16x32Dot Mincyo
From 0x00 to 0x7f, the characters image of Alphanumeric are stored.
From 0x80 to 0xff, the characters image of Japanese are stored.
Changing this file will change the font.
You can add your original fonts.
The format of the font file is the FONTX format.
Your font file is put in font directory.
Your font file is uploaded to SPIFFS partition using meke flash.
Please refer this page about FONTX format.
There is a font file editor.
This can be done on Windows 10.
Developer page is here.
step1)
download Font File Editor(FONTX Editor) from here.
step2)
download BDF font file from Internet.
I downloaded from here.
fontxedit.exe can ONLY import Monospaced bitmap fonts file.
Monospaced bitmap fonts can also be downloaded here.
step3)
import the BDF font file into your fontxedit.exe.
this tool can convert from BDF to FONTX.
step5)
check font pattern.
when you have made any changes, press the apply button.
step6)
save as .fnt file from your fontedit.exe.
step7)
upload your font file to $HOME/esp-idf-ili9340/font directory.
step8)
add font to use
FontxFile fx32L[2];
InitFontx(fx32L,"/spiffs/LATIN32B.FNT",""); // 16x32Dot LATIN
Font file that From 0x00 to 0x7f, the characters image of Standard ASCII are stored.
Font file that From 0x80 to 0xff, the characters image of Japanese are stored.
Font file that From 0x80 to 0xff, the characters image of Latin are stored.
u8g2 library contains many BDF fonts.
This is a 24x24 font converted from emoticons21.bdf.
This is a 16x16 font converted from Scroll-o-Sprites.bdf.
step1)
Download WFONTX64.exe from here.
Developer page is here.
step2)
Select ttf font.
Please note that if you select a proportional font, some fonts may not convert correctly.
If you select a proportional font, some fonts will need to be modified using fontxedit.exe.
Monospaced fonts can be converted correctly.
You can find Monospaced fonts here.
step3)
Enter Height, Width, FontX2 name.
Specify half of Height for Width.
Specify your favorite font name in the FontX2 name field using up to 8 characters.
step4)
Specify the file name to save.
step5)
Specify the font style as required.
step6)
Press the RUN button to convert TTF fonts to FONTX format.
step7)
upload your font file to $HOME/esp-idf-ili9340/font directory.
step8)
add font to use
FontxFile fx16G[2];
FontxFile fx24G[2];
FontxFile fx32G[2];
//InitFontx(fx16G,"/spiffs/ILGH16XB.FNT",""); // 8x16Dot Gothic
//InitFontx(fx24G,"/spiffs/ILGH24XB.FNT",""); // 12x24Dot Gothic
//InitFontx(fx32G,"/spiffs/ILGH32XB.FNT",""); // 16x32Dot Gothic
InitFontx(fx16G,"/spiffs/Gigi16.FNT",""); // 8x16Dot Gigi
InitFontx(fx24G,"/spiffs/Gigi24.FNT",""); // 12x24Dot Gigi
InitFontx(fx32G,"/spiffs/Gigi32.FNT",""); // 16x32Dot Gigi
Change here.
#define RED rgb565(255, 0, 0) // 0xf800
#define GREEN rgb565( 0, 255, 0) // 0x07e0
#define BLUE rgb565( 0, 0, 255) // 0x001f
#define BLACK rgb565( 0, 0, 0) // 0x0000
#define WHITE rgb565(255, 255, 255) // 0xffff
#define GRAY rgb565(128, 128, 128) // 0x8410
#define YELLOW rgb565(255, 255, 0) // 0xFFE0
#define CYAN rgb565( 0, 156, 209) // 0x04FA
#define PURPLE rgb565(128, 0, 128) // 0x8010
A library of XPT2046 Touch Screen is included in this project.
There is a TFT equipped with XPT2046.
XPT2046 shares the TFT and SPI bus.
Use the menu to enable XPT2046.
- Touch position accuacy
The coordinates read from XPT2046 are physical coordinates.
Physical coordinates are converted to logical coordinates.
Then draw using logical coordinates.
In TouchPenTest, when you touch the screen, a circle is drawn at the touched position, but if you touch the same position as the previous time, it is not drawn.
This value is the threshold that determines whether the touch location is the same as the previous touch location.
Decreasing this value will make the position more accurate, but less responsive.
Increasing this value will make the position more inaccurate but more responsive.
There is a TFT equipped with HR2046.
XPT2046 and HR2046 are very similar. But HR2046 does not work properly.
TFT | ESP32 | ESP32-S2/S3 | ESP32-C2/C3 | ||
---|---|---|---|---|---|
VCC | -- | 3.3V | 3.3V | 3V3 | |
GND | -- | GND | GND | GND | |
CS | -- | GPIO14 | GPIO34 | GPIO2 | |
RES | -- | GPIO33 | GPIO41 | GPIO4 | (*1) |
D/C | -- | GPIO27 | GPIO40 | GPIO3 | (*1) |
MOSI | -- | GPIO23 | GPIO35 | GPIO0 | (*1) (*2) |
SCK | -- | GPIO18 | GPIO36 | GPIO1 | (*1) (*2) |
LED | -- | 3.3V | 3.3V | 3.3V | (*1) (*3) |
MISO | -- | N/C | N/C | N/C | |
T_CLK | -- | GPIO18 | GPIO36 | GPIO1 | (*1) (*2) |
T_CS | -- | GPIO21 | GPIO38 | GPIO7 | (*1) (*4) |
T_DIN | -- | GPIO23 | GPIO35 | GPIO0 | (*1) (*2) |
T_OUT | -- | GPIO19 | GPIO37 | GPIO6 | (*1) (*4) |
T_IRQ | -- | GPIO22 | GPIO39 | GPIO8 | (*1) (*4) |
(*1) You can change it to any gpio using menuconfig. But some gpio's are input only.
(*2) These are shared by TFT and XPT2046.
(*3) It can be controlled using gpio. However, GPIO of ESP32 cannot supply too much current. TFT backlight becomes brighter when powered by an external power source.
(*4) I found that there are limits to the GPIOs that can be used as touch panel controls.
You can check if XPT2046 works properly.
If you touch it at this time, the touched coordinates will be displayed.
If there is no touch for 10 seconds, it will end.
Move the touch-pen vertically and horizontally to check the X and Y coordinates.
What you get here is the physical coordinates.
See here about physical coordinates.
This module also has an XPT2046.
XPT2046 uses the same SPI bus as TFT.
XPT2046's SCLK and MOSI use the same GPIO as the TFT.
This module also has an XPT2046.
XPT2046 uses a different SPI bus than TFT.
XPT2046's SCLK and MOSI use separate GPIOs from the TFT.
If there is no touch for 10 seconds, it will end.
You can only enter up to 15 characters.
If there is no touch for 10 seconds, it will end.
If there is no touch for 10 seconds, it will end.
If there is no touch for 10 seconds, it will end.
If there is no touch for 10 seconds, it will end.
I borrowed the icon from here.
Write calibration data to NVS.
Read calibration data from NVS when starting the firmware and use it.
If you use the same TFT, you don't need to calibrate again.
To clear the calibration data recorded in NVS, execute the following command.
idf.py erase_flash
According to the datasheet, the minimum SPI clock cycles for each driver are as follows:
Maximum SPI clock frequency is the reciprocal of this.
Driver | minimum SPI clock cycle | maximum SPI clock frequency |
---|---|---|
ILI9225 | 100ns | 10MHz |
ILI9340 | 66ns | 15MHz |
ILI9341 | 100ns | 10MHz |
ST7735 | 66ns | 15MHz |
ST7796 | 66ns | 15MHz |
The SPI clock frequency used by this project is 10MHz.
Higher SPI clock frequencies can be specified using spi_clock_speed()
.
When using higher SPI clock frequencies, you need to be careful about the length of the wire cable.
int speed = 15000000; // 15MHz
spi_clock_speed(speed);
spi_master_init(&dev, CONFIG_MOSI_GPIO, CONFIG_SCLK_GPIO, CONFIG_TFT_CS_GPIO, CONFIG_DC_GPIO,
CONFIG_RESET_GPIO, CONFIG_BL_GPIO, XPT_MISO_GPIO, XPT_CS_GPIO, XPT_IRQ_GPIO, XPT_SCLK_GPIO, XPT_MOSI_GPIO);
lcdInit(&dev, model, CONFIG_WIDTH, CONFIG_HEIGHT, CONFIG_OFFSETX, CONFIG_OFFSETY);
The ESP32 series has three SPI BUSs.
SPI1_HOST is used for communication with Flash memory.
You can use SPI2_HOST and SPI3_HOST freely.
When you use SDSPI(SD Card via SPI), SDSPI uses SPI2_HOST BUS.
When using this module at the same time as SDSPI or other SPI device using SPI2_HOST, it needs to be changed to SPI3_HOST.
When you don't use SDSPI, both SPI2_HOST and SPI3_HOST will work.
Previously it was called HSPI_HOST / VSPI_HOST, but now it is called SPI2_HOST / SPI3_HOST.
When FrameBuffer is enabled, all output will be stored in the internal FrameBuffer and reflected to the device with lcdDrawFinish
.
If you don't use FrameBuffer, lcdDrawFinish
does nothing.
If your main purpose is to display text, it's well worth using FrameBuffer.
If your main purpose is to display images, there is no value in using FrameBuffer.
Enabling FrameBuffer does not make image display faster.
This is because image analysis takes time.
This option requires large RAM space.
If your SoC has PSRAM, you can avoid running out of memory by enabling PSRAM.
Benchmarking using ESP32-S2@240 & 2.4 inch TFT
Disable Frame Buffer | Enable Frame Buffer | |
---|---|---|
FillTest | 1390 | 1450 |
ColorBarTest | 150 | 160 |
ArrowTest | 330 | 160 |
LineTest | 2670 | 180 |
CircleTest | 2390 | 190 |
RoundRectTest | 2430 | 180 |
DirectionTest | 500 | 160 |
HorizontalTest | 1110 | 170 |
VerticalTest | 1100 | 180 |
FillRectTest | 300 | 180 |
ColorTest | 370 | 170 |
CodeTest | 1760 | 180 |
BMPTest | 3000 | 2810 |
JPEGTest | 2760 | 2760 |
PNGTest | 2940 | 2960 |
IconTest | 740 | 870 |
I purchased this adapter on AliExpress.
It comes with an ESP32 and costs $4.
However, this adapter's T_IRQ is not connected anywhere.
To use the touch panel, you need to add a jumper.
As a result, the GPIO will be:
TFT | ESP32 | ||
---|---|---|---|
VCC | -- | 3.3V | |
GND | -- | GND | |
CS | -- | GPIO15 | |
RES | -- | GPIO04 | |
D/C | -- | GPIO02 | |
MOSI | -- | GPIO23 | |
SCK | -- | GPIO18 | |
LED | -- | 3.3V | *1 |
MISO | -- | N/C | |
T_CLK | -- | GPIO18 | |
T_CS | -- | GPIO05 | |
T_DIN | -- | GPIO23 | |
T_OUT | -- | GPIO19 | |
T_IRQ | -- | GPIO21 |
(*1) BL_EN is directly connected to 3.3V, so it cannot control BackLight.
When not using the touch panel.
A TFT shield like this can be used with ESP-IDF.