f
This commit is contained in:
312
st7789py.py
Normal file
312
st7789py.py
Normal file
@@ -0,0 +1,312 @@
|
||||
import time
|
||||
from micropython import const
|
||||
import ustruct as struct
|
||||
|
||||
# commands
|
||||
ST77XX_NOP = const(0x00)
|
||||
ST77XX_SWRESET = const(0x01)
|
||||
ST77XX_RDDID = const(0x04)
|
||||
ST77XX_RDDST = const(0x09)
|
||||
|
||||
ST77XX_SLPIN = const(0x10)
|
||||
ST77XX_SLPOUT = const(0x11)
|
||||
ST77XX_PTLON = const(0x12)
|
||||
ST77XX_NORON = const(0x13)
|
||||
|
||||
ST77XX_INVOFF = const(0x20)
|
||||
ST77XX_INVON = const(0x21)
|
||||
ST77XX_DISPOFF = const(0x28)
|
||||
ST77XX_DISPON = const(0x29)
|
||||
ST77XX_CASET = const(0x2A)
|
||||
ST77XX_RASET = const(0x2B)
|
||||
ST77XX_RAMWR = const(0x2C)
|
||||
ST77XX_RAMRD = const(0x2E)
|
||||
|
||||
ST77XX_PTLAR = const(0x30)
|
||||
ST77XX_COLMOD = const(0x3A)
|
||||
ST7789_MADCTL = const(0x36)
|
||||
|
||||
ST7789_MADCTL_MY = const(0x80)
|
||||
ST7789_MADCTL_MX = const(0x40)
|
||||
ST7789_MADCTL_MV = const(0x20)
|
||||
ST7789_MADCTL_ML = const(0x10)
|
||||
ST7789_MADCTL_BGR = const(0x08)
|
||||
ST7789_MADCTL_MH = const(0x04)
|
||||
ST7789_MADCTL_RGB = const(0x00)
|
||||
|
||||
ST7789_RDID1 = const(0xDA)
|
||||
ST7789_RDID2 = const(0xDB)
|
||||
ST7789_RDID3 = const(0xDC)
|
||||
ST7789_RDID4 = const(0xDD)
|
||||
|
||||
ColorMode_65K = const(0x50)
|
||||
ColorMode_262K = const(0x60)
|
||||
ColorMode_12bit = const(0x03)
|
||||
ColorMode_16bit = const(0x05)
|
||||
ColorMode_18bit = const(0x06)
|
||||
ColorMode_16M = const(0x07)
|
||||
|
||||
# Color definitions
|
||||
BLACK = const(0x0000)
|
||||
BLUE = const(0x001F)
|
||||
RED = const(0xF800)
|
||||
GREEN = const(0x07E0)
|
||||
CYAN = const(0x07FF)
|
||||
MAGENTA = const(0xF81F)
|
||||
YELLOW = const(0xFFE0)
|
||||
WHITE = const(0xFFFF)
|
||||
|
||||
_ENCODE_PIXEL = ">H"
|
||||
_ENCODE_POS = ">HH"
|
||||
_DECODE_PIXEL = ">BBB"
|
||||
|
||||
_BUFFER_SIZE = const(256)
|
||||
|
||||
|
||||
def delay_ms(ms):
|
||||
time.sleep_ms(ms)
|
||||
|
||||
|
||||
def color565(r, g=0, b=0):
|
||||
"""Convert red, green and blue values (0-255) into a 16-bit 565 encoding. As
|
||||
a convenience this is also available in the parent adafruit_rgb_display
|
||||
package namespace."""
|
||||
try:
|
||||
r, g, b = r # see if the first var is a tuple/list
|
||||
except TypeError:
|
||||
pass
|
||||
return (r & 0xf8) << 8 | (g & 0xfc) << 3 | b >> 3
|
||||
|
||||
|
||||
class ST77xx:
|
||||
def __init__(self, spi, width, height, reset, dc, cs=None, backlight=None,
|
||||
xstart=-1, ystart=-1):
|
||||
"""
|
||||
display = st7789.ST7789(
|
||||
SPI(1, baudrate=40000000, phase=0, polarity=1),
|
||||
240, 240,
|
||||
reset=machine.Pin(5, machine.Pin.OUT),
|
||||
dc=machine.Pin(2, machine.Pin.OUT),
|
||||
)
|
||||
|
||||
"""
|
||||
self.width = width
|
||||
self.height = height
|
||||
self.spi = spi
|
||||
if spi is None:
|
||||
import machine
|
||||
self.spi = machine.SPI(1, baudrate=40000000, phase=0, polarity=1)
|
||||
self.reset = reset
|
||||
self.dc = dc
|
||||
self.cs = cs
|
||||
self.backlight = backlight
|
||||
if xstart >= 0 and ystart >= 0:
|
||||
self.xstart = xstart
|
||||
self.ystart = ystart
|
||||
elif (self.width, self.height) == (240, 240):
|
||||
self.xstart = 0
|
||||
self.ystart = 0
|
||||
elif (self.width, self.height) == (135, 240):
|
||||
self.xstart = 52
|
||||
self.ystart = 40
|
||||
else:
|
||||
raise ValueError(
|
||||
"Unsupported display. Only 240x240 and 135x240 are supported "
|
||||
"without xstart and ystart provided"
|
||||
)
|
||||
|
||||
def dc_low(self):
|
||||
self.dc.off()
|
||||
|
||||
def dc_high(self):
|
||||
self.dc.on()
|
||||
|
||||
def reset_low(self):
|
||||
if self.reset:
|
||||
self.reset.off()
|
||||
|
||||
def reset_high(self):
|
||||
if self.reset:
|
||||
self.reset.on()
|
||||
|
||||
def cs_low(self):
|
||||
if self.cs:
|
||||
self.cs.off()
|
||||
|
||||
def cs_high(self):
|
||||
if self.cs:
|
||||
self.cs.on()
|
||||
|
||||
def write(self, command=None, data=None):
|
||||
"""SPI write to the device: commands and data"""
|
||||
self.cs_low()
|
||||
if command is not None:
|
||||
self.dc_low()
|
||||
self.spi.write(bytes([command]))
|
||||
if data is not None:
|
||||
self.dc_high()
|
||||
self.spi.write(data)
|
||||
self.cs_high()
|
||||
|
||||
def hard_reset(self):
|
||||
self.cs_low()
|
||||
self.reset_high()
|
||||
delay_ms(50)
|
||||
self.reset_low()
|
||||
delay_ms(50)
|
||||
self.reset_high()
|
||||
delay_ms(150)
|
||||
self.cs_high()
|
||||
|
||||
def soft_reset(self):
|
||||
self.write(ST77XX_SWRESET)
|
||||
delay_ms(150)
|
||||
|
||||
def sleep_mode(self, value):
|
||||
if value:
|
||||
self.write(ST77XX_SLPIN)
|
||||
else:
|
||||
self.write(ST77XX_SLPOUT)
|
||||
|
||||
def inversion_mode(self, value):
|
||||
if value:
|
||||
self.write(ST77XX_INVON)
|
||||
else:
|
||||
self.write(ST77XX_INVOFF)
|
||||
|
||||
def _set_color_mode(self, mode):
|
||||
self.write(ST77XX_COLMOD, bytes([mode & 0x77]))
|
||||
|
||||
def init(self, *args, **kwargs):
|
||||
self.hard_reset()
|
||||
self.soft_reset()
|
||||
self.sleep_mode(False)
|
||||
if self.backlight:
|
||||
self.backlight.on()
|
||||
|
||||
def _set_mem_access_mode(self, rotation, vert_mirror, horz_mirror, is_bgr):
|
||||
rotation &= 7
|
||||
value = {
|
||||
0: 0,
|
||||
1: ST7789_MADCTL_MX,
|
||||
2: ST7789_MADCTL_MY,
|
||||
3: ST7789_MADCTL_MX | ST7789_MADCTL_MY,
|
||||
4: ST7789_MADCTL_MV,
|
||||
5: ST7789_MADCTL_MV | ST7789_MADCTL_MX,
|
||||
6: ST7789_MADCTL_MV | ST7789_MADCTL_MY,
|
||||
7: ST7789_MADCTL_MV | ST7789_MADCTL_MX | ST7789_MADCTL_MY,
|
||||
}[rotation]
|
||||
|
||||
if vert_mirror:
|
||||
value = ST7789_MADCTL_ML
|
||||
elif horz_mirror:
|
||||
value = ST7789_MADCTL_MH
|
||||
|
||||
if is_bgr:
|
||||
value |= ST7789_MADCTL_BGR
|
||||
self.write(ST7789_MADCTL, bytes([value]))
|
||||
|
||||
def _encode_pos(self, x, y):
|
||||
"""Encode a postion into bytes."""
|
||||
return struct.pack(_ENCODE_POS, x, y)
|
||||
|
||||
def _encode_pixel(self, color):
|
||||
"""Encode a pixel color into bytes."""
|
||||
return struct.pack(_ENCODE_PIXEL, color)
|
||||
|
||||
def _set_columns(self, start, end):
|
||||
if start > end or end >= self.width:
|
||||
return
|
||||
start += self.xstart
|
||||
end += self.xstart
|
||||
self.write(ST77XX_CASET, self._encode_pos(start, end))
|
||||
|
||||
def _set_rows(self, start, end):
|
||||
if start > end or end >= self.height:
|
||||
return
|
||||
start += self.ystart
|
||||
end += self.ystart
|
||||
self.write(ST77XX_RASET, self._encode_pos(start, end))
|
||||
|
||||
def set_window(self, x0, y0, x1, y1):
|
||||
self._set_columns(x0, x1)
|
||||
self._set_rows(y0, y1)
|
||||
self.write(ST77XX_RAMWR)
|
||||
|
||||
def vline(self, x, y, length, color):
|
||||
self.fill_rect(x, y, 1, length, color)
|
||||
|
||||
def hline(self, x, y, length, color):
|
||||
self.fill_rect(x, y, length, 1, color)
|
||||
|
||||
def pixel(self, x, y, color):
|
||||
self.set_window(x, y, x, y)
|
||||
self.write(None, self._encode_pixel(color))
|
||||
|
||||
def blit_buffer(self, buffer, x, y, width, height):
|
||||
self.set_window(x, y, x + width - 1, y + height - 1)
|
||||
self.write(None, buffer)
|
||||
|
||||
def rect(self, x, y, w, h, color):
|
||||
self.hline(x, y, w, color)
|
||||
self.vline(x, y, h, color)
|
||||
self.vline(x + w - 1, y, h, color)
|
||||
self.hline(x, y + h - 1, w, color)
|
||||
|
||||
def fill_rect(self, x, y, width, height, color):
|
||||
self.set_window(x, y, x + width - 1, y + height - 1)
|
||||
chunks, rest = divmod(width * height, _BUFFER_SIZE)
|
||||
pixel = self._encode_pixel(color)
|
||||
self.dc_high()
|
||||
if chunks:
|
||||
data = pixel * _BUFFER_SIZE
|
||||
for _ in range(chunks):
|
||||
self.write(None, data)
|
||||
if rest:
|
||||
self.write(None, pixel * rest)
|
||||
|
||||
def fill(self, color):
|
||||
self.fill_rect(0, 0, self.width, self.height, color)
|
||||
|
||||
def line(self, x0, y0, x1, y1, color):
|
||||
# Line drawing function. Will draw a single pixel wide line starting at
|
||||
# x0, y0 and ending at x1, y1.
|
||||
steep = abs(y1 - y0) > abs(x1 - x0)
|
||||
if steep:
|
||||
x0, y0 = y0, x0
|
||||
x1, y1 = y1, x1
|
||||
if x0 > x1:
|
||||
x0, x1 = x1, x0
|
||||
y0, y1 = y1, y0
|
||||
dx = x1 - x0
|
||||
dy = abs(y1 - y0)
|
||||
err = dx // 2
|
||||
if y0 < y1:
|
||||
ystep = 1
|
||||
else:
|
||||
ystep = -1
|
||||
while x0 <= x1:
|
||||
if steep:
|
||||
self.pixel(y0, x0, color)
|
||||
else:
|
||||
self.pixel(x0, y0, color)
|
||||
err -= dy
|
||||
if err < 0:
|
||||
y0 += ystep
|
||||
err += dx
|
||||
x0 += 1
|
||||
|
||||
|
||||
class ST7789(ST77xx):
|
||||
def init(self, *, color_mode=ColorMode_65K | ColorMode_16bit):
|
||||
super().init()
|
||||
self._set_color_mode(color_mode)
|
||||
delay_ms(50)
|
||||
self._set_mem_access_mode(4, True, True, False)
|
||||
self.inversion_mode(True)
|
||||
delay_ms(10)
|
||||
self.write(ST77XX_NORON)
|
||||
delay_ms(10)
|
||||
self.fill(0)
|
||||
self.write(ST77XX_DISPON)
|
||||
delay_ms(500)
|
||||
Reference in New Issue
Block a user