2020-01-23 19:59:43 +01:00
|
|
|
# MicroPython ST7789 display driver, currently only has an SPI interface
|
|
|
|
|
2020-01-31 20:36:55 +01:00
|
|
|
import micropython
|
|
|
|
|
2020-01-23 19:59:43 +01:00
|
|
|
from micropython import const
|
|
|
|
from time import sleep_ms
|
|
|
|
|
|
|
|
# register definitions
|
|
|
|
_SWRESET = const(0x01)
|
2020-02-01 21:20:30 +01:00
|
|
|
_SLPIN = const(0x10)
|
2020-01-23 19:59:43 +01:00
|
|
|
_SLPOUT = const(0x11)
|
|
|
|
_NORON = const(0x13)
|
|
|
|
_INVOFF = const(0x20)
|
|
|
|
_INVON = const(0x21)
|
|
|
|
_DISPON = const(0x29)
|
|
|
|
_CASET = const(0x2a)
|
|
|
|
_RASET = const(0x2b)
|
|
|
|
_RAMWR = const(0x2c)
|
|
|
|
_COLMOD = const(0x3a)
|
|
|
|
_MADCTL = const(0x36)
|
2020-01-21 23:10:50 +01:00
|
|
|
|
|
|
|
class ST7789(object):
|
2020-01-23 19:59:43 +01:00
|
|
|
def __init__(self, width, height):
|
|
|
|
self.width = width
|
|
|
|
self.height = height
|
|
|
|
self.linebuffer = bytearray(2 * width)
|
|
|
|
self.init_display()
|
2020-01-21 23:10:50 +01:00
|
|
|
|
2020-01-23 19:59:43 +01:00
|
|
|
def init_display(self):
|
2020-01-21 23:10:50 +01:00
|
|
|
self.reset()
|
|
|
|
|
2020-01-23 19:59:43 +01:00
|
|
|
self.write_cmd(_SLPOUT)
|
|
|
|
sleep_ms(10)
|
|
|
|
|
|
|
|
for cmd in (
|
|
|
|
(_COLMOD, b'\x05'), # MCU will send 16-bit RGB565
|
|
|
|
(_MADCTL, b'\x00'), # Left to right, top to bottom
|
|
|
|
#(_INVOFF, None), # Results in odd palette
|
|
|
|
(_INVON, None),
|
|
|
|
(_NORON, None),
|
|
|
|
):
|
|
|
|
self.write_cmd(cmd[0])
|
|
|
|
if cmd[1]:
|
|
|
|
self.write_data(cmd[1])
|
|
|
|
self.fill(0)
|
|
|
|
self.write_cmd(_DISPON)
|
2020-01-28 22:19:36 +01:00
|
|
|
|
|
|
|
# From the point we sent the SLPOUT there must be a
|
|
|
|
# 120ms gap before any subsequent SLPIN. In most cases
|
|
|
|
# (i.e. wen the SPI baud rate is slower than 8M then
|
|
|
|
# that time already elapsed as we zeroed the RAM).
|
|
|
|
#sleep_ms(125)
|
2020-01-23 19:59:43 +01:00
|
|
|
|
|
|
|
def poweroff(self):
|
2020-02-01 21:20:30 +01:00
|
|
|
self.write_cmd(_SLPIN)
|
|
|
|
sleep_ms(125)
|
2020-01-23 19:59:43 +01:00
|
|
|
|
|
|
|
def poweron(self):
|
2020-02-01 21:20:30 +01:00
|
|
|
self.write_cmd(_SLPOUT)
|
|
|
|
sleep_ms(125)
|
2020-01-23 19:59:43 +01:00
|
|
|
|
|
|
|
def contrast(self, contrast):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def invert(self, invert):
|
|
|
|
if invert:
|
|
|
|
self.write_cmd(_INVON)
|
2020-01-21 23:10:50 +01:00
|
|
|
else:
|
2020-01-23 19:59:43 +01:00
|
|
|
self.write_cmd(_INVOFF)
|
2020-01-21 23:10:50 +01:00
|
|
|
|
2020-01-23 19:59:43 +01:00
|
|
|
def set_window(self, x=0, y=0, width=None, height=None):
|
|
|
|
if not width:
|
|
|
|
width = self.width
|
|
|
|
if not height:
|
|
|
|
height = self.height
|
2020-01-21 23:10:50 +01:00
|
|
|
|
2020-01-23 19:59:43 +01:00
|
|
|
xp = x + width - 1
|
|
|
|
yp = y + height - 1
|
2020-01-21 23:10:50 +01:00
|
|
|
|
2020-01-23 19:59:43 +01:00
|
|
|
self.write_cmd(_CASET)
|
|
|
|
self.write_data(bytearray([x >> 8, x & 0xff, xp >> 8, xp & 0xff]))
|
|
|
|
self.write_cmd(_RASET)
|
|
|
|
self.write_data(bytearray([y >> 8, y & 0xff, yp >> 8, yp & 0xff]))
|
|
|
|
self.write_cmd(_RAMWR)
|
2020-01-21 23:10:50 +01:00
|
|
|
|
2020-01-23 19:59:43 +01:00
|
|
|
def fill(self, bg):
|
|
|
|
self.set_window()
|
2020-01-21 23:10:50 +01:00
|
|
|
|
2020-01-23 19:59:43 +01:00
|
|
|
# Populate the line buffer
|
|
|
|
for x in range(0, 2 * self.width, 2):
|
|
|
|
self.linebuffer[x] = bg >> 8
|
|
|
|
self.linebuffer[x+1] = bg & 0xff
|
|
|
|
for y in range(self.height):
|
|
|
|
self.write_data(self.linebuffer)
|
2020-01-21 23:10:50 +01:00
|
|
|
|
2020-01-28 19:34:00 +01:00
|
|
|
@micropython.native
|
2020-02-03 20:09:16 +01:00
|
|
|
def rleblit(self, image, pos=(0, 0), fg=0xffff, bg=0):
|
2020-01-23 23:00:42 +01:00
|
|
|
(sx, sy, rle) = image
|
2020-02-03 20:09:16 +01:00
|
|
|
self.set_window(pos[0], pos[1], sx, sy)
|
2020-01-21 23:10:50 +01:00
|
|
|
|
2020-01-23 23:00:42 +01:00
|
|
|
# TODO: rework algorithm to allow us to reuse the line buffer
|
2020-01-23 19:59:43 +01:00
|
|
|
buf = bytearray(2*sx)
|
|
|
|
bp = 0
|
|
|
|
color = bg
|
|
|
|
|
2020-01-23 23:00:42 +01:00
|
|
|
for rl in rle:
|
2020-01-23 19:59:43 +01:00
|
|
|
while rl:
|
|
|
|
buf[bp] = color >> 8
|
|
|
|
buf[bp+1] = color & 0xff
|
|
|
|
bp += 2
|
|
|
|
rl -= 1
|
|
|
|
|
|
|
|
if bp >= (2*sx):
|
|
|
|
self.write_data(buf)
|
|
|
|
bp = 0
|
|
|
|
|
|
|
|
if color == bg:
|
|
|
|
color = fg
|
|
|
|
else:
|
|
|
|
color = bg
|
|
|
|
|
|
|
|
class ST7789_SPI(ST7789):
|
|
|
|
def __init__(self, width, height, spi, cs, dc, res=None, rate=8000000):
|
|
|
|
self.spi = spi
|
|
|
|
self.dc = dc
|
|
|
|
self.res = res
|
|
|
|
self.cs = cs
|
|
|
|
self.rate = rate
|
|
|
|
|
|
|
|
#self.spi.init(baudrate=self.rate, polarity=1, phase=1)
|
|
|
|
cs.init(cs.OUT, value=1)
|
|
|
|
dc.init(dc.OUT, value=0)
|
|
|
|
if res:
|
|
|
|
res.init(res.OUT, value=0)
|
|
|
|
|
|
|
|
super().__init__(width, height)
|
|
|
|
|
|
|
|
def reset(self):
|
|
|
|
if self.res:
|
|
|
|
self.res(0)
|
|
|
|
sleep_ms(10)
|
|
|
|
self.res(1)
|
|
|
|
else:
|
|
|
|
self.write_cmd(_SWRESET)
|
2020-02-01 21:20:30 +01:00
|
|
|
sleep_ms(125)
|
2020-01-23 19:59:43 +01:00
|
|
|
|
|
|
|
def write_cmd(self, cmd):
|
|
|
|
self.dc(0)
|
|
|
|
self.cs(0)
|
|
|
|
self.spi.write(bytearray([cmd]))
|
|
|
|
self.cs(1)
|
|
|
|
|
|
|
|
def write_data(self, buf):
|
|
|
|
self.dc(1)
|
|
|
|
self.cs(0)
|
|
|
|
self.spi.write(buf)
|
|
|
|
self.cs(1)
|