1.28" 240x240 Round Display with GC9A01 SPI, on Raspberry Pi Pico 2 W.

Exercises run on Raspberry Pi Pico 2 W/CircuitPython 10.0.3, to display on 1.28 inch IPS Module: GC9A01+CST816S 240*240(Round) 4W-SPI.

Connection:

     Raspberry Pi Pico 2 W

            Run |
            GP22| ------- LCD_BLK ------------+
            GND |                             |
            GP21| ------- LCD_DC ---------+   |
            GP20| ------- LCD_RES-------+ |   |
            GP19| MOSI	- SPI_SDA ----+ | |   |
            GP18| SCK	- SPI_SCL --+ | | |   |
            GND |                   | | | |   |
            GP17| SS	- LCD_CS ---|-|-|-|-+ |
            GP16| MISO  - no use    | | | | | |
	--------+                   | | | | | |
                                    | | | | | |
                                    | | | | | |     GC9A01
                                    | | | | | |
                                    | | | | | +---- BLK
                                    | | | | +------ CS
                                    | | | +-------- DC
                                    | | +---------- RES
                                    | +------------ SDA
                                    +-------------- SCL
                                            3V3 --- VCC
                                            GND --- GND


Code:

cpy_rpPicoW_gc9a01_color.py, basic color test.
"""
Raspberry Pi Pico 2 W/CircuitPython 10.0.3
with 1.28" 240x240 Round GC9A01 SPI IPS LCD
Basic Color Test

details:
https://coxxect.blogspot.com/2026/01/128-240x240-round-display-with-gc9a01.html

Library needed:
- adafruit_gc9a01a.mpy
- adafruit_display_text folder
"""
import os, sys
import board
import time
import displayio
import busio
import terminalio
import adafruit_gc9a01a
from fourwire import FourWire
from adafruit_display_text import label

displayio.release_displays()

tft_blk = board.GP22
tft_cs  = board.GP17
tft_dc  = board.GP21
tft_res = board.GP20
tft_sda = board.GP19
tft_scl = board.GP18

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

disp_spi = busio.SPI(clock=tft_scl, MOSI=tft_sda)

display_bus = FourWire(spi_bus=disp_spi,
                       command=tft_dc,
                       chip_select=tft_cs,
                       reset=tft_res)
display = adafruit_gc9a01a.GC9A01A(display_bus, width=240, height=240, backlight_pin=tft_blk)

#=======================================
info = os.uname()[4] + "\n" + \
       sys.implementation[0] + " " + os.uname()[3] + "\n" + \
       adafruit_gc9a01a.__name__ + " " + adafruit_gc9a01a.__version__
print("=======================================")
print(info)
print("=======================================")
print()

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

#display.show(bgGroup)
display.root_group = bgGroup

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

color_bitmap = displayio.Bitmap(display.width, display.height, 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=0, y=0)
bgGroup.append(color_sprite)

# Draw label
text_group = displayio.Group(scale=1, x=20, y=120)
text_area = label.Label(terminalio.FONT, text=info, color=0xFFFFFF)
text_group.append(text_area)  # Subgroup for text scaling
bgGroup.append(text_group)
time.sleep(3)

text_group.scale = 2
time.sleep(2)
text_group.scale = 3
time.sleep(2)
while True:
    for i in colorSet:
        color_palette[0] = i[0]
        text_area.text = i[1]
        text_area.color = i[0] ^ 0xFFFFFF
        time.sleep(3)


cpy_rpPicoW_gc9a01_circle_scene.py, draw something circles.
"""
Raspberry Pi Pico 2 W/CircuitPython 10.0.3
with 1.28" 240x240 Round GC9A01 SPI IPS LCD
Draw something (concentric circles, rainbow wheel, spiral illusion),
also show how to switch between scenes (bgGroup and group), by calling show_scene().

details:
https://coxxect.blogspot.com/2026/01/128-240x240-round-display-with-gc9a01.html

Library needed:
- adafruit_gc9a01a.mpy
- adafruit_display_text folder

"""
import os, sys
import board
import time
import displayio
import busio
import terminalio
import adafruit_gc9a01a
from fourwire import FourWire
from adafruit_display_text import label
import math

displayio.release_displays()

tft_blk = board.GP22
tft_cs  = board.GP17
tft_dc  = board.GP21
tft_res = board.GP20
tft_sda = board.GP19
tft_scl = board.GP18

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

disp_spi = busio.SPI(clock=tft_scl, MOSI=tft_sda)

display_bus = FourWire(spi_bus=disp_spi,
                       command=tft_dc,
                       chip_select=tft_cs,
                       reset=tft_res)
display = adafruit_gc9a01a.GC9A01A(display_bus, width=240, height=240, backlight_pin=tft_blk)

#=======================================
info = os.uname()[4] + "\n" + \
       sys.implementation[0] + " " + os.uname()[3] + "\n" + \
       adafruit_gc9a01a.__name__ + " " + adafruit_gc9a01a.__version__
print("=======================================")
print(info)
print("=======================================")
print()

# Group to display Title
bgGroup = displayio.Group()

color_bitmap = displayio.Bitmap(display.width, display.height, 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=0, y=0)
bgGroup.append(color_sprite)

# Draw label
text_group = displayio.Group(scale=1, x=20, y=120)
text_area = label.Label(terminalio.FONT, text=info, color=0xFFFFFF)
text_group.append(text_area)  # Subgroup for text scaling
bgGroup.append(text_group)

# Group to display Bitmap

bitmap = displayio.Bitmap(240, 240, 256)
palette = displayio.Palette(256)

tile_grid = displayio.TileGrid(bitmap, pixel_shader=palette)
group = displayio.Group()
group.append(tile_grid)

# Used to switch whole root_group, between bgGroup and group
def show_scene(scene_group):
    display.root_group = scene_group
    
show_scene(bgGroup)
time.sleep(2)
show_scene(group)

# clear palette all to black
def clear_palette():
    for i in range(0, 256):
        palette[i] = (0, 0, 0)

def fill_palette_red():
    palette[0] = (0, 0, 0)
    for i in range(1, 256):
        palette[i] = (i, 255-i, 255-i)
        
def fill_palette_green():
    palette[0] = (0, 0, 0)
    for i in range(1, 256):
        palette[i] = (255-i, i, 255-i)
        
def fill_palette_blue():
    palette[0] = (0, 0, 0)
    for i in range(1, 256):
        palette[i] = (255-i, 255-i, 255)
        
def fill_palette_white():
    palette[0] = (0, 0, 0)
    for i in range(1, 256):
        palette[i] = (i, i, i)
        
def fill_palette_black():
    palette[0] = (0, 0, 0)
    for i in range(1, 256):
        palette[i] = (255-i, 255-i, 255-i)
    
def change_palette():
    fill_palette_red()
    time.sleep(2)

    fill_palette_green()
    time.sleep(2)

    fill_palette_blue()
    time.sleep(2)
    
    fill_palette_white()
    time.sleep(2)
    
    fill_palette_black()
    time.sleep(2)

def draw_concentric_circles():
    text_group.scale = 1
    text_area.text = "concentric\ncircles"
    show_scene(bgGroup)
    time.sleep(2)
    show_scene(group)
    
    clear_palette()
    bitmap.fill(0)
    for r in range(10, 120, 5):
        color = (r*2) % 255
        for angle in range(0, 360, 1):
            angle_radians = math.radians(angle)
            x = int(120 + r * (math.cos(angle_radians)))
            y = int(120 + r * (math.sin(angle_radians)))
            if 0 <= x < 240 and 0 <= y < 240:
                bitmap[x, y] = color
                
    change_palette()
    
def draw_rainbow_wheel():
    text_group.scale = 2
    text_area.text = "rainbow\nwheel"
    show_scene(bgGroup)
    time.sleep(2)
    show_scene(group)
    
    clear_palette()
    bitmap.fill(0)
    for angle in range(0, 360, 5):
        # Because palette[0]=Black, so map 0~359(angle) to 1~255(color)
        color = 1 + int(angle * 254 / 359)
        for r in range(20, 120):
            x = int(120 + r * math.cos(math.radians(angle)))
            y = int(120 + r * math.sin(math.radians(angle)))
            if 0 <= x < 240 and 0 <= y < 240:
                bitmap[x, y] = color

    change_palette()
    
def draw_spiral_illusion():
    text_group.scale = 3
    text_area.text = "spiral\nillusion"
    show_scene(bgGroup)
    time.sleep(2)
    show_scene(group)
    
    clear_palette()
    bitmap.fill(0)
    palette[0] = 0x000000 # Black
    palette[1] = 0xFFFFFF # White
    
    for s in range(4, 9, 1):
        do_spiral_illusion(step=s)
        time.sleep(2)

def do_spiral_illusion(step=5):
    bitmap.fill(0)
    for angle in range(0, 360, step):
        for r in range(20, 120, step):
            x = int(120 + r * math.cos(math.radians(angle)))
            y = int(120 + r * math.sin(math.radians(angle)))
            if 0 <= x < 240 and 0 <= y < 240:
                bitmap[x, y] = ((r//step + angle//step) % 2)

while True:
    draw_concentric_circles()
    draw_rainbow_wheel()
    draw_spiral_illusion()


cpy_rpPicoW_gc9a01_heart.py, display beating heart.
"""
Raspberry Pi Pico 2 W/CircuitPython 10.0.3
with 1.28" 240x240 Round GC9A01 SPI IPS LCD
Draw beating heart, switch between two bitmaps to prevent flicker problem.

details:
https://coxxect.blogspot.com/2026/01/128-240x240-round-display-with-gc9a01.html

Library needed:
- adafruit_gc9a01a.mpy
- adafruit_display_text folder

"""
import os, sys
import board
import time
import displayio
import busio
import terminalio
import adafruit_gc9a01a
from fourwire import FourWire
from adafruit_display_text import label
import math

displayio.release_displays()

tft_blk = board.GP22
tft_cs  = board.GP17
tft_dc  = board.GP21
tft_res = board.GP20
tft_sda = board.GP19
tft_scl = board.GP18

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

disp_spi = busio.SPI(clock=tft_scl, MOSI=tft_sda)

display_bus = FourWire(spi_bus=disp_spi,
                       command=tft_dc,
                       chip_select=tft_cs,
                       reset=tft_res)
display = adafruit_gc9a01a.GC9A01A(display_bus, width=240, height=240, backlight_pin=tft_blk)

#=======================================
info = os.uname()[4] + "\n" + \
       sys.implementation[0] + " " + os.uname()[3] + "\n" + \
       adafruit_gc9a01a.__name__ + " " + adafruit_gc9a01a.__version__
print("=======================================")
print(info)
print("=======================================")
print()

# Group to display Title
bgGroup = displayio.Group()

color_bitmap = displayio.Bitmap(display.width, display.height, 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=0, y=0)
bgGroup.append(color_sprite)

# Draw label
text_group = displayio.Group(scale=1, x=20, y=120)
text_area = label.Label(terminalio.FONT, text=info, color=0xFFFFFF)
text_group.append(text_area)  # Subgroup for text scaling
bgGroup.append(text_group)

# Group to display Bitmap

# two bitmaps, same palette
bitmap_a = displayio.Bitmap(240, 240, 2)
bitmap_b = displayio.Bitmap(240, 240, 2)
palette = displayio.Palette(2)
palette[0] = 0x000000 # Black
palette[1] = 0xFF0000 # Red
    
tile_grid = displayio.TileGrid(bitmap_a, pixel_shader=palette)
group = displayio.Group()
group.append(tile_grid)

# Used to switch whole root_group, between bgGroup and group
def show_scene(scene_group):
    display.root_group = scene_group
    
show_scene(bgGroup)
time.sleep(2)
show_scene(group)

WIDTH = display.width
HEIGHT = display.height
CENTER_X = WIDTH//2
CENTER_Y = HEIGHT//2

# parameter to calculate scale
heart_size = 5
beating_amplitude = 1
beating_speed = 2

def to_draw_heart():
    use_a = True
    while True:
        scale = heart_size + beating_amplitude*math.sin(time.monotonic()*beating_speed)
        if use_a:
            draw_heart(bitmap_a, scale)
            tile_grid.bitmap = bitmap_a
        else:
            draw_heart(bitmap_b, scale)
            tile_grid.bitmap = bitmap_b
        use_a = not use_a
        time.sleep(0.05)
        
# helper to draw heart into a bitmap
def draw_heart(bitmap, scale):
    bitmap.fill(0)
    for t in range(0, 360, 2):
        rad = math.radians(t)
        x = int(CENTER_X + scale * 16 * math.sin(rad)**3)
        y = int(CENTER_Y - scale * (13*math.cos(rad)
                                    - 5*math.cos(2*rad)
                                    - 2*math.cos(3*rad)
                                    - math.cos(4*rad)))
        if 0 <= x < WIDTH and 0 <= y < HEIGHT:
            bitmap[x, y] = 1

while True:
    text_group.scale = 3
    text_area.text = "Beating\nheart"
    show_scene(bgGroup)
    time.sleep(2)
    show_scene(group)
    
    to_draw_heart()



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