st7735r driver works on 160 wide display only.

ili9341
Peter Hinch 2020-11-25 14:25:25 +00:00
rodzic 33c91aa3d8
commit 62ff95dbd3
3 zmienionych plików z 200 dodań i 4 usunięć

Wyświetl plik

@ -53,7 +53,8 @@ wiring details, pin names and hardware issues.
3.7 [Class Textbox](./README.md#37-class-textbox) Scrolling text display.
4. [Device drivers](./README.md#4-device-drivers) Device driver compatibility
requirements (these are minimal).
5. [ESP8266](./README.md#5-esp8266) This can work.
5. [ESP8266](./README.md#5-esp8266) This can work. Contains information on
minimising the RAM and flash footprints of the GUI.
# 1. Introduction
@ -159,6 +160,10 @@ Installation comprises copying the `gui` and `drivers` directories, with their
contents, plus a hardware configuration file, to the target. The directory
structure on the target must match that in the repo.
In the interests of conserving RAM, supplied drivers support only the
functionality required by the GUI. More fully featured drivers may better suit
other applications. See [section 4](./README.md#4-device-drivers).
Filesystem space may be conserved by copying only the required driver from
`drivers`, but the directory path to that file must be retained. For example,
for SSD1351 displays only the following are actually required:
@ -785,8 +790,14 @@ the oldest (topmost) being discarded as required.
# 4. Device drivers
Device drivers capable of supporting `nanogui` can be extremely simple: see the
`drivers/sharp/sharp.py` for a minimal example.
Device drivers capable of supporting `nanogui` can be extremely simple: see
`drivers/sharp/sharp.py` for a minimal example. It should be noted that the
supplied device drivers are designed purely to support nanogui. To conserve RAM
they provide for the transfer of an external frame buffer to the device and
little else. Such a transfer typically takes a few tens of milliseconds. Many
driver chips support graphics primitives in hardware. In performance orientated
applications such as games, drivers using these capabilities will be faster
than those provided here.
For a driver to support `nanogui` it must be subclassed from
`framebuf.FrameBuffer` and provide `height` and `width` bound variables being
@ -800,7 +811,7 @@ hardware.
For color drivers, to conserve RAM it is suggested that 8-bit color is used
for the `framebuf`. If the hardware does not support this, conversion to the
supported color space needs to be done "on the fly" as per the SSD1351 driver.
Since this is likely to be slow, consider using native, viper or assembler.
To maximise update speed consider using native, viper or assembler.
Color drivers should have a static method converting rgb(255, 255, 255) to a
form acceptable to the driver. For 8-bit rrrgggbb this can be:

Wyświetl plik

@ -0,0 +1,146 @@
# st7735r.py Driver for ST7735R LCD displays for nano-gui
# Released under the MIT License (MIT). See LICENSE.
# Copyright (c) 2018-2020 Peter Hinch
# Supported displays
# Adfruit 1.8' Color TFT LCD display with MicroSD Card Breakout:
# https://www.adafruit.com/product/358
# Adafruit 1.44' Color TFT LCD Display with MicroSD Card breakout:
# https://www.adafruit.com/product/2088
# Based on
# https://github.com/adafruit/Adafruit_CircuitPython_ST7735R/blob/master/adafruit_st7735r.py
# https://github.com/GuyCarver/MicroPython/blob/master/lib/ST7735.py
# https://github.com/boochow/MicroPython-ST7735
from time import sleep_ms
import framebuf
import gc
import micropython
# Datasheet para 8.4 scl write cycle 66ns == 15MHz
# _lcopy: copy a line in 8 bit format to one in 12 bit RGB444. para 9.8.20.
# 2 bytes become 3 in destination. Source format:
# < D7 D6 D5 D4 D3 D2 D1 D0>
# <R02 R01 R00 G02 G01 G00 B01 B00> <R12 R11 R10 G12 G11 G10 B11 B10>
# dest:
# <R02 R01 R00 0 G02 G01 G00 0> <B01 B00 0 0 R12 R11 R10 0> <G12 G11 G10 0 B11 B10 0 0>
@micropython.viper
def _lcopy(dest:ptr8, source:ptr8, length:int):
n = 0
for x in range(0, length, 2):
c = source[x]
d = source[x + 1]
dest[n] = (c & 0xe0) | ((c & 0x1c) >> 1) # R0 G0
n += 1
dest[n] = ((c & 3) << 6) | ((d & 0xe0) >> 4) # B0 R1
n += 1
dest[n] = ((d & 0x1c) << 3) | ((d & 3) << 2) # G1 B1
n += 1
class ST7735R(framebuf.FrameBuffer):
# Convert r, g, b in range 0-255 to an 8 bit colour value
# rrrgggbb. Converted to 12 bit on the fly.
@staticmethod
def rgb(r, g, b):
return (r & 0xe0) | ((g >> 3) & 0x1c) | (b >> 6)
# rst and cs are active low, SPI is mode 0
def __init__(self, spi, cs, dc, rst, height=128, width=128):
self._spi = spi
self._rst = rst # Pins
self._dc = dc
self._cs = cs
self.height = height # Required by Writer class
self.width = width
# Save color mode for use by writer_gui (blit)
self.mode = framebuf.GS8 # Use 8bit greyscale for 8 bit color.
gc.collect()
self.buffer = bytearray(self.height * self.width)
self._mvb = memoryview(self.buffer)
super().__init__(self.buffer, self.width, self.height, self.mode)
self._linebuf = bytearray(int(self.width * 3 // 2)) # 12 bit color out
self._init()
self.show()
# Hardware reset
def _hwreset(self):
self._dc(0)
self._rst(1)
sleep_ms(1)
self._rst(0)
sleep_ms(1)
self._rst(1)
sleep_ms(1)
# Write a command, a bytes instance (in practice 1 byte).
def _wcmd(self, buf):
self._dc(0)
self._cs(0)
self._spi.write(buf)
self._cs(1)
# Write a command followed by a data arg.
def _wcd(self, c, d):
self._dc(0)
self._cs(0)
self._spi.write(c)
self._cs(1)
self._dc(1)
self._cs(0)
self._spi.write(d)
self._cs(1)
# Initialise the hardware. Blocks 500ms.
def _init(self):
self._hwreset() # Hardware reset. Blocks 3ms
cmd = self._wcmd
wcd = self._wcd
cmd(b'\x01') # SW reset datasheet specifies > 120ms
sleep_ms(150)
cmd(b'\x11') # SLPOUT
sleep_ms(256) # Adafruit delay (datsheet 120ms)
wcd(b'\xb1', b'\x01\x2C\x2D') # FRMCTRL1
wcd(b'\xb2', b'\x01\x2C\x2D') # FRMCTRL2
wcd(b'\xb3', b'\x01\x2C\x2D\x01\x2C\x2D') # FRMCTRL3
wcd(b'\xb4', b'\x07') # INVCTR line inversion
wcd(b'\xc0', b'\xa2\x02\x84') # PWCTR1 GVDD = 4.7V, 1.0uA
wcd(b'\xc1', b'\xc5') # PWCTR2 VGH=14.7V, VGL=-7.35V
wcd(b'\xc2', b'\x0a\x00') # PWCTR3 Opamp current small, Boost frequency
wcd(b'\xc3', b'\x8a\x2a') # PWCTR4
wcd(b'\xc4', b'\x8a\xee') # PWCTR5
wcd(b'\xc5', b'\x0e') # VMCTR1 VCOMH = 4V, VOML = -1.1V NOTE I make VCOM == -0.775V
cmd(b'\x20') # INVOFF
# d7..d5 of MADCTL determine rotation/orientation
wcd(b'\x36', b'\x20') # MADCTL: RGB landscape mode
wcd(b'\x3a', b'\x03') # COLMOD 12 bit
wcd(b'\xe0', b'\x02\x1c\x07\x12\x37\x32\x29\x2d\x29\x25\x2B\x39\x00\x01\x03\x10') # GMCTRP1 Gamma
wcd(b'\xe1', b'\x03\x1d\x07\x06\x2E\x2C\x29\x2D\x2E\x2E\x37\x3F\x00\x00\x02\x10') # GMCTRN1
wcd(b'\x2a', int.to_bytes(self.width, 4, 'big')) # CASET column address 0 start, 160/128 end
wcd(b'\x2b', int.to_bytes(self.height, 4, 'big')) # RASET
cmd(b'\x13') # NORON
sleep_ms(10)
cmd(b'\x29') # DISPON
sleep_ms(100)
def show(self): # Blocks 36ms on Pyboard D at stock frequency (160*128)
wd = self.width
ht = self.height
lb = self._linebuf
buf = self._mvb
self._dc(0)
self._cs(0)
self._spi.write(b'\x2c') # RAMWR
self._dc(1)
for start in range(wd * (ht - 1), -1, - wd): # For each line
_lcopy(lb, buf[start :], wd) # Copy and map colors (68us)
self._spi.write(lb)
self._cs(1)

39
st7735r_setup.py 100644
Wyświetl plik

@ -0,0 +1,39 @@
# st7735r_setup.py Customise for your hardware config
# Released under the MIT License (MIT). See LICENSE.
# Copyright (c) 2020 Peter Hinch
# As written, supports:
# Adfruit 1.8' Color TFT LCD display with MicroSD Card Breakout:
# https://www.adafruit.com/product/358
# Adafruit 1.44' Color TFT LCD Display with MicroSD Card breakout:
# https://www.adafruit.com/product/2088
# Demo of initialisation procedure designed to minimise risk of memory fail
# when instantiating the frame buffer. The aim is to do this as early as
# possible before importing other modules.
# WIRING (Adafruit pin nos and names).
# Pyb SSD
# 3v3 Vin (10)
# Gnd Gnd (11)
# Y1 DC (3 DC)
# Y2 CS (5 OC OLEDCS)
# Y3 Rst (4 R RESET)
# Y6 CLK (2 CL SCK)
# Y8 DATA (1 SI MOSI)
import machine
import gc
from drivers.st7735r.st7735r import ST7735R as SSD
height = 128
width = 128
pdc = machine.Pin('Y1', machine.Pin.OUT_PP, value=0)
pcs = machine.Pin('Y2', machine.Pin.OUT_PP, value=1)
prst = machine.Pin('Y3', machine.Pin.OUT_PP, value=1)
spi = machine.SPI(2, baudrate=12_000_000)
gc.collect() # Precaution before instantiating framebuf
ssd = SSD(spi, pcs, pdc, prst, height, width) # Create a display instance