ILI9488 SPI LCD on Raspberry Pi/Python using Luma.LCD

Luma.LCD provides a Python3 interface to small LCD displays connected to Raspberry Pi and other Linux-based single-board computers (SBC). It provides a Pillow-compatible drawing canvas, and other functionality.

This exercises tested on Raspberry Pi 4/64-bit Raspberry Pi OS (bookworm) using Python3 + Luma.LCD to driver 3.5 inch 480x320 ILI9488 SPI LCD.


Connection:

Follows the suggested wiring for ILI9488 in Luma.LCD docs.

Enable SPI Interface:

Make sure SPI is enabled in Raspberry Pi using raspi-config.
(https://luma-lcd.readthedocs.io/en/latest/hardware.html#enabling-the-spi-interface)
sudo raspi-config

Create Python virtual environment Install luma.lcd:

Create Python virtual environment to include site packages:
python -m venv --system-site-packages envPy_luma

Activate the virtual environment:
source envPy_luma/bin/activate

install the latest version of the library in the virtual environment with:
pip install --upgrade luma.lcd
Exit virtual environment after used:
deactivate

In Thonny, configure interpreter to select the Python executable in the new virtual environment.

Exercise Code:

luma_ili9488.py, Hello World with color/pwm backlight test.
"""
3.5 inch 480x320 TFT with SPI ILI9488
on Raspberry Pi 4B using Python/luma.lcd
Hello World with color/pwm backlight test.
"""

from luma.core.interface.serial import spi
from luma.core.render import canvas
from luma.lcd.device import ili9488
from PIL import ImageFont
import time

serial = spi(port=0, device=0, gpio_DC=23, gpio_RST=24)
device = ili9488(serial, rotate=2,
                 gpio_LIGHT=18, active_low=False) # BACKLIGHT PIN = GPIO 18, active High)

font_FreeMonoBold_30 = ImageFont.truetype("/usr/share/fonts/truetype/freefont/FreeMonoBold.ttf", 30)
font_FreeSansBold_20 = ImageFont.truetype("/usr/share/fonts/truetype/freefont/FreeSansBold.ttf", 20)
font_FreeSerifBoldItalic_30 = ImageFont.truetype("/usr/share/fonts/truetype/freefont/FreeSerifBoldItalic.ttf", 30)

device.backlight(True) # Turn on backlight using luma device.backlight()

with canvas(device) as draw:
    draw.rectangle(device.bounding_box, outline="white", fill="black")
    draw.text((30, 40), "Hello World", font=font_FreeSerifBoldItalic_30, fill="white")

time.sleep(3)
with canvas(device) as draw:
    draw.rectangle(device.bounding_box, outline="white", fill="red")
    draw.text((30, 40), "red", font=font_FreeMonoBold_30, fill="white")

time.sleep(3)
with canvas(device) as draw:
    draw.rectangle(device.bounding_box, outline="white", fill="green")
    draw.text((30, 40), "green", font=font_FreeMonoBold_30, fill="white")
    
time.sleep(3)
with canvas(device) as draw:
    draw.rectangle(device.bounding_box, outline="white", fill="blue")
    draw.text((30, 40), "blue", font=font_FreeMonoBold_30, fill="white")

time.sleep(3)
with canvas(device) as draw:
    draw.rectangle(device.bounding_box, outline="white", fill="black")
    draw.text((10, 40), "Test backlight using GPIO.PWM", font=font_FreeMonoBold_30, fill="white")
    
#=== Test control BACKLIGHT_PIN using GPIO.PWM ===
import RPi.GPIO as GPIO

BACKLIGHT_PIN = 18

#GPIO.setmode(GPIO.BCM)
#GPIO.setup(BACKLIGHT_PIN, GPIO.OUT)

pwm = GPIO.PWM(BACKLIGHT_PIN, 1000)
pwm.start(0)

def fade_in():
    for duty_cycle in range(0, 101, 1):
        pwm.ChangeDutyCycle(duty_cycle)
        time.sleep(0.01)

def fade_out():
    for duty_cycle in range(100, -1, -1):
        pwm.ChangeDutyCycle(duty_cycle)
        time.sleep(0.01)

while True:
    fade_in()
    time.sleep(1)
    fade_out()
    time.sleep(1)

pwm.stop()
GPIO.cleanup()

luma_ili9488_image_show.py, show a single image.
"""
3.5 inch 480x320 TFT with SPI ILI9488
on Raspberry Pi 4B using Python/luma.lcd
Show image.
"""

from luma.core.interface.serial import spi
from luma.core.render import canvas
from luma.lcd.device import ili9488
from PIL import Image, ImageOps

serial = spi(port=0, device=0, gpio_DC=23, gpio_RST=24)
device = ili9488(serial, rotate=2,
                 gpio_LIGHT=18, active_low=False) # BACKLIGHT PIN = GPIO 18, active High

device.backlight(True)

ImagePath = "/home/pi/myImages/images/img_002.jpg"

image = Image.open(ImagePath)
print("Open image:", ImagePath)
img_resized = image.resize((426, 320), Image.LANCZOS)
img_expanded = ImageOps.expand(img_resized, border=(27, 0), fill='black')

device.display(img_expanded)

luma_ili9488_image_slideshow.py, show images in Slideshow.
"""
3.5 inch 480x320 TFT with SPI ILI9488
on Raspberry Pi 4B using Python/luma.lcd
Show images in Slideshow.
"""

from luma.core.interface.serial import spi
from luma.core.render import canvas
from luma.lcd.device import ili9488
from PIL import Image, ImageOps
import os
import time

serial = spi(port=0, device=0, gpio_DC=23, gpio_RST=24, spi_speed_hz=32000000)

device = ili9488(serial, rotate=2,
                 gpio_LIGHT=18, active_low=False) # BACKLIGHT PIN = GPIO 18, active High

device.backlight(True)

# Because the image source is 1024x768
# and the LCD display is 480x320
# so resize 1024x768 to 426x320
# expand to 480x320, with border of 27 pixel, (480-426)/2 = 27.
def showImage(image_source):
    image = Image.open(image_source)
    print("Open image:", image_source)
    img_resized = image.resize((426, 320), Image.LANCZOS)
    img_expanded = ImageOps.expand(img_resized, border=(27, 0), fill='black')

    device.display(img_expanded)
    

images_folder = "/home/pi/myImages/images"
files = os.listdir(images_folder)
jpg_files = [file for file in files if file.endswith('.jpg')]
jpg_file_list = sorted(jpg_files)

print("=== Start ===")
print("# of file:", len(jpg_file_list))

while True:
    for i in range(0, len(jpg_file_list)):
        ImagePath = os.path.join(images_folder, jpg_file_list[i])
        showImage(ImagePath)
        
        time.sleep(3)

luma_ili9488_image_slideshow_fade.py, show images in Slideshow with fade-in/fade-out.
"""
3.5 inch 480x320 TFT with SPI ILI9488
on Raspberry Pi 4B using Python/luma.lcd
Show images in Slideshow, with fade-in/fade-out.
"""

from luma.core.interface.serial import spi
from luma.core.render import canvas
from luma.lcd.device import ili9488
from PIL import Image, ImageOps
import os
import time
import RPi.GPIO as GPIO

serial = spi(port=0, device=0, gpio_DC=23, gpio_RST=24, spi_speed_hz=32000000)

device = ili9488(serial, rotate=2,
                 gpio_LIGHT=18, active_low=False) # BACKLIGHT PIN = GPIO 18, active High

device.backlight(False) # Turn OFF backlight first

BACKLIGHT_PIN = 18

#GPIO.setmode(GPIO.BCM)
#GPIO.setup(BACKLIGHT_PIN, GPIO.OUT)
pwm = GPIO.PWM(BACKLIGHT_PIN, 1000)
pwm.start(0)

def fade_in():
    for duty_cycle in range(0, 101, 1):
        pwm.ChangeDutyCycle(duty_cycle)
        time.sleep(0.01)

def fade_out():
    for duty_cycle in range(100, -1, -1):
        pwm.ChangeDutyCycle(duty_cycle)
        time.sleep(0.01)

# Because the image source is 1024x768
# and the LCD display is 480x320
# so resize 1024x768 to 426x320
# expand to 480x320, with border of 27 pixel, (480-426)/2 = 27.
def showImage(image_source):
    image = Image.open(image_source)
    print("Open image:", image_source)
    img_resized = image.resize((426, 320), Image.LANCZOS)
    img_expanded = ImageOps.expand(img_resized, border=(27, 0), fill='black')

    device.display(img_expanded)

images_folder = "/home/pi/myImages/images"
files = os.listdir(images_folder)
jpg_files = [file for file in files if file.endswith('.jpg')]
jpg_file_list = sorted(jpg_files)

print("=== Start ===")
print("# of file:", len(jpg_file_list))

while True:
    for i in range(0, len(jpg_file_list)):
        ImagePath = os.path.join(images_folder, jpg_file_list[i])
        showImage(ImagePath)
        
        fade_in()
        time.sleep(3)
        fade_out()


Comments

Popular posts from this blog

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

my dev.tools - FNIRSI 2C23T 3-in-1 Dual Channel Oscilloscope/Multimeter/Signal Generator