ILI9341 (8bit parallel bus) display on RP2040/CircuitPython

This video show WeAct RP2040 (16M Flash) running CircuitPython 8.0.5, to display on 2.8 inch 320x240 ili9341 TFT with 8/16BIT parallel interface. It should be work on Raspberry Pi Pico also.


This display is set 16-bit parallel interface by default. Read here to set it in 8 bit interface.


    Connection between RP2040 and
    2.8" 320x240 ili9341 TFT in 8-bit parallel interface:

	RP2040 GPIO
        |                      |
        V	               V
		+------------+
		| CLK	T_CS |	
		| F_CS	PEN  |
		| MOSI	MISO |
		| NC	GND  | GND
        GND	| GND	VDD  | 3V3
        3V3	| VDD	BL   | 3V3
		| SDCS	DB15 | 17
        16	| DB14	DB13 | 15
        14	| DB12	DB11 | 13
        12      | DB10	DB9  | 11
        10	| DB8	DB7  |
		| DB6	DB5  |
		| DB4	DB3  |
		| DB2	DB1  |
		| DB0	RST  | 20
        8       | RD	WR   | 19
        9 	| RS	CS   | 18
		+------------+
	        ILI9341 TFT (parallel i/f)
	

Exercise code

cpyPico_ParallelBus_ili9341.py
Simple setup display of adafruit_ili9341, with display_bus = displayio.ParallelBus().
import os, sys
import time
import board
import displayio
import adafruit_ili9341

displayio.release_displays()

"""
This Raspberry Pi Pico,
supports data0= only, not data_pins=, because it requires contiguous pins.
"""
TFT_DATA0 = board.GP10  #The first data pin. The rest are implied
                        #D0~D7 = GP10~17
TFT_RS = board.GP9    #command
TFT_CS = board.GP18   #chip Select
TFT_WR = board.GP19   #write
TFT_RD = board.GP8    #read
TFT_RST = board.GP20  #reset

TFT_WIDTH = 320
TFT_HEIGHT = 240

display_bus = displayio.ParallelBus(data0=TFT_DATA0,
                                    command=TFT_RS,
                                    chip_select=TFT_CS,
                                    write=TFT_WR,
                                    read=TFT_RD,
                                    reset=TFT_RST)

display = adafruit_ili9341.ILI9341(display_bus,
                                   width=TFT_WIDTH,
                                   height=TFT_HEIGHT)
display.rotation=270

print("========================================")
print(sys.implementation[0], os.uname()[3],
      "\nrun on", os.uname()[4])
print("========================================")
print(adafruit_ili9341.__name__, adafruit_ili9341.__version__)
print(display_bus)
print()
print("display.rotation:", display.rotation)
print("display.width:   ", display.width)
print("display.height:  ", display.height)

print()
print("Press Enter to return to REPL")
input()

print("~ bye ~")
time.sleep(1)
print()


cpyPico_ParallelBus_ili9341_graysq.py
A visual illusion exercise, both square have the same gray level.
import os, sys
import time
import board
import displayio
import adafruit_ili9341
from adafruit_display_shapes.rect import Rect

displayio.release_displays()

"""
This Raspberry Pi Pico,
supports data0= only, not data_pins=, because it requires contiguous pins.
"""
TFT_DATA0 = board.GP10  #The first data pin. The rest are implied
                        #D0~D7 = GP10~17
TFT_RS = board.GP9    #command
TFT_CS = board.GP18   #chip Select
TFT_WR = board.GP19   #write
TFT_RD = board.GP8    #read
TFT_RST = board.GP20  #reset

TFT_WIDTH = 320
TFT_HEIGHT = 240

display_bus = displayio.ParallelBus(data0=TFT_DATA0,
                                    command=TFT_RS,
                                    chip_select=TFT_CS,
                                    write=TFT_WR,
                                    read=TFT_RD,
                                    reset=TFT_RST,
                                    frequency=60000000)
# very strange, in my test,
# frequency of 60000000 is more stable than 30000000 or 40000000

display = adafruit_ili9341.ILI9341(display_bus,
                                   width=TFT_WIDTH,
                                   height=TFT_HEIGHT)
display.rotation=0

print("========================================")
print(sys.implementation[0], os.uname()[3],
      "\nrun on", os.uname()[4])
print("========================================")
print(adafruit_ili9341.__name__, adafruit_ili9341.__version__)
print(display_bus)
print()
print("display.rotation:", display.rotation)
print("display.width:   ", display.width)
print("display.height:  ", display.height)
print()


group = displayio.Group()

no_of_color = 256
bg_bitmap = displayio.Bitmap(display.width, display.height, no_of_color)
bg_palette = displayio.Palette(no_of_color)
bg = displayio.TileGrid(bg_bitmap, pixel_shader=bg_palette)

for i in range(no_of_color):
    bg_palette[i] = i*0x10000 + i*0x100 +i
    
for y in range(display.height):
    for x in range(display.width):
        bg_bitmap[x, y] = y

group.append(bg)

sq = Rect(20, 20, 20, 20, fill=0xA0A0A0)
group.append(sq)

sq2 = Rect(280, 200, 20, 20, fill=0xA0A0A0)
group.append(sq2)

"""
show() is deprecated and will be removed in CircuitPython 9.0.0. Use .root_group = group instead.
https://docs.circuitpython.org/en/latest/shared-bindings/displayio/index.html#displayio.Display.show
"""
#display.show(group)
display.root_group = group
time.sleep(5)

x_dir=1
y_dir=1
x_step=3
y_step=2


while True:
    time.sleep(0.05)
    sq.x = sq.x + x_dir*x_step
    sq.y = sq.y + y_dir*y_step
    
    if x_dir>0:
        if sq.x>=display.width-1-sq.width:
            x_dir = -1
    else:
        if sq.x<=0:
            x_dir = 1
            
    if y_dir>0:
        if sq.y>=display.height-1-sq.height:
            y_dir = -1
    else:
        if sq.y<=0:
            y_dir = 1


while True:
    pass

cpyPico_ParallelBus_ili9341_graybar.py
Another visual illusion exercise, the frame is set a single gray level.
import os, sys
import time
import board
import displayio
import adafruit_ili9341
from adafruit_display_shapes.rect import Rect

displayio.release_displays()

"""
This Raspberry Pi Pico,
supports data0= only, not data_pins=, because it requires contiguous pins.
"""
TFT_DATA0 = board.GP10  #The first data pin. The rest are implied
                        #D0~D7 = GP10~17
TFT_RS = board.GP9    #command
TFT_CS = board.GP18   #chip Select
TFT_WR = board.GP19   #write
TFT_RD = board.GP8    #read
TFT_RST = board.GP20  #reset

TFT_WIDTH = 320
TFT_HEIGHT = 240

display_bus = displayio.ParallelBus(data0=TFT_DATA0,
                                    command=TFT_RS,
                                    chip_select=TFT_CS,
                                    write=TFT_WR,
                                    read=TFT_RD,
                                    reset=TFT_RST,
                                    frequency=60000000)

display = adafruit_ili9341.ILI9341(display_bus,
                                   width=TFT_WIDTH,
                                   height=TFT_HEIGHT)
display.rotation=0

print("========================================")
print(sys.implementation[0], os.uname()[3],
      "\nrun on", os.uname()[4])
print("========================================")
print(adafruit_ili9341.__name__, adafruit_ili9341.__version__)
print(display_bus)
print()
print("display.rotation:", display.rotation)
print("display.width:   ", display.width)
print("display.height:  ", display.height)
print()

group = displayio.Group()

no_of_color = 256
bg_bitmap = displayio.Bitmap(display.width, display.height, no_of_color)
bg_palette = displayio.Palette(no_of_color)
bg = displayio.TileGrid(bg_bitmap, pixel_shader=bg_palette)

for i in range(no_of_color):
    bg_palette[i] = i*0x10000 + i*0x100 +i
    
for y in range(display.height):
    for x in range(display.width):
        bg_bitmap[x, y] = y

group.append(bg)

#All four rect set same gray level
rect = Rect(20, 10, 10, 220, fill=0xA0A0A0)
group.append(rect)

rect2 = Rect(20, 10, 280, 10, fill=0xA0A0A0)
group.append(rect2)

rect3 = Rect(20, 220, 280, 10, fill=0xA0A0A0)
group.append(rect3)

rect3 = Rect(300, 10, 10, 220, fill=0xA0A0A0)
group.append(rect3)

"""
show() is deprecated and will be removed in CircuitPython 9.0.0. Use .root_group = group instead.
https://docs.circuitpython.org/en/latest/shared-bindings/displayio/index.html#displayio.Display.show
"""
#display.show(group)
display.root_group = group

while True:
    time.sleep(5)
    for i in range(no_of_color):
        inv_i = 255-i
        bg_palette[i] = inv_i*0x10000 + inv_i*0x100 +inv_i
    
    time.sleep(5)
    for i in range(no_of_color):
        bg_palette[i] = i*0x10000 + i*0x100 +i
 


cpyPico_ParallelBus_ili9341_hello.py
import os, sys
import time
import board
import displayio
import adafruit_ili9341
import terminalio
from adafruit_display_shapes.rect import Rect
from adafruit_display_text import label

displayio.release_displays()

"""
This Raspberry Pi Pico,
supports data0= only, not data_pins=, because it requires contiguous pins.
"""
TFT_DATA0 = board.GP10  #The first data pin. The rest are implied
                        #D0~D7 = GP10~17
TFT_RS = board.GP9    #command
TFT_CS = board.GP18   #chip Select
TFT_WR = board.GP19   #write
TFT_RD = board.GP8    #read
TFT_RST = board.GP20  #reset

TFT_WIDTH = 320
TFT_HEIGHT = 240

display_bus = displayio.ParallelBus(data0=TFT_DATA0,
                                    command=TFT_RS,
                                    chip_select=TFT_CS,
                                    write=TFT_WR,
                                    read=TFT_RD,
                                    reset=TFT_RST,
                                    frequency=60000000)
# very strange, in my test,
# frequency of 60000000 is more stable than 30000000 or 40000000

display = adafruit_ili9341.ILI9341(display_bus,
                                   width=TFT_WIDTH,
                                   height=TFT_HEIGHT)
display.rotation=270

print("========================================")
print(sys.implementation[0], os.uname()[3],
      "\nrun on", os.uname()[4])
print("========================================")
print(adafruit_ili9341.__name__, adafruit_ili9341.__version__)
print(display_bus)
print()
print("display.rotation:", display.rotation)
print("display.width:   ", display.width)
print("display.height:  ", display.height)
print()


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

"""
show() is deprecated and will be removed in CircuitPython 9.0.0. Use .root_group = group instead.
https://docs.circuitpython.org/en/latest/shared-bindings/displayio/index.html#displayio.Display.show
"""
#display.show(splash)
display.root_group = splash

bg_bitmap = displayio.Bitmap(display.width, display.height, 1)
bg_palette = displayio.Palette(1)
bg_palette[0] = 0xFFFFFF  # White

background = displayio.TileGrid(bg_bitmap, pixel_shader=bg_palette, x=0, y=0)
splash.append(background)

inner_bitmap = displayio.Bitmap(display.width-2, display.height-2, 1)
inner_palette = displayio.Palette(1)
inner_palette[0] = 0x000000  # Black

inner = displayio.TileGrid(inner_bitmap, pixel_shader=inner_palette, x=1, y=1)
splash.append(inner)


# draw a label say hello
text_hello = "coxxect.blogspot.com"
label_hello = label.Label(terminalio.FONT, text=text_hello, scale=2, color=0xFF0000, x=2, y=10)
splash.append(label_hello)

# label for CircuitPython info
sys_info = sys.implementation[0] + " " + os.uname()[2] + "\nrun on " + os.uname()[4]
# labels for driver
label_sysinfo = label.Label(terminalio.FONT,
                            text=sys_info,
                            scale=1,
                            color=0x00FF00,
                            x=5, y=40)
splash.append(label_sysinfo)

# labels for driver
label_drv_name = label.Label(terminalio.FONT,
                             text=adafruit_ili9341.__name__,
                             scale=1,
                             color=0x0000FF,
                             x=5, y=90)
splash.append(label_drv_name)

label_drv_ver = label.Label(terminalio.FONT,
                            text=adafruit_ili9341.__version__,
                            scale=2,
                            color=0x0000FF,
                            x=5, y=110)
splash.append(label_drv_ver)

# scroll()/reverse_scroll()
# 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

time.sleep(1)

while True:
    scroll(label_sysinfo)
    scroll(label_drv_name)
    reverse_scroll(label_drv_ver)
    display.refresh(minimum_frames_per_second=0)

ref:
CircuitPython Display Support Using displayio Display and Display Bus
paralleldisplay

next:
RP2040/CircuitPython 8.1.0 Beta 1, play animated GIF on 8 bit parallel bus ILI9341.
Play animated GIF stored in SD Card

Comments

Popular posts from this blog

MicroPython/ESP32-C3 + 1.8" 128x160 TFT ST7735 SPI, using boochow/MicroPython-ST7735 library.

CameraWebServe: ESP32-S3 (arduino-esp32) + OV5640 camera module