From 0539c3a8f60cc3c7c0cb90dd3f4bf39d7f84a0dc Mon Sep 17 00:00:00 2001 From: Peter Hinch Date: Sat, 24 Apr 2021 13:58:26 +0100 Subject: [PATCH] ST7789 TTGO first release. --- DRIVERS.md | 18 +++++++-- color_setup/ssd7789.py | 2 +- drivers/st7789/color_setup_ttgo.py | 27 ++++++++++++-- drivers/st7789/st7789_4bit.py | 60 +++++++++++++++++++----------- 4 files changed, 77 insertions(+), 30 deletions(-) diff --git a/DRIVERS.md b/DRIVERS.md index 38544a7..a98fe27 100644 --- a/DRIVERS.md +++ b/DRIVERS.md @@ -390,8 +390,8 @@ below. An example file for the Pi Pico is in `color_setup/ssd7789.py`. #### ST7789 Constructor args: * `spi` An initialised SPI bus instance. The chip supports clock rates of upto - 62.5MHz (datasheet table 6). I have tested 60MHz. High speeds may be sensitive - to electrical issues such as lead lengths, PCB layout and grounding. + 62.5MHz (datasheet table 6). I have tested 60MHz. High speeds are sensitive to + electrical issues such as lead lengths, PCB layout and grounding. * `cs` An initialised output pin. Initial value should be 1. * `dc` An initialised output pin. Initial value should be 0. * `rst` An initialised output pin. Initial value should be 1. @@ -424,11 +424,12 @@ def spi_init(spi): ``` #### Display mode -This is povided in the hope of supporting other displays which may not be -symmetrical. It also enables the Adafruit display image to be rotated. +This is provided mainly to support asymmetrical displays. It also enables the +Adafruit display image to be rotated. The driver exports the following constants: ```python +LANDSCAPE = 0 # Normal display PORTRAIT = 0x20 # Rotate 90° REFLECT = 0x40 # Swap pixels left-right USD = 0x80 # Upside down: swap pixels top-bottom @@ -474,6 +475,9 @@ option may be to overclock. ### 3.3.1 TTGO T Display +Thanks to [Ihor Nehrutsa](https://github.com/IhorNehrutsa) who wrote much of +the setup file for this device. + This is an ESP32 based device with an integrated 1.14" 135x240 pixel display based on ST7789. @@ -481,6 +485,12 @@ It is supported by `color_setup_ttgo.py` in `drivers/st7789`. Copy to `/pyboard/color_setup.py` on the device. It produces a landscape mode display with the top left hand corner adjacent to pin 36. +Commented-out code offers portrait mode with variants for upside-down and +reflected display modes. These differ from those for the Adafruit display. This +is because the display hardware is designed in portrait mode. The color setup +file transposes the `PORTRAIT` and `LANDSCAPE` constants with consequent +changes to the effect of the `USD` and `REFLECT` constants. + ###### [Contents](./DRIVERS.md#contents) # 4. Drivers for sharp displays diff --git a/color_setup/ssd7789.py b/color_setup/ssd7789.py index 0e0e612..75d5e3c 100644 --- a/color_setup/ssd7789.py +++ b/color_setup/ssd7789.py @@ -33,7 +33,7 @@ pcs = Pin(14, Pin.OUT, value=1) prst = Pin(15, Pin.OUT, value=1) gc.collect() # Precaution before instantiating framebuf -# Conservative low baudrate. Can go to 62.5MHz. +# Conservative low baudrate. Can go to 62.5MHz. Depending on wiring. spi = SPI(1, 30_000_000, sck=Pin(10), mosi=Pin(11), miso=Pin(8)) ssd = SSD(spi, dc=pdc, cs=pcs, rst=prst) #, disp_mode=PORTRAIT | USD) diff --git a/drivers/st7789/color_setup_ttgo.py b/drivers/st7789/color_setup_ttgo.py index 7207cdd..9a052c3 100644 --- a/drivers/st7789/color_setup_ttgo.py +++ b/drivers/st7789/color_setup_ttgo.py @@ -6,7 +6,7 @@ # Notes: Peter Hinch April 2021 # UNDER DEVELOPMENT. This file and the ST7789 driver may change. # These settings produce a landscape mode display with top left -# adjactent to pin 36. +# adjacent to pin 36. # Supports: # TTGO T-Display 1.14" 135*240(Pixel) based on ST7789V @@ -46,7 +46,7 @@ BUTTON2 = 0 # left of the USB connector from machine import Pin, SPI, ADC import gc -from drivers.st7789.st7789_4bit import ST7789 as SSD, PORTRAIT, USD, REFLECT +from drivers.st7789.st7789_4bit import ST7789 as SSD, PORTRAIT, USD, REFLECT, LANDSCAPE pdc = Pin(TFT_DC, Pin.OUT, value=0) # Arbitrary pins pcs = Pin(TFT_CS, Pin.OUT, value=1) @@ -56,8 +56,29 @@ pbl = Pin(TFT_BL, Pin.OUT, value=1) gc.collect() # Precaution before instantiating framebuf # Conservative low baudrate. Can go to 62.5MHz. spi = SPI(1, 30_000_000, sck=Pin(TFT_SCLK), mosi=Pin(TFT_MOSI)) +# Tweaks for TTGO +OFFSET = (52, 40) +PORTRAIT, LANDSCAPE = LANDSCAPE, PORTRAIT # Hardware is portrait mode +# Landscape configs. +# Right way up landscape: defined as top left adjacent to pin 36 +# Normal display +ssd = SSD(spi, height=135, width=240, dc=pdc, cs=pcs, rst=prst, disp_mode=LANDSCAPE | REFLECT, offset=OFFSET) +# Reflected (mirror image) +# ssd = SSD(spi, height=135, width=240, dc=pdc, cs=pcs, rst=prst, disp_mode=LANDSCAPE | USD | REFLECT, offset=OFFSET) +# Upside down (USD) landscape top left close to pin 12 +# ssd = SSD(spi, height=135, width=240, dc=pdc, cs=pcs, rst=prst, disp_mode=LANDSCAPE | USD, offset=OFFSET) +# USD Reflected (mirror image) +# ssd = SSD(spi, height=135, width=240, dc=pdc, cs=pcs, rst=prst, disp_mode=LANDSCAPE, offset=OFFSET) -ssd = SSD(spi, height=135, width=240, dc=pdc, cs=pcs, rst=prst, disp_mode=PORTRAIT | REFLECT, offset=(40, 52)) +# Portrait configs. +# Normal portrait display +# ssd = SSD(spi, height=240, width=135, dc=pdc, cs=pcs, rst=prst, disp_mode=PORTRAIT, offset=OFFSET) +# Normal Reflected +# ssd = SSD(spi, height=240, width=135, dc=pdc, cs=pcs, rst=prst, disp_mode=PORTRAIT | REFLECT, offset=OFFSET) +# USD +# ssd = SSD(spi, height=240, width=135, dc=pdc, cs=pcs, rst=prst, disp_mode=PORTRAIT | USD | REFLECT, offset=OFFSET) +# USD Reflected +# ssd = SSD(spi, height=240, width=135, dc=pdc, cs=pcs, rst=prst, disp_mode=PORTRAIT | USD, offset=OFFSET) # optional # b1 = Pin(BUTTON1, Pin.IN) diff --git a/drivers/st7789/st7789_4bit.py b/drivers/st7789/st7789_4bit.py index d3395df..7af0706 100644 --- a/drivers/st7789/st7789_4bit.py +++ b/drivers/st7789/st7789_4bit.py @@ -67,7 +67,8 @@ class ST7789(framebuf.FrameBuffer): self._lock = asyncio.Lock() mode = framebuf.GS4_HMSB # Use 4bit greyscale. gc.collect() - buf = bytearray(height * width // 2) + #buf = bytearray(height * width // 2) + buf = bytearray(height * -(-width // 2)) # Ceiling division for odd widths self._mvb = memoryview(buf) super().__init__(buf, width, height, mode) self._linebuf = bytearray(self.width * 2) # 16 bit color out @@ -130,28 +131,41 @@ class ST7789(framebuf.FrameBuffer): wcd(b'\x36', int.to_bytes(disp_mode, 1, 'little')) cmd(b'\x29') # DISPON. Adafruit then delay 500ms. - # Define the mapping between RAM and the display - # May need modifying for non-Adafruit hardware which may use a different - # mapping between chip RAM and LCD. Datasheet section 8.12 p124. + # Define the mapping between RAM and the display. + # Datasheet section 8.12 p124. def set_window(self, mode): rht = 320 rwd = 240 # RAM ht and width - wht = self.height - wwd = self.width # Window dimensions - # Determine x and y start and end. Defaults for LANDSCAPE and PORTRAIT - xoff = self._offset[0] - xs = xoff - xe = wwd + xoff - 1 - yoff = self._offset[1] - ys = yoff # y start - ye = wht + yoff - 1 # y end - if mode & REFLECT: - ys = rwd - wht - yoff - ye = rwd - yoff - 1 - if mode & USD: - xs = rht - wwd - xoff - xe = rht - xoff - 1 - # Col address set. Add in any offset. + wht = self.height # Window (framebuf) dimensions. + wwd = self.width # In portrait mode wht > wwd + if mode & PORTRAIT: + xoff = self._offset[1] # x and y transposed + yoff = self._offset[0] + xs = xoff + xe = wwd + xoff - 1 + ys = yoff # y start + ye = wht + yoff - 1 # y end + if mode & REFLECT: + ys = rwd - wht - yoff + ye = rwd - yoff - 1 + if mode & USD: + xs = rht - wwd - xoff + xe = rht - xoff - 1 + else: # LANDSCAPE + xoff = self._offset[0] + yoff = self._offset[1] + xs = xoff + xe = wwd + xoff - 1 + ys = yoff # y start + ye = wht + yoff - 1 # y end + if mode & USD: + ys = rht - wht - yoff + ye = rht - yoff - 1 + if mode & REFLECT: + xs = rwd - wwd - xoff + xe = rwd - xoff - 1 + + # Col address set. self._wcd(b'\x2a', int.to_bytes(xs, 2, 'big') + int.to_bytes(xe, 2, 'big')) # Row address set self._wcd(b'\x2b', int.to_bytes(ys, 2, 'big') + int.to_bytes(ye, 2, 'big')) @@ -160,7 +174,8 @@ class ST7789(framebuf.FrameBuffer): def show(self): # Blocks for 83ms @60MHz SPI #ts = ticks_us() clut = ST7789.lut - wd = self.width // 2 + #wd = self.width // 2 + wd = -(-self.width // 2) # Ceiling division for odd number widths end = self.height * wd lb = self._linebuf buf = self._mvb @@ -183,7 +198,8 @@ class ST7789(framebuf.FrameBuffer): if mod: raise ValueError('Invalid do_refresh arg.') clut = ST7789.lut - wd = self.width // 2 + #wd = self.width // 2 + wd = -(-self.width // 2) lb = self._linebuf buf = self._mvb line = 0