3157bcc310
This driver was rewritten from scratch, borrowing some idioms from the SSD1306 driver to ensure an efficient implementation in uPy.
145 lines
3.7 KiB
Python
145 lines
3.7 KiB
Python
# MicroPython ST7789 display driver, currently only has an SPI interface
|
|
|
|
from micropython import const
|
|
from time import sleep_ms
|
|
|
|
# register definitions
|
|
_SWRESET = const(0x01)
|
|
_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)
|
|
|
|
class ST7789(object):
|
|
def __init__(self, width, height):
|
|
self.width = width
|
|
self.height = height
|
|
self.linebuffer = bytearray(2 * width)
|
|
self.init_display()
|
|
|
|
def init_display(self):
|
|
self.reset()
|
|
|
|
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)
|
|
sleep_ms(125)
|
|
|
|
def poweroff(self):
|
|
pass
|
|
|
|
def poweron(self):
|
|
pass
|
|
|
|
def contrast(self, contrast):
|
|
pass
|
|
|
|
def invert(self, invert):
|
|
if invert:
|
|
self.write_cmd(_INVON)
|
|
else:
|
|
self.write_cmd(_INVOFF)
|
|
|
|
def set_window(self, x=0, y=0, width=None, height=None):
|
|
if not width:
|
|
width = self.width
|
|
if not height:
|
|
height = self.height
|
|
|
|
xp = x + width - 1
|
|
yp = y + height - 1
|
|
|
|
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)
|
|
|
|
def fill(self, bg):
|
|
self.set_window()
|
|
|
|
# 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)
|
|
|
|
def rleblit(self, sx, sy, image, fg=0xffff, bg=0):
|
|
self.set_window()
|
|
|
|
# TODO: rework algorithm to allow us to reuse the line buffer
|
|
buf = bytearray(2*sx)
|
|
bp = 0
|
|
color = bg
|
|
|
|
for rl in image:
|
|
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)
|
|
sleep_ms(130)
|
|
|
|
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)
|