From 75bbe28e3f126b8be97a9aecd5aedce658c03ea3 Mon Sep 17 00:00:00 2001 From: Angus71 Date: Tue, 7 May 2024 19:40:35 +0200 Subject: [PATCH] ILI9341: Add software reset command in init command ILI9XXX: Add option to provide external orientation table XPT2046: Add SoftSPI support (E.g. CYD boards) --- driver/esp32/ili9XXX.py | 22 ++++++++------- driver/esp32/xpt2046.py | 59 +++++++++++++++++++++++++++++++++++++---- 2 files changed, 67 insertions(+), 14 deletions(-) diff --git a/driver/esp32/ili9XXX.py b/driver/esp32/ili9XXX.py index b86be18bd..9ce29aabd 100644 --- a/driver/esp32/ili9XXX.py +++ b/driver/esp32/ili9XXX.py @@ -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. @@ -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 @@ -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])}, @@ -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])}, @@ -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: @@ -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])}, @@ -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: @@ -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])}, @@ -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 @@ -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])}, diff --git a/driver/esp32/xpt2046.py b/driver/esp32/xpt2046.py index 0fad01b43..27aceedb0 100644 --- a/driver/esp32/xpt2046.py +++ b/driver/esp32/xpt2046.py @@ -1,5 +1,7 @@ from micropython import const +import machine + import espidf as esp import lvgl as lv @@ -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) @@ -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 @@ -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)