ILI9341/FT6336U/SD on ESP32S3/MicroPython

Exercise of MicroPython v1.24.1 running on ESP32-S3-DevKitC-1, display on 3.2" 320x240 IPS LCD (ILI9341 SPI) with Cap. Touch (FT6336U) and Micro SD Slot. In the exercises, all the three parts of the display module have been tested: ILI9341 SPI LCD, FT6336U cap. touch, and MicroSD card slot.



Connection:

			ESP32-S3-DevKitC-1	ILI9341 SPI display module
			+-----USB--UART-----+
			|GND	        GND |   GND
			|GND	        5V0 |
			|IO19		IO14|	LCD_CS
			|IO20		IO13|	LCD_RST
			|IO21		IO12|	LCD_RS
			|IO47		IO11|	SDI(MOSI)
			|IO48		IO10|	SCK
			|IO45		IO9 |	LED
			|IO0		IO46|
			|IO35		IO3 |	
			|IO36		IO8 |	SDO(MISO)
			|IO37		IO18|	SD_CS
			|IO38		IO17|	
			|IO39		IO16|	
			|IO40		IO15|
			|IO41		IO7 |	CTP_SCL
			|IO42		IO6 |	CTP_RST
			|IO2		IO5 |	CTP_SDA
			|IO1		IO4 |	CTP_INT
			|IO44		RST | 
			|IO43		3V3 |
			|GND		3V3 |	VCC
			+-------------------+
		

Libraries:

In the exercise, we need libraries of:
- rdagger/micropython-ili9341 (ili9341.py, xglcd_font.py and Unispace12x24.c)
micropython-lib/sdcard.py (can be installed in Thonny's Manager packages...)
lbuque/micropython-ft6x36

Exercise Code:

mpy_s3_ili9341_color.py
"""
ESP32-S3-DevKitC-1 running MicroPython v1.24.1
3.2" 320x240 IPS LCD (ILI9341 SPI) with Cap. Touch (FT6336) and Micro SD Slot
Colot test

Libraries needed, copy to /lib:
- ili9341.py
- xglcd_font.py
Font file need: copy to /fonts
- Unispace12x24.c

rdagger/micropython-ili9341
https://github.com/rdagger/micropython-ili9341
"""
import os, sys
import machine
from time import sleep, ticks_ms
from machine import Pin, SPI

from ili9341 import Display, color565
from xglcd_font import XglcdFont

print("====================================")
print(sys.implementation[0], os.uname()[3],
      "\nrun on", os.uname()[4])
print("====================================")

colors = [
    ("RED", (255, 0, 0)),
    ("GREEN", (0, 255, 0)),
    ("BLUE", (0, 0, 255))]

LCD_CS=14  # low to select
LCD_RST=13
LCD_RS=12
LCD_SDI=11 #MOSI
LCD_SCK=10
LCD_LED=9
LCD_SDO=8  #MISO

SD_CS=18   # low to select

# un-select both LCD and SD in power-up,
# to prevent un-used cs unstable and false selected.
pin_cs_lcd = Pin(LCD_CS, Pin.OUT)
pin_cs_lcd.value(1)
pin_cs_sd = Pin(SD_CS, Pin.OUT)
pin_cs_sd.value(1)

# off backlight at power-up
pin_backlight=Pin(LCD_LED, Pin.OUT)
pin_backlight.value(0)

# rot and rot_set
# are used to better manager rotation/width/height of display
rot=1   # 0 rotation = 0
        # 1 rotation = 90
        # 2 rotation = 180
        # 3 rotation = 270
# rot_set[x][0] : ili9341 Display rotation
# rot_set[x][1] : ili9341 Display width
# rot_set[x][2] : ili9341 Display height
rot_set = [[0, 240, 320],
           [90, 320, 240],
           [180, 240, 320],
           [270, 320, 240]]

spi = SPI(1, baudrate=40000000, sck=LCD_SCK, mosi=LCD_SDI, miso=LCD_SDO)
#display = Display(spi, dc=Pin(LCD_RS), cs=Pin(LCD_CS), rst=Pin(LCD_RST))
display = Display(spi,
                  rotation=rot_set[rot][0],
                  width=rot_set[rot][1], height=rot_set[rot][2],
                  dc=Pin(LCD_RS), cs=Pin(LCD_CS), rst=Pin(LCD_RST))
display.invert(enable=True)
pin_backlight.value(1)    # turn on backlight

print("Display:", display.width, "x", display.height)

print('Clearing to black...')
display.clear()
sleep(0.5)

print('Clearing to white...')
display.clear(color=color565(255, 255, 255))
sleep(0.5)

print('Clearing to black...')
display.clear()
sleep(0.5)

font_Unispace12x24 = XglcdFont('fonts/Unispace12x24.c', 12, 24)

# draw a rectangle show the boundary of the screen
display.draw_rectangle(0, 0, display.width, display.height, color565(255, 255, 255))
#draw a small circle on upper-left corner
display.draw_circle(10, 10, 10, color565(255, 255, 0))

# Color test
if display.width >= display.height:
    r = int(display.height*0.9/2)
else:
    r = int(display.width*0.9/2)
cx = display.width//2
cy = display.height//2

for color_name, rgb_value in colors:
    print(f"{color_name}: {rgb_value}")

    display.fill_circle(cx, cy,
                        r,
                        color565(*rgb_value))
    display.draw_text(cx, cy,
                      text=color_name,
                      font=font_Unispace12x24,
                      color=color565(rgb_value[0] ^ 0b11111111,
                                     rgb_value[1] ^ 0b11111111,
                                     rgb_value[2] ^ 0b11111111),
                      background=color565(*rgb_value)
                      )
    sleep(3)

print("~ bye ~")


mpy_s3_ili9341_sd_share_spi.py
"""
ESP32-S3-DevKitC-1 running MicroPython v1.24.1
3.2" 320x240 IPS LCD (ILI9341 SPI) with Cap. Touch (FT6336) and Micro SD Slot
ili9341 LCD and SD share the same SPI.
Read a text file (hello.txt) from SD, and display the content on LCD.

Libraries needed, install to /lib:
- ili9341.py
- xglcd_font.py
- sdcard (remark: NOT machine.SDCard)
Font file need: copy to /fonts
- Unispace12x24.c

ili9341.py, xglcd_font.py and Unispace12x24.c download from:
rdagger/micropython-ili9341
https://github.com/rdagger/micropython-ili9341

micropython-lib/sdcard.py can be download from
https://github.com/micropython/micropython-lib/blob/master/micropython/drivers/storage/sdcard/sdcard.py
or using Thonny > Tools > Manager Package...
"""
import os, sys
import machine
from time import sleep, ticks_ms
from machine import Pin, SPI
import sdcard

from ili9341 import Display, color565
from xglcd_font import XglcdFont

print("====================================")
print(sys.implementation[0], os.uname()[3],
      "\nrun on", os.uname()[4])
print("====================================")

colors = [
    ("RED", (255, 0, 0)),
    ("GREEN", (0, 255, 0)),
    ("BLUE", (0, 0, 255))]

LCD_CS=14  # low to select
LCD_RST=13
LCD_RS=12
LCD_SDI=11 #MOSI
LCD_SCK=10
LCD_LED=9
LCD_SDO=8  #MISO

SD_CS=18   # low to select

# un-select both LCD and SD in power-up,
# to prevent un-used cs unstable and false selected.
pin_cs_lcd = Pin(LCD_CS, Pin.OUT)
pin_cs_lcd.value(1)
pin_cs_sd = Pin(SD_CS, Pin.OUT)
pin_cs_sd.value(1)

pin_backlight=Pin(LCD_LED, Pin.OUT)
pin_backlight.value(0)

# rot and rot_set
# are used to better manager rotation/width/height of display
rot=1   # 0 rotation = 0
        # 1 rotation = 90
        # 2 rotation = 180
        # 3 rotation = 270
# rot_set[x][0] : ili9341 Display rotation
# rot_set[x][1] : ili9341 Display width
# rot_set[x][2] : ili9341 Display height
rot_set = [[0, 240, 320],
           [90, 320, 240],
           [180, 240, 320],
           [270, 320, 240]]

# spi share by LCD and SD
spi = SPI(1, baudrate=40000000, sck=LCD_SCK, mosi=LCD_SDI, miso=LCD_SDO)

display = Display(spi,
                  rotation=rot_set[rot][0],
                  width=rot_set[rot][1], height=rot_set[rot][2],
                  dc=Pin(LCD_RS), cs=Pin(LCD_CS), rst=Pin(LCD_RST))
display.invert(enable=True)

# remark:
# It's sdcard.SDCard
# NOT machine.SDCard
sd = sdcard.SDCard(spi, Pin(SD_CS))

vfs = os.VfsFat(sd)
os.mount(vfs, "/sd")

pin_backlight.value(1)

print(display.rotation, ":", display.width, "x", display.height)

print('Clearing to black...')
display.clear()
sleep(0.5)

font_Unispace12x24 = XglcdFont('fonts/Unispace12x24.c', 12, 24)

# draw a rectangle show the boundary of the screen
display.draw_rectangle(0, 0, display.width, display.height, color565(255, 255, 255))

# Color test
if display.width >= display.height:
    r = int(display.height*0.9/2)
else:
    r = int(display.width*0.9/2)
cx = display.width//2
cy = display.height//2

for color_name, rgb_value in colors:
    print(f"{color_name}: {rgb_value}")

    display.fill_circle(cx, cy,
                        r,
                        color565(*rgb_value))
    display.draw_text(cx, cy,
                      text=color_name,
                      font=font_Unispace12x24,
                      color=color565(rgb_value[0] ^ 0b11111111,
                                     rgb_value[1] ^ 0b11111111,
                                     rgb_value[2] ^ 0b11111111),
                      background=color565(*rgb_value)
                      )
    sleep(0.5)

# read SD and draw on display
def readHello():
    print(os.listdir("/sd"))
    with open("/sd/hello.txt", "r") as f:
        y=0
        for line in f:
            line_strip = line.strip()
            print(line_strip)
            display.draw_text(0, y,
                          text=line_strip,
                          font=font_Unispace12x24,
                          color=color565(255, 255, 255)
                          )
            y=y+25
            
readHello()

print("~ bye ~")


mpy_s3_ili9341_ft6336u.py
"""
ESP32-S3-DevKitC-1 running MicroPython v1.24.1
3.2" 320x240 IPS LCD (ILI9341 SPI) with Cap. Touch (FT6336) and Micro SD Slot
ili9341 LCD and FT6336U cap touch

Libraries needed, install to /lib:
- ili9341.py
- xglcd_font.py
- ft6x36.py
Font file need: copy to /fonts
- Unispace12x24.c

ili9341.py, xglcd_font.py and Unispace12x24.c download from:
rdagger/micropython-ili9341
https://github.com/rdagger/micropython-ili9341

lbuque/micropython-ft6x36
https://github.com/lbuque/micropython-ft6x36

"""
import os, sys
import machine
from time import sleep, ticks_ms
from machine import Pin, SPI, I2C
import sdcard

from ili9341 import Display, color565
from xglcd_font import XglcdFont

from ft6x36 import FT6x36

print("====================================")
print(sys.implementation[0], os.uname()[3],
      "\nrun on", os.uname()[4])
print("====================================")

LCD_CS=14  # low to select
LCD_RST=13
LCD_RS=12
LCD_SDI=11 # MOSI
LCD_SCK=10
LCD_LED=9
LCD_SDO=8  # MISO

CTP_SCL=7
CTP_RST=6
CTP_SDA=5
CTP_INT=4  #Not used

SD_CS=18   # low to select

# un-select both LCD and SD in power-up,
# to prevent un-used cs unstable and false selected.
pin_cs_lcd = Pin(LCD_CS, Pin.OUT)
pin_cs_lcd.value(1)
pin_cs_sd = Pin(SD_CS, Pin.OUT)
pin_cs_sd.value(1)

# Turn off backlight at power-up
pin_backlight=Pin(LCD_LED, Pin.OUT)
pin_backlight.value(0)

# output a negative pulse to CTP_RST pin, to reset FT6336U
pin_CTP_RST=Pin(CTP_RST, Pin.OUT)
pin_CTP_RST.value(1)
sleep(0.1)
pin_CTP_RST.value(0)
sleep(0.1)
pin_CTP_RST.value(1)
sleep(0.1)

# rot and rot_set
# are used to better manager rotation/width/height of display and touch
rot=3   # 0 rotation = 0
        # 1 rotation = 90
        # 2 rotation = 180
        # 3 rotation = 270
# rot_set[x][0] : ili9341 Display rotation
# rot_set[x][1] : ili9341 Display width
# rot_set[x][2] : ili9341 Display height
# rot_set[x][3] : ft6336U Touch rotation
# rot_set[x][4] : ft6336U Touch width
# rot_set[x][5] : ft6336U Touch height
rot_set = [[0, 240, 320, FT6x36.PORTRAIT_INVERTED, 240, 320],
           [90, 320, 240, FT6x36.LANDSCAPE_INVERTED, 240, 320],
           [180, 240, 320, FT6x36.PORTRAIT, 240, 320],
           [270, 320, 240, FT6x36.LANDSCAPE, 240, 320]]

# spi
spi = SPI(1, baudrate=40000000, sck=LCD_SCK, mosi=LCD_SDI, miso=LCD_SDO)
display = Display(spi,
                  rotation=rot_set[rot][0],
                  width=rot_set[rot][1], height=rot_set[rot][2],
                  dc=Pin(LCD_RS), cs=Pin(LCD_CS), rst=Pin(LCD_RST))
display.invert(enable=True)
pin_backlight.value(1)
print("Display:", display.width, "x", display.height)
display.clear()

# i2c
i2c = I2C(0, scl=Pin(CTP_SCL), sda=Pin(CTP_SDA))
print("i2c", i2c)
print("I2C Scan:", i2c.scan())
touch = FT6x36(i2c,
               width=rot_set[rot][4],
               height=rot_set[rot][5],
               rotation=rot_set[rot][3],)
print("Touch:", touch._width, "x", touch._height)

font_Unispace12x24 = XglcdFont('fonts/Unispace12x24.c', 12, 24)

# draw a rectangle show the boundary of the screen
display.draw_rectangle(0, 0, display.width, display.height, color565(255, 255, 255))
display.draw_text(10, 10,
                  text="FT6336U Touch test",
                  font=font_Unispace12x24,
                  color=color565(255, 255, 255)
                  )

cleared = True
last_xy = []
while True:
    p = touch.get_positions()
    if len(p) > 0:
        print(p)
        x = p[0][0]
        y = p[0][1]
        display.fill_circle(x, y, 3, color565(255, 255, 0))
        cleared = False
        
        if last_xy:
            display.draw_line(last_xy[0], last_xy[1],
                              x, y,
                              color565(255, 255, 255))
        last_xy = [x, y]

    else:
        if not cleared:
            display.clear()
            cleared = True
            last_xy = []
    sleep(0.1)

print("~ bye ~")


Remark:
The MicroPython firmware used in the above video is in-correct, but not affected in this exercises. For ESP32-S3-DevKitC-1 with Octal SPI flash/PSRAM memory, use the "spiram-oct" variant such as ESP32_GENERIC_S3-SPIRAM_OCT-20241129-v1.24.1.bin. It will be fixed in next exercise.

next:

Comments

Popular posts from this blog

480x320 TFT/ILI9488 SPI wih EP32C3 (arduino-esp32) using Arduino_GFX Library

Drive 320x240 ILI9341 SPI TFT using ESP32-S3 (NodeMCU ESP-S3-12K-Kit) using TFT_eSPI library, in Arduino Framework.