Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ESP32/CYD: Add support for XPT2046 access via SoftSpi and user supplied orientation tables for ILI9XXX classes #340

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 13 additions & 9 deletions driver/esp32/ili9XXX.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
MADCTL_MY = const(0x80) # 0=Top to Bottom, 1=Bottom to Top

# MADCTL values for each of the orientation constants for non-st7789 displays.
ORIENTATION_TABLE = (MADCTL_MX, MADCTL_MV, MADCTL_MY, MADCTL_MY | MADCTL_MX | MADCTL_MV)
DEFAULT_ORIENTATION_TABLE = (MADCTL_MX, MADCTL_MV, MADCTL_MY, MADCTL_MY | MADCTL_MX | MADCTL_MV)

# Negative orientation constants indicate the MADCTL value will come from the ORIENTATION_TABLE,
# otherwise the rot value is used as the MADCTL value.
Expand Down Expand Up @@ -497,7 +497,8 @@ def __init__(self,
miso=5, mosi=18, clk=19, cs=13, dc=12, rst=4, power=14, backlight=15, backlight_on=0, power_on=0,
spihost=esp.HSPI_HOST, spimode=0, mhz=40, factor=4, hybrid=True, width=240, height=320, start_x=0, start_y=0,
colormode=COLOR_MODE_BGR, rot=PORTRAIT, invert=False, double_buffer=True, half_duplex=True,
asynchronous=False, initialize=True, color_format=lv.COLOR_FORMAT.RGB565, swap_rgb565_bytes=True
asynchronous=False, initialize=True, color_format=lv.COLOR_FORMAT.RGB565, swap_rgb565_bytes=True,
orientation_table=DEFAULT_ORIENTATION_TABLE
):

# Make sure MicroPython was built such that color won't require processing before DMA
Expand All @@ -508,6 +509,7 @@ def __init__(self,
self.display_name = 'ILI9341'

self.init_cmds = [
{'cmd': 0x01, 'delay': 100}, # SW Reset
{'cmd': 0xCF, 'data': bytes([0x00, 0x83, 0X30])},
{'cmd': 0xED, 'data': bytes([0x64, 0x03, 0X12, 0X81])},
{'cmd': 0xE8, 'data': bytes([0x85, 0x01, 0x79])},
Expand All @@ -520,7 +522,7 @@ def __init__(self,
{'cmd': 0xC7, 'data': bytes([0xBE])}, # VCOM control

{'cmd': 0x36, 'data': bytes([
self.madctl(colormode, rot, ORIENTATION_TABLE)])}, # MADCTL
self.madctl(colormode, rot, orientation_table)])}, # MADCTL

{'cmd': 0x3A, 'data': bytes([0x55])}, # Pixel Format Set
{'cmd': 0xB1, 'data': bytes([0x00, 0x1B])},
Expand Down Expand Up @@ -549,7 +551,8 @@ def __init__(self,
miso=5, mosi=18, clk=19, cs=13, dc=12, rst=4, power=14, backlight=15, backlight_on=0, power_on=0,
spihost=esp.HSPI_HOST, spimode=0, mhz=40, factor=8, hybrid=True, width=320, height=480, colormode=COLOR_MODE_RGB,
rot=PORTRAIT, invert=False, double_buffer=True, half_duplex=True, asynchronous=False, initialize=True,
color_format=lv.COLOR_FORMAT.XRGB8888, display_type=DISPLAY_TYPE_ILI9488, p16=False, swap_rgb565_bytes=False
color_format=lv.COLOR_FORMAT.XRGB8888, display_type=DISPLAY_TYPE_ILI9488, p16=False, swap_rgb565_bytes=False,
orientation_table=DEFAULT_ORIENTATION_TABLE
):

if (lv.color_format_get_bpp(color_format) != 32) and not p16:
Expand All @@ -576,7 +579,7 @@ def __init__(self,
#{'cmd': 0xC5, 'data': bytes([0x00, 0x0, 0x0, 0x0])},

{'cmd': 0x36, 'data': bytes([
self.madctl(colormode, rot, ORIENTATION_TABLE)])}, # MADCTL
self.madctl(colormode, rot, orientation_table)])}, # MADCTL

{'cmd': 0x3A, 'data': bytes(pix_format)},
{'cmd': 0xB0, 'data': bytes([0x00])},
Expand Down Expand Up @@ -633,7 +636,7 @@ def __init__(self,
miso=5, mosi=18, clk=19, cs=13, dc=12, rst=4, power=14, backlight=15, backlight_on=0, power_on=0,
spihost=esp.HSPI_HOST, spimode=0, mhz=60, factor=4, hybrid=True, width=240, height=240, colormode=COLOR_MODE_RGB,
rot=PORTRAIT, invert=False, double_buffer=True, half_duplex=True, asynchronous=False, initialize=True,
color_format=lv.COLOR_FORMAT.RGB565, swap_rgb565_bytes=True
color_format=lv.COLOR_FORMAT.RGB565, swap_rgb565_bytes=True, orientation_table=DEFAULT_ORIENTATION_TABLE
):

if lv.color_format_get_bpp(color_format) != 16:
Expand Down Expand Up @@ -670,7 +673,7 @@ def __init__(self,
{'cmd': 0xB6, 'data': bytes([0x00, 0x00])},

{'cmd': 0x36, 'data': bytes([
self.madctl(colormode, rot, ORIENTATION_TABLE)])}, # MADCTL
self.madctl(colormode, rot, orientation_table)])}, # MADCTL

{'cmd': 0x3A, 'data': bytes([0x05])},
{'cmd': 0x90, 'data': bytes([0x08, 0x08, 0x08, 0x08])},
Expand Down Expand Up @@ -774,7 +777,8 @@ def __init__(self,
miso=-1, mosi=19, clk=18, cs=13, dc=12, rst=4, power=-1, backlight=15, backlight_on=1, power_on=0,
spihost=esp.HSPI_HOST, spimode=0, mhz=40, factor=4, hybrid=True, width=128, height=160, start_x=0, start_y=0,
colormode=COLOR_MODE_RGB, rot=PORTRAIT, invert=False, double_buffer=True, half_duplex=True,
asynchronous=False, initialize=True, color_format=lv.COLOR_FORMAT.RGB565, swap_rgb565_bytes=True):
asynchronous=False, initialize=True, color_format=lv.COLOR_FORMAT.RGB565, swap_rgb565_bytes=True,
orientation_table=(MADCTL_MX | MADCTL_MY, MADCTL_MV | MADCTL_MY, 0, MADCTL_MX | MADCTL_MV)):

# Make sure Micropython was built such that color won't require processing before DMA

Expand All @@ -796,7 +800,7 @@ def __init__(self,
{'cmd': 0xC7, 'data': bytes([0xBE])}, # VCOM control

{'cmd': 0x36, 'data': bytes([
self.madctl(colormode, rot, (MADCTL_MX | MADCTL_MY, MADCTL_MV | MADCTL_MY, 0, MADCTL_MX | MADCTL_MV))])}, # MADCTL
self.madctl(colormode, rot, orientation_table)])}, # MADCTL

{'cmd': 0x3A, 'data': bytes([0x55])}, # Pixel Format Set
{'cmd': 0xB1, 'data': bytes([0x00, 0x1B])},
Expand Down
59 changes: 54 additions & 5 deletions driver/esp32/xpt2046.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from micropython import const

import machine

import espidf as esp
import lvgl as lv

Expand All @@ -11,10 +13,10 @@
class xpt2046:

# Command is 8 bit, but we add another bit as a space before xpt2046 stats sending the response, See Figure 12 on the datasheet
CMD_X_READ = const(0b100100000)
CMD_Y_READ = const(0b110100000)
CMD_Z1_READ = const(0b101100000)
CMD_Z2_READ = const(0b110000000)
CMD_X_READ = 0b100100000
CMD_Y_READ = 0b110100000
CMD_Z1_READ = 0b101100000
CMD_Z2_READ = 0b110000000

MAX_RAW_COORD = const((1<<12) - 1)

Expand Down Expand Up @@ -192,7 +194,7 @@ def get_coords(self):
x = ((int(raw_x) - int(self.cal_x0)) * int(self.screen_width)) // (int(self.cal_x1) - int(self.cal_x0))
y = ((int(raw_y) - int(self.cal_y0)) * int(self.screen_height)) // (int(self.cal_y1) - int(self.cal_y0))
# print('(%d, %d) ==> (%d, %d)' % (raw_x, raw_y, x, y))
return x,y
return min(max(0, x), self.screen_width),min(max(0, y), self.screen_height)
else: return None

# @micropython.native
Expand Down Expand Up @@ -223,4 +225,51 @@ def read(self, indev_drv, data) -> int:
def stat(self):
return self.touch_cycles / (self.touch_count * self.cycles_in_ms)

class xpt2046_softspi(xpt2046):
# Reduce back to 8 bit, as SoftSPI does not support 9 commandbits option
# (See also comment in parent class)
CMD_X_READ = 0b10010000
CMD_Y_READ = 0b11010000
CMD_Z1_READ = 0b10110000
CMD_Z2_READ = 0b11000000

def __init__(self, miso=-1, mosi=-1, clk=-1, cs=25,
spihost=esp.HSPI_HOST, half_duplex=True, mhz=5, max_cmds=16,
cal_x0 = 3783, cal_y0 = 3948, cal_x1 = 242, cal_y1 = 423,
transpose = True, samples = 3):

# Create SOFTSPI buffers
self.softSpiTxBuf = bytearray(3)
self.softSpiRxBuf = bytearray(3)

super().__init__(miso = miso, mosi = mosi, clk = clk, cs = cs,
half_duplex = half_duplex, mhz = mhz, max_cmds = max_cmds,
cal_x0 = cal_x0, cal_y0 = cal_y0, cal_x1 = cal_x1, cal_y1 = cal_y1,
transpose = transpose, samples = samples)

def spi_init(self):
self.spi = machine.SoftSPI(baudrate=self.mhz*1000*1000, bits=8, sck=machine.Pin(self.clk), mosi=machine.Pin(self.mosi), miso=machine.Pin(self.miso))
self.cs = machine.Pin(self.cs)

def deinit(self):
self.spi.deinit()

# @micropython.viper
def xpt_cmds(self, cmds):
cmd_count = int(len(cmds))
result = []
rx = self.softSpiRxBuf
tx = self.softSpiTxBuf
for i in range(0, cmd_count):
tx[0] = cmds[i]
self.cs(0)
self.spi.write_readinto(tx, rx)
self.cs(1)
# Due to SoftSPI not supporting 9 command bits, the received 12 bits are delayed by 1 bit
value = (int(rx[1]) << 5) + (int(rx[2]) >> 3) # value is in the 12 higher bits, network order

if value == int(self.MAX_RAW_COORD):
value = 0
result.append(value)

return tuple(result)