1.54" 320x320 ST7796 SPI IPS on Waveshare ESP32-H2-Zero/CircuitPython 10.0.3

1.54" 320x320 ST7796 SPI IPS on Waveshare ESP32-H2-Zero/CircuitPython 10.0.3



Currently, no official ST7796 library for CircuitPython, so we have to implement my custom ST7796_INIT_SEQUENCE and busdisplay.BusDisplay().

cpy_H2Zero_st7796_320x320.py, simple color test.
"""
Waveshare ESP32-H2-Zero/CircuitPython
display on 1.54 inch 320x320 ST7796 SPI IPS

    320x320 ST7796 LCD      ESP32-H2-Zero
    -
    BL   -----+             +-----=======-----+
    3V3  ---+ |             |5V         GPIO24|
    GND  ---|-|-------------|GND        GPIO23|
            +-|-------------|3V3        GPIO25|
              +-------------|GPIO0      GPIO22|
    CS   -------------------|GPIO1      GPIO14|
    SCK  -------------------|GPIO2      GPIO13|
    DC   -------------------|GPIO3      GPIO12|
    MOSI -------------------|GPIO4      GPIO11|
                            |GPIO5      GPIO10|
                            +-----------------+

CircuitPython Libraries Bundle for Version 10.x needed:
(https://circuitpython.org/libraries)
- adafruit_display_text folder
"""
import os, sys, board, time
import busdisplay
import displayio
import busio
import fourwire
from adafruit_display_text import label
import terminalio

TFT_MOSI = board.IO4
TFT_DC   = board.IO3
TFT_SCK  = board.IO2
TFT_CS   = board.IO1
TFT_BL   = board.IO0

DISPLAY_width = 320
DISPLAY_height = 320

ST7796_INIT_SEQUENCE = (
    b"\x01\x80\x96"  # _SWRESET and Delay 150ms

    b"\x11\x80\x78"  # SLPOUT
    b"\x36\x01\x48"  # b"\x36\x01\x08"  # MADCTL
    b"\x3A\x01\x05"  #COLMOD
    b"\xF0\x01\xC3"  # CSCON enable command 2 part I
    b"\xF0\x01\x96"  # CSCON enable command 2 part II
    b"\xB4\x01\x01"  # DIC (Display Inversion Control) - 1 dot inversion
    b"\xB7\x01\xC6"  # EM (Entry mode Set)
    b"\xC0\x02\x80\x45"  # PWR1(Power Control 1)
    b"\xC1\x01\x13"  # PWR2(Power Control 2)
    b"\xC2\x01\xA7"  # PWR3(Power Control 3
    b"\xC5\x01\x0A"  # VCMPCTL (VCOM Control)
    b"\xE8\x08\x40\x8A\x00\x00\x29\x19\xA5\x33" # DOCA (Display Output Ctrl Adjust)
    b"\xE0\x0E\xD0\x08\x0F\x06\x06\x33\x30\x33\x47\x17\x13\x13\x2B\x31" # PGC (Positive Gamma Control)
    b"\xE1\x0E\xD0\x0A\x11\x0B\x09\x07\x2F\x33\x47\x38\x15\x16\x2C\x32" # NGC (Negative Gamma Control)
    b"\xF0\x01\x3C"     # CSCON disable command 2 part I
    b"\xF0\x81\x69\x78" # CSCON disable command 2 part II, then delay 120ms
    b"\x21\x00" # INVON (Display Inversion On)
    b"\x29\x00" # DISPON (Display On)
)

sys_info_text = sys.implementation[0] + " " + os.uname()[3] +\
                "\nrun on " + os.uname()[4] +\
                "\nusing " + busdisplay.BusDisplay.__name__
print("=========================================")
print(sys_info_text)
print("=========================================")

# === init LCD ===
# Release any resources currently in use for the displays
displayio.release_displays()

spi = busio.SPI(clock=TFT_SCK, MOSI=TFT_MOSI)

display_bus = fourwire.FourWire(spi_bus=spi,
                                command=TFT_DC,
                                chip_select=TFT_CS)

display = busdisplay.BusDisplay(display_bus,
                                ST7796_INIT_SEQUENCE,
                                width=DISPLAY_width,
                                height=DISPLAY_height,
                                backlight_pin=TFT_BL)

# Make the display context
bgGroup = displayio.Group()
display.root_group = bgGroup

bg_bitmap = displayio.Bitmap(display.width, display.height, 1)  # with one color
bg_palette = displayio.Palette(1)
bg_palette[0] = 0xA0A0A0  # light-gray
bg_sprite = displayio.TileGrid(bg_bitmap, pixel_shader=bg_palette, x=0, y=0)
bgGroup.append(bg_sprite)

color_bitmap = displayio.Bitmap(display.width-2, display.height-2, 1)  # with one color
color_palette = displayio.Palette(1)
color_palette[0] = 0x000000  # BLACK
color_sprite = displayio.TileGrid(color_bitmap, pixel_shader=color_palette, x=1, y=1)
bgGroup.append(color_sprite)

color_text_group = displayio.Group(scale=3, x=20, y=120)
color_text_area = label.Label(terminalio.FONT, text="", color=0xFFFFFF)
color_text_group.append(color_text_area)
bgGroup.append(color_text_group)

colorSet = ((0xFF0000, "RED"),
            (0x00FF00, "GREEN"),
            (0x0000FF, "BLUE"),
            (0xFFFFFF, "WHITE"),
            (0x000000, "BLACK"))

# Color Test
time.sleep(0.5)
for i in colorSet:
    time.sleep(2)
    color_palette[0] = i[0]
    color_text_area.text = i[1]
    color_text_area.color = i[0] ^ 0xFFFFFF

time.sleep(0.5)
bgGroup.remove(color_text_group)

# scrolling text
# ref:
# https://learn.adafruit.com/rgb-led-matrices-matrix-panels-with-circuitpython/example-simple-two-line-text-scroller
def scroll(line):
    line.x = line.x - 1
    line_width = line.bounding_box[2]
    if line.x < -line_width:
        line.x = display.width
        
def reverse_scroll(line):
    line.x = line.x + 1
    line_width = line.bounding_box[2]
    if line.x >= display.width:
        line.x = -line_width

# Scrolling text

sys_info_group = displayio.Group(scale=2, x=0, y=20)
sys_info_area = label.Label(terminalio.FONT, text=sys_info_text, color=0xFFFFFF)
sys_info_group.append(sys_info_area)
bgGroup.append(sys_info_group)

info1_text = "coXXect.blogspot.com"
info1_scale = 2
info1_area = label.Label(terminalio.FONT, text=info1_text, color=0xFFFF00)

# Measure text width
text_width = info1_area.bounding_box[2]  # bounding_box = (x, y, width, height)

# Assume display is your display object
center_x = (display.width - text_width * info1_scale) // 2  # scale factor = 3

# Create group with centered x
info1_group = displayio.Group(scale=info1_scale, x=center_x, y=220)
info1_group.append(info1_area)
bgGroup.append(info1_group)

while True:
    scroll(sys_info_area)
    display.refresh(minimum_frames_per_second=0)



cpy_H2Zero_st7796_OnDiskBitmap.py, display .bmp in CircuitPython devices /images folder, using OnDiskBitmap.
"""
Waveshare ESP32-H2-Zero/CircuitPython
display on 1.54 inch 320x320 ST7796 SPI IPS
Display images in /images folder using displayio.OnDiskBitmap, in SlideShow form.

"""
import os, sys, board, time
import busdisplay
import displayio
import busio
import fourwire
import terminalio

TFT_MOSI = board.IO4
TFT_DC   = board.IO3
TFT_SCK  = board.IO2
TFT_CS   = board.IO1
TFT_BL   = board.IO0

DISPLAY_width = 320
DISPLAY_height = 320

ST7796_INIT_SEQUENCE = (
    b"\x01\x80\x96"  # _SWRESET and Delay 150ms

    b"\x11\x80\x78"  # SLPOUT
    b"\x36\x01\x48"  # b"\x36\x01\x08"  # MADCTL
    b"\x3A\x01\x05"  #COLMOD
    b"\xF0\x01\xC3"  # CSCON enable command 2 part I
    b"\xF0\x01\x96"  # CSCON enable command 2 part II
    b"\xB4\x01\x01"  # DIC (Display Inversion Control) - 1 dot inversion
    b"\xB7\x01\xC6"  # EM (Entry mode Set)
    b"\xC0\x02\x80\x45"  # PWR1(Power Control 1)
    b"\xC1\x01\x13"  # PWR2(Power Control 2)
    b"\xC2\x01\xA7"  # PWR3(Power Control 3
    b"\xC5\x01\x0A"  # VCMPCTL (VCOM Control)
    b"\xE8\x08\x40\x8A\x00\x00\x29\x19\xA5\x33" # DOCA (Display Output Ctrl Adjust)
    b"\xE0\x0E\xD0\x08\x0F\x06\x06\x33\x30\x33\x47\x17\x13\x13\x2B\x31" # PGC (Positive Gamma Control)
    b"\xE1\x0E\xD0\x0A\x11\x0B\x09\x07\x2F\x33\x47\x38\x15\x16\x2C\x32" # NGC (Negative Gamma Control)
    b"\xF0\x01\x3C"     # CSCON disable command 2 part I
    b"\xF0\x81\x69\x78" # CSCON disable command 2 part II, then delay 120ms
    b"\x21\x00" # INVON (Display Inversion On)
    b"\x29\x00" # DISPON (Display On)
)

sys_info_text = sys.implementation[0] + " " + os.uname()[3] +\
                "\nrun on " + os.uname()[4] +\
                "\nusing " + busdisplay.BusDisplay.__name__
print("=========================================")
print(sys_info_text)
print("=========================================")

# === init LCD ===
# Release any resources currently in use for the displays
displayio.release_displays()

spi = busio.SPI(clock=TFT_SCK, MOSI=TFT_MOSI)

display_bus = fourwire.FourWire(spi_bus=spi,
                                command=TFT_DC,
                                chip_select=TFT_CS)

display = busdisplay.BusDisplay(display_bus,
                                ST7796_INIT_SEQUENCE,
                                width=DISPLAY_width,
                                height=DISPLAY_height,
                                backlight_pin=TFT_BL)

# Make the display context

#images bmp stored in CIRCUITPY's /images/ folder
images_folder = "/images/"
images_file = ["image_001_320x320_rgb888.bmp",
               "image_002_320x320_rgb888.bmp"]

# Create a dummy bitmap
dummy_bitmap = displayio.Bitmap(320, 320, 1)
dummy_palette = displayio.Palette(1)
dummy_palette[0] = 0x000000
bmpTileGrid = displayio.TileGrid(dummy_bitmap, pixel_shader=dummy_palette)

group = displayio.Group()
group.append(bmpTileGrid)
display.root_group = group

def fade_in():
    for i in range(101):
        display.brightness = 0.01 * i
        time.sleep(0.01)
    
def fade_out():
    for i in range(100, -1, -1):
        display.brightness = 0.01 * i
        time.sleep(0.01)

#fade_out()
def update_bmpTileGrid(path_to_bmp):
    odb = displayio.OnDiskBitmap(path_to_bmp)
    bmpTileGrid.bitmap = odb
    bmpTileGrid.pixel_shader = odb.pixel_shader
    display.refresh()
    #fade_in()
    #time.sleep(3)
    #fade_out()

while True:
    for f in images_file:
        update_bmpTileGrid(images_folder+f)

while True:
    pass



cpy_H2Zero_st7796_SD_OnDiskBitmap.py, display .bmp in /sd/images_bmp folder, using OnDiskBitmap.
"""
Waveshare ESP32-H2-Zero/CircuitPython
display on 1.54 inch 320x320 ST7796 SPI IPS
Display bmp in /sd/images_bmp folder using displayio.OnDiskBitmap.
LCD and SD Card module share the same spi.

    320x320 ST7796 LCD      ESP32-H2-Zero
    -
    BL   ---------+         +-----=======-----+
    3V3  -------+ |         |5V         GPIO24|
    GND  -------|-|---------|GND        GPIO23|
                +-|---------|3V3        GPIO25|
                  +---------|GPIO0      GPIO22|
    CS   -------------------|GPIO1      GPIO14|
    SCK  ----------+--------|GPIO2      GPIO13|
    DC   ----------|--------|GPIO3      GPIO12|
    MOSI --------+-|--------|GPIO4      GPIO11|
                 | |   +----|GPIO5      GPIO10| ----+
                 | |   |    +-----------------+     |
    MicroSD      | |   |                            |
    GND  --- GND | |   |                            |
    VCC  --- 5V  | |   |                            |
    MISO --------|-|---+                            |
    MOSI --------+ |                                |
    SCK  ----------+                                |
    CS   -------------------------------------------+

    Notice: For my MicroSD Card module,
            VCC:  4.5~5.5V
            Data: 3V3/5V 
"""
import os, sys, board, time
import busdisplay
import displayio
import busio
import fourwire
import terminalio

import sdcardio
import storage

SPI_MISO = board.IO5
SPI_MOSI = board.IO4
TFT_DC   = board.IO3
SPI_SCK  = board.IO2
TFT_CS   = board.IO1
TFT_BL   = board.IO0
SD_CS    = board.IO10

DISPLAY_width = 320
DISPLAY_height = 320

ST7796_INIT_SEQUENCE = (
    b"\x01\x80\x96"  # _SWRESET and Delay 150ms

    b"\x11\x80\x78"  # SLPOUT
    b"\x36\x01\x48"  # b"\x36\x01\x08"  # MADCTL
    b"\x3A\x01\x05"  #COLMOD
    b"\xF0\x01\xC3"  # CSCON enable command 2 part I
    b"\xF0\x01\x96"  # CSCON enable command 2 part II
    b"\xB4\x01\x01"  # DIC (Display Inversion Control) - 1 dot inversion
    b"\xB7\x01\xC6"  # EM (Entry mode Set)
    b"\xC0\x02\x80\x45"  # PWR1(Power Control 1)
    b"\xC1\x01\x13"  # PWR2(Power Control 2)
    b"\xC2\x01\xA7"  # PWR3(Power Control 3
    b"\xC5\x01\x0A"  # VCMPCTL (VCOM Control)
    b"\xE8\x08\x40\x8A\x00\x00\x29\x19\xA5\x33" # DOCA (Display Output Ctrl Adjust)
    b"\xE0\x0E\xD0\x08\x0F\x06\x06\x33\x30\x33\x47\x17\x13\x13\x2B\x31" # PGC (Positive Gamma Control)
    b"\xE1\x0E\xD0\x0A\x11\x0B\x09\x07\x2F\x33\x47\x38\x15\x16\x2C\x32" # NGC (Negative Gamma Control)
    b"\xF0\x01\x3C"     # CSCON disable command 2 part I
    b"\xF0\x81\x69\x78" # CSCON disable command 2 part II, then delay 120ms
    b"\x21\x00" # INVON (Display Inversion On)
    b"\x29\x00" # DISPON (Display On)
)

sys_info_text = sys.implementation[0] + " " + os.uname()[3] +\
                "\nrun on " + os.uname()[4] +\
                "\nusing " + busdisplay.BusDisplay.__name__
print("=========================================")
print(sys_info_text)
print("=========================================")

# Release any resources currently in use for the displays
displayio.release_displays()
spi = busio.SPI(clock=SPI_SCK, MOSI=SPI_MOSI, MISO=SPI_MISO) # spi shared by LCD and SD Card module

# === SD card be initialized before display
sd = sdcardio.SDCard(spi=spi, cs=SD_CS)

# Test .bmp stored in "images_bmp" folder in MicroSD card.
storage.mount(storage.VfsFat(sd), '/sd')
images_folder = "/sd/images_bmp/"    
# Collect all .bmp files into a list
images_file = sorted(
    [f for f in os.listdir(images_folder) if f.lower().endswith(".bmp")]
)

# Print the list
for b in images_file:
    print(b)

# === init LCD ===
display_bus = fourwire.FourWire(spi_bus=spi,
                                command=TFT_DC,
                                chip_select=TFT_CS)

display = busdisplay.BusDisplay(display_bus,
                                ST7796_INIT_SEQUENCE,
                                width=DISPLAY_width,
                                height=DISPLAY_height,
                                backlight_pin=TFT_BL)

# Create a dummy bitmap
dummy_bitmap = displayio.Bitmap(320, 320, 1)
dummy_palette = displayio.Palette(1)
dummy_palette[0] = 0x000000
bmpTileGrid = displayio.TileGrid(dummy_bitmap, pixel_shader=dummy_palette)

group = displayio.Group()
group.append(bmpTileGrid)
display.root_group = group

#fade_out()
def update_bmpTileGrid(path_to_bmp):
    print("display:", path_to_bmp)
    odb = displayio.OnDiskBitmap(path_to_bmp)
    bmpTileGrid.bitmap = odb
    bmpTileGrid.pixel_shader = odb.pixel_shader
    display.refresh()

while True:
    for f in images_file:
        update_bmpTileGrid(images_folder+f)




Comments

Popular posts from this blog

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

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