adds the correct driver, as the IL driver wasn't cut out for the job
This commit is contained in:
parent
5ed20aef7f
commit
59daa25a91
2 changed files with 1253 additions and 68 deletions
939
src/ST7735.py
Normal file
939
src/ST7735.py
Normal file
|
@ -0,0 +1,939 @@
|
||||||
|
#driver for Sainsmart 1.8" TFT display ST7735
|
||||||
|
#Translated by Guy Carver from the ST7735 sample code.
|
||||||
|
#Modirfied for micropython-esp32 by boochow
|
||||||
|
|
||||||
|
import machine
|
||||||
|
import time
|
||||||
|
from math import sqrt
|
||||||
|
from sysfont import sysfont
|
||||||
|
#TFTRotations and TFTRGB are bits to set
|
||||||
|
# on MADCTL to control display rotation/color layout
|
||||||
|
#Looking at display with pins on top.
|
||||||
|
#00 = upper left printing right
|
||||||
|
#10 = does nothing (MADCTL_ML)
|
||||||
|
#20 = upper left printing down (backwards) (Vertical flip)
|
||||||
|
#40 = upper right printing left (backwards) (X Flip)
|
||||||
|
#80 = lower left printing right (backwards) (Y Flip)
|
||||||
|
#04 = (MADCTL_MH)
|
||||||
|
|
||||||
|
#60 = 90 right rotation
|
||||||
|
#C0 = 180 right rotation
|
||||||
|
#A0 = 270 right rotation
|
||||||
|
TFTRotations = [0x00, 0x60, 0xC0, 0xA0]
|
||||||
|
TFTBGR = 0x08 #When set color is bgr else rgb.
|
||||||
|
TFTRGB = 0x00
|
||||||
|
|
||||||
|
#@micropython.native
|
||||||
|
def clamp( aValue, aMin, aMax ) :
|
||||||
|
return max(aMin, min(aMax, aValue))
|
||||||
|
|
||||||
|
#@micropython.native
|
||||||
|
def TFTColor( aR, aG, aB ) :
|
||||||
|
'''Create a 16 bit rgb value from the given R,G,B from 0-255.
|
||||||
|
This assumes rgb 565 layout and will be incorrect for bgr.'''
|
||||||
|
return ((aR & 0xF8) << 8) | ((aG & 0xFC) << 3) | (aB >> 3)
|
||||||
|
|
||||||
|
ScreenSize = (128, 160)
|
||||||
|
|
||||||
|
class TFT(object) :
|
||||||
|
"""Sainsmart TFT 7735 display driver."""
|
||||||
|
|
||||||
|
NOP = 0x0
|
||||||
|
SWRESET = 0x01
|
||||||
|
RDDID = 0x04
|
||||||
|
RDDST = 0x09
|
||||||
|
|
||||||
|
SLPIN = 0x10
|
||||||
|
SLPOUT = 0x11
|
||||||
|
PTLON = 0x12
|
||||||
|
NORON = 0x13
|
||||||
|
|
||||||
|
INVOFF = 0x20
|
||||||
|
INVON = 0x21
|
||||||
|
DISPOFF = 0x28
|
||||||
|
DISPON = 0x29
|
||||||
|
CASET = 0x2A
|
||||||
|
RASET = 0x2B
|
||||||
|
RAMWR = 0x2C
|
||||||
|
RAMRD = 0x2E
|
||||||
|
|
||||||
|
VSCRDEF = 0x33
|
||||||
|
VSCSAD = 0x37
|
||||||
|
|
||||||
|
COLMOD = 0x3A
|
||||||
|
MADCTL = 0x36
|
||||||
|
|
||||||
|
FRMCTR1 = 0xB1
|
||||||
|
FRMCTR2 = 0xB2
|
||||||
|
FRMCTR3 = 0xB3
|
||||||
|
INVCTR = 0xB4
|
||||||
|
DISSET5 = 0xB6
|
||||||
|
|
||||||
|
PWCTR1 = 0xC0
|
||||||
|
PWCTR2 = 0xC1
|
||||||
|
PWCTR3 = 0xC2
|
||||||
|
PWCTR4 = 0xC3
|
||||||
|
PWCTR5 = 0xC4
|
||||||
|
VMCTR1 = 0xC5
|
||||||
|
|
||||||
|
RDID1 = 0xDA
|
||||||
|
RDID2 = 0xDB
|
||||||
|
RDID3 = 0xDC
|
||||||
|
RDID4 = 0xDD
|
||||||
|
|
||||||
|
PWCTR6 = 0xFC
|
||||||
|
|
||||||
|
GMCTRP1 = 0xE0
|
||||||
|
GMCTRN1 = 0xE1
|
||||||
|
|
||||||
|
BLACK = 0
|
||||||
|
RED = TFTColor(0xFF, 0x00, 0x00)
|
||||||
|
MAROON = TFTColor(0x80, 0x00, 0x00)
|
||||||
|
GREEN = TFTColor(0x00, 0xFF, 0x00)
|
||||||
|
FOREST = TFTColor(0x00, 0x80, 0x80)
|
||||||
|
BLUE = TFTColor(0x00, 0x00, 0xFF)
|
||||||
|
NAVY = TFTColor(0x00, 0x00, 0x80)
|
||||||
|
CYAN = TFTColor(0x00, 0xFF, 0xFF)
|
||||||
|
YELLOW = TFTColor(0xFF, 0xFF, 0x00)
|
||||||
|
PURPLE = TFTColor(0xFF, 0x00, 0xFF)
|
||||||
|
WHITE = TFTColor(0xFF, 0xFF, 0xFF)
|
||||||
|
GRAY = TFTColor(0x80, 0x80, 0x80)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def color( aR, aG, aB ) :
|
||||||
|
'''Create a 565 rgb TFTColor value'''
|
||||||
|
return TFTColor(aR, aG, aB)
|
||||||
|
|
||||||
|
def __init__( self, spi, aDC, aReset, aCS) :
|
||||||
|
"""aLoc SPI pin location is either 1 for 'X' or 2 for 'Y'.
|
||||||
|
aDC is the DC pin and aReset is the reset pin."""
|
||||||
|
self._size = ScreenSize
|
||||||
|
self._offset = bytearray([0,0])
|
||||||
|
self.rotate = 0 #Vertical with top toward pins.
|
||||||
|
self._rgb = True #color order of rgb.
|
||||||
|
self.tfa = 0 #top fixed area
|
||||||
|
self.bfa = 0 #bottom fixed area
|
||||||
|
self.dc = machine.Pin(aDC, machine.Pin.OUT, machine.Pin.PULL_DOWN)
|
||||||
|
self.reset = machine.Pin(aReset, machine.Pin.OUT, machine.Pin.PULL_DOWN)
|
||||||
|
self.cs = machine.Pin(aCS, machine.Pin.OUT, machine.Pin.PULL_DOWN)
|
||||||
|
self.cs(1)
|
||||||
|
self.spi = spi
|
||||||
|
self.colorData = bytearray(2)
|
||||||
|
self.windowLocData = bytearray(4)
|
||||||
|
self.x = 0
|
||||||
|
self.y = 0
|
||||||
|
|
||||||
|
def size( self ) :
|
||||||
|
return self._size
|
||||||
|
|
||||||
|
# @micropython.native
|
||||||
|
def on( self, aTF = True ) :
|
||||||
|
'''Turn display on or off.'''
|
||||||
|
self._writecommand(TFT.DISPON if aTF else TFT.DISPOFF)
|
||||||
|
|
||||||
|
# @micropython.native
|
||||||
|
def invertcolor( self, aBool ) :
|
||||||
|
'''Invert the color data IE: Black = White.'''
|
||||||
|
self._writecommand(TFT.INVON if aBool else TFT.INVOFF)
|
||||||
|
def set_pos(self,x,y):
|
||||||
|
self.x = x
|
||||||
|
self.y = y
|
||||||
|
# @micropython.native
|
||||||
|
def rgb( self, aTF = True ) :
|
||||||
|
'''True = rgb else bgr'''
|
||||||
|
self._rgb = aTF
|
||||||
|
self._setMADCTL()
|
||||||
|
|
||||||
|
# @micropython.native
|
||||||
|
def rotation( self, aRot ) :
|
||||||
|
'''0 - 3. Starts vertical with top toward pins and rotates 90 deg
|
||||||
|
clockwise each step.'''
|
||||||
|
if (0 <= aRot < 4):
|
||||||
|
rotchange = self.rotate ^ aRot
|
||||||
|
self.rotate = aRot
|
||||||
|
#If switching from vertical to horizontal swap x,y
|
||||||
|
# (indicated by bit 0 changing).
|
||||||
|
if (rotchange & 1):
|
||||||
|
self._size =(self._size[1], self._size[0])
|
||||||
|
self._setMADCTL()
|
||||||
|
|
||||||
|
# @micropython.native
|
||||||
|
def pixel( self, aPos, aColor ) :
|
||||||
|
'''Draw a pixel at the given position'''
|
||||||
|
if 0 <= aPos[0] < self._size[0] and 0 <= aPos[1] < self._size[1]:
|
||||||
|
self._setwindowpoint(aPos)
|
||||||
|
self._pushcolor(aColor)
|
||||||
|
|
||||||
|
# @micropython.native
|
||||||
|
def print(self,text,color=RED,font=sysfont,size = 1,nowrap = False ):
|
||||||
|
self.text((self.x,self.y),text,color,sysfont,size,False)
|
||||||
|
# @micropython.native
|
||||||
|
def text( self, aPos, aString, aColor, aFont, aSize = 1, nowrap = False ) :
|
||||||
|
'''Draw a text at the given position. If the string reaches the end of the
|
||||||
|
display it is wrapped to aPos[0] on the next line. aSize may be an integer
|
||||||
|
which will size the font uniformly on w,h or a or any type that may be
|
||||||
|
indexed with [0] or [1].'''
|
||||||
|
|
||||||
|
if aFont == None:
|
||||||
|
return
|
||||||
|
|
||||||
|
#Make a size either from single value or 2 elements.
|
||||||
|
if (type(aSize) == int) or (type(aSize) == float):
|
||||||
|
wh = (aSize, aSize)
|
||||||
|
else:
|
||||||
|
wh = aSize
|
||||||
|
|
||||||
|
px, py = aPos
|
||||||
|
width = wh[0] * aFont["Width"] + 1
|
||||||
|
for c in aString:
|
||||||
|
self.char((px, py), c, aColor, aFont, wh)
|
||||||
|
px += width
|
||||||
|
self.x += width
|
||||||
|
#We check > rather than >= to let the right (blank) edge of the
|
||||||
|
# character print off the right of the screen.
|
||||||
|
if px + width > self._size[0]:
|
||||||
|
if nowrap:
|
||||||
|
self.y += aFont["Height"] * wh[1] + 1
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
py += aFont["Height"] * wh[1] + 1
|
||||||
|
self.y += aFont["Height"] * wh[1] + 1
|
||||||
|
px = aPos[0]
|
||||||
|
self.x = aPos[0]
|
||||||
|
self.x = 0
|
||||||
|
self.y += aFont["Height"] * wh[1] + 1
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# @micropython.native
|
||||||
|
def char( self, aPos, aChar, aColor, aFont, aSizes ) :
|
||||||
|
'''Draw a character at the given position using the given font and color.
|
||||||
|
aSizes is a tuple with x, y as integer scales indicating the
|
||||||
|
# of pixels to draw for each pixel in the character.'''
|
||||||
|
|
||||||
|
if aFont == None:
|
||||||
|
return
|
||||||
|
|
||||||
|
startchar = aFont['Start']
|
||||||
|
endchar = aFont['End']
|
||||||
|
|
||||||
|
ci = ord(aChar)
|
||||||
|
if (startchar <= ci <= endchar):
|
||||||
|
fontw = aFont['Width']
|
||||||
|
fonth = aFont['Height']
|
||||||
|
ci = (ci - startchar) * fontw
|
||||||
|
|
||||||
|
charA = aFont["Data"][ci:ci + fontw]
|
||||||
|
px = aPos[0]
|
||||||
|
if aSizes[0] <= 1 and aSizes[1] <= 1 :
|
||||||
|
buf = bytearray(2 * fonth * fontw)
|
||||||
|
for q in range(fontw) :
|
||||||
|
c = charA[q]
|
||||||
|
for r in range(fonth) :
|
||||||
|
if c & 0x01 :
|
||||||
|
pos = 2 * (r * fontw + q)
|
||||||
|
buf[pos] = aColor >> 8
|
||||||
|
buf[pos + 1] = aColor & 0xff
|
||||||
|
c >>= 1
|
||||||
|
self.image(aPos[0], aPos[1], aPos[0] + fontw - 1, aPos[1] + fonth - 1, buf)
|
||||||
|
else:
|
||||||
|
for c in charA :
|
||||||
|
py = aPos[1]
|
||||||
|
for r in range(fonth) :
|
||||||
|
if c & 0x01 :
|
||||||
|
self.fillrect((px, py), aSizes, aColor)
|
||||||
|
py += aSizes[1]
|
||||||
|
c >>= 1
|
||||||
|
px += aSizes[0]
|
||||||
|
|
||||||
|
# @micropython.native
|
||||||
|
def line( self, aStart, aEnd, aColor ) :
|
||||||
|
'''Draws a line from aStart to aEnd in the given color. Vertical or horizontal
|
||||||
|
lines are forwarded to vline and hline.'''
|
||||||
|
if aStart[0] == aEnd[0]:
|
||||||
|
#Make sure we use the smallest y.
|
||||||
|
pnt = aEnd if (aEnd[1] < aStart[1]) else aStart
|
||||||
|
self.vline(pnt, abs(aEnd[1] - aStart[1]) + 1, aColor)
|
||||||
|
elif aStart[1] == aEnd[1]:
|
||||||
|
#Make sure we use the smallest x.
|
||||||
|
pnt = aEnd if aEnd[0] < aStart[0] else aStart
|
||||||
|
self.hline(pnt, abs(aEnd[0] - aStart[0]) + 1, aColor)
|
||||||
|
else:
|
||||||
|
px, py = aStart
|
||||||
|
ex, ey = aEnd
|
||||||
|
dx = ex - px
|
||||||
|
dy = ey - py
|
||||||
|
inx = 1 if dx > 0 else -1
|
||||||
|
iny = 1 if dy > 0 else -1
|
||||||
|
|
||||||
|
dx = abs(dx)
|
||||||
|
dy = abs(dy)
|
||||||
|
if (dx >= dy):
|
||||||
|
dy <<= 1
|
||||||
|
e = dy - dx
|
||||||
|
dx <<= 1
|
||||||
|
while (px != ex):
|
||||||
|
self.pixel((px, py), aColor)
|
||||||
|
if (e >= 0):
|
||||||
|
py += iny
|
||||||
|
e -= dx
|
||||||
|
e += dy
|
||||||
|
px += inx
|
||||||
|
else:
|
||||||
|
dx <<= 1
|
||||||
|
e = dx - dy
|
||||||
|
dy <<= 1
|
||||||
|
while (py != ey):
|
||||||
|
self.pixel((px, py), aColor)
|
||||||
|
if (e >= 0):
|
||||||
|
px += inx
|
||||||
|
e -= dy
|
||||||
|
e += dx
|
||||||
|
py += iny
|
||||||
|
|
||||||
|
# @micropython.native
|
||||||
|
def vline( self, aStart, aLen, aColor ) :
|
||||||
|
'''Draw a vertical line from aStart for aLen. aLen may be negative.'''
|
||||||
|
start = (clamp(aStart[0], 0, self._size[0]), clamp(aStart[1], 0, self._size[1]))
|
||||||
|
stop = (start[0], clamp(start[1] + aLen, 0, self._size[1]))
|
||||||
|
#Make sure smallest y 1st.
|
||||||
|
if (stop[1] < start[1]):
|
||||||
|
start, stop = stop, start
|
||||||
|
self._setwindowloc(start, stop)
|
||||||
|
self._setColor(aColor)
|
||||||
|
self._draw(aLen)
|
||||||
|
|
||||||
|
# @micropython.native
|
||||||
|
def hline( self, aStart, aLen, aColor ) :
|
||||||
|
'''Draw a horizontal line from aStart for aLen. aLen may be negative.'''
|
||||||
|
start = (clamp(aStart[0], 0, self._size[0]), clamp(aStart[1], 0, self._size[1]))
|
||||||
|
stop = (clamp(start[0] + aLen, 0, self._size[0]), start[1])
|
||||||
|
#Make sure smallest x 1st.
|
||||||
|
if (stop[0] < start[0]):
|
||||||
|
start, stop = stop, start
|
||||||
|
self._setwindowloc(start, stop)
|
||||||
|
self._setColor(aColor)
|
||||||
|
self._draw(aLen)
|
||||||
|
|
||||||
|
# @micropython.native
|
||||||
|
def rect( self, aStart, aSize, aColor ) :
|
||||||
|
'''Draw a hollow rectangle. aStart is the smallest coordinate corner
|
||||||
|
and aSize is a tuple indicating width, height.'''
|
||||||
|
self.hline(aStart, aSize[0], aColor)
|
||||||
|
self.hline((aStart[0], aStart[1] + aSize[1] - 1), aSize[0], aColor)
|
||||||
|
self.vline(aStart, aSize[1], aColor)
|
||||||
|
self.vline((aStart[0] + aSize[0] - 1, aStart[1]), aSize[1], aColor)
|
||||||
|
|
||||||
|
# @micropython.native
|
||||||
|
def fillrect( self, aStart, aSize, aColor ) :
|
||||||
|
'''Draw a filled rectangle. aStart is the smallest coordinate corner
|
||||||
|
and aSize is a tuple indicating width, height.'''
|
||||||
|
start = (clamp(aStart[0], 0, self._size[0]), clamp(aStart[1], 0, self._size[1]))
|
||||||
|
end = (clamp(start[0] + aSize[0] - 1, 0, self._size[0]), clamp(start[1] + aSize[1] - 1, 0, self._size[1]))
|
||||||
|
|
||||||
|
if (end[0] < start[0]):
|
||||||
|
tmp = end[0]
|
||||||
|
end = (start[0], end[1])
|
||||||
|
start = (tmp, start[1])
|
||||||
|
if (end[1] < start[1]):
|
||||||
|
tmp = end[1]
|
||||||
|
end = (end[0], start[1])
|
||||||
|
start = (start[0], tmp)
|
||||||
|
|
||||||
|
self._setwindowloc(start, end)
|
||||||
|
numPixels = (end[0] - start[0] + 1) * (end[1] - start[1] + 1)
|
||||||
|
self._setColor(aColor)
|
||||||
|
self._draw(numPixels)
|
||||||
|
|
||||||
|
# @micropython.native
|
||||||
|
def circle( self, aPos, aRadius, aColor ) :
|
||||||
|
'''Draw a hollow circle with the given radius and color with aPos as center.'''
|
||||||
|
self.colorData[0] = aColor >> 8
|
||||||
|
self.colorData[1] = aColor
|
||||||
|
xend = int(0.7071 * aRadius) + 1
|
||||||
|
rsq = aRadius * aRadius
|
||||||
|
for x in range(xend) :
|
||||||
|
y = int(sqrt(rsq - x * x))
|
||||||
|
xp = aPos[0] + x
|
||||||
|
yp = aPos[1] + y
|
||||||
|
xn = aPos[0] - x
|
||||||
|
yn = aPos[1] - y
|
||||||
|
xyp = aPos[0] + y
|
||||||
|
yxp = aPos[1] + x
|
||||||
|
xyn = aPos[0] - y
|
||||||
|
yxn = aPos[1] - x
|
||||||
|
|
||||||
|
self._setwindowpoint((xp, yp))
|
||||||
|
self._writedata(self.colorData)
|
||||||
|
self._setwindowpoint((xp, yn))
|
||||||
|
self._writedata(self.colorData)
|
||||||
|
self._setwindowpoint((xn, yp))
|
||||||
|
self._writedata(self.colorData)
|
||||||
|
self._setwindowpoint((xn, yn))
|
||||||
|
self._writedata(self.colorData)
|
||||||
|
self._setwindowpoint((xyp, yxp))
|
||||||
|
self._writedata(self.colorData)
|
||||||
|
self._setwindowpoint((xyp, yxn))
|
||||||
|
self._writedata(self.colorData)
|
||||||
|
self._setwindowpoint((xyn, yxp))
|
||||||
|
self._writedata(self.colorData)
|
||||||
|
self._setwindowpoint((xyn, yxn))
|
||||||
|
self._writedata(self.colorData)
|
||||||
|
|
||||||
|
# @micropython.native
|
||||||
|
def fillcircle( self, aPos, aRadius, aColor ) :
|
||||||
|
'''Draw a filled circle with given radius and color with aPos as center'''
|
||||||
|
rsq = aRadius * aRadius
|
||||||
|
for x in range(aRadius) :
|
||||||
|
y = int(sqrt(rsq - x * x))
|
||||||
|
y0 = aPos[1] - y
|
||||||
|
ey = y0 + y * 2
|
||||||
|
y0 = clamp(y0, 0, self._size[1])
|
||||||
|
ln = abs(ey - y0) + 1;
|
||||||
|
|
||||||
|
self.vline((aPos[0] + x, y0), ln, aColor)
|
||||||
|
self.vline((aPos[0] - x, y0), ln, aColor)
|
||||||
|
|
||||||
|
def fill( self, aColor = BLACK ) :
|
||||||
|
'''Fill screen with the given color.'''
|
||||||
|
self.fillrect((0, 0), self._size, aColor)
|
||||||
|
|
||||||
|
def image( self, x0, y0, x1, y1, data ) :
|
||||||
|
self._setwindowloc((x0, y0), (x1, y1))
|
||||||
|
self._writedata(data)
|
||||||
|
|
||||||
|
def setvscroll(self, tfa, bfa) :
|
||||||
|
''' set vertical scroll area '''
|
||||||
|
self._writecommand(TFT.VSCRDEF)
|
||||||
|
data2 = bytearray([0, tfa])
|
||||||
|
self._writedata(data2)
|
||||||
|
data2[1] = 162 - tfa - bfa
|
||||||
|
self._writedata(data2)
|
||||||
|
data2[1] = bfa
|
||||||
|
self._writedata(data2)
|
||||||
|
self.tfa = tfa
|
||||||
|
self.bfa = bfa
|
||||||
|
|
||||||
|
def vscroll(self, value) :
|
||||||
|
a = value + self.tfa
|
||||||
|
if (a + self.bfa > 162) :
|
||||||
|
a = 162 - self.bfa
|
||||||
|
self._vscrolladdr(a)
|
||||||
|
|
||||||
|
def _vscrolladdr(self, addr) :
|
||||||
|
self._writecommand(TFT.VSCSAD)
|
||||||
|
data2 = bytearray([addr >> 8, addr & 0xff])
|
||||||
|
self._writedata(data2)
|
||||||
|
|
||||||
|
# @micropython.native
|
||||||
|
def _setColor( self, aColor ) :
|
||||||
|
self.colorData[0] = aColor >> 8
|
||||||
|
self.colorData[1] = aColor
|
||||||
|
self.buf = bytes(self.colorData) * 32
|
||||||
|
|
||||||
|
# @micropython.native
|
||||||
|
def _draw( self, aPixels ) :
|
||||||
|
'''Send given color to the device aPixels times.'''
|
||||||
|
|
||||||
|
self.dc(1)
|
||||||
|
self.cs(0)
|
||||||
|
for i in range(aPixels//32):
|
||||||
|
self.spi.write(self.buf)
|
||||||
|
rest = (int(aPixels) % 32)
|
||||||
|
if rest > 0:
|
||||||
|
buf2 = bytes(self.colorData) * rest
|
||||||
|
self.spi.write(buf2)
|
||||||
|
self.cs(1)
|
||||||
|
|
||||||
|
# @micropython.native
|
||||||
|
def _setwindowpoint( self, aPos ) :
|
||||||
|
'''Set a single point for drawing a color to.'''
|
||||||
|
x = self._offset[0] + int(aPos[0])
|
||||||
|
y = self._offset[1] + int(aPos[1])
|
||||||
|
self._writecommand(TFT.CASET) #Column address set.
|
||||||
|
self.windowLocData[0] = self._offset[0]
|
||||||
|
self.windowLocData[1] = x
|
||||||
|
self.windowLocData[2] = self._offset[0]
|
||||||
|
self.windowLocData[3] = x
|
||||||
|
self._writedata(self.windowLocData)
|
||||||
|
|
||||||
|
self._writecommand(TFT.RASET) #Row address set.
|
||||||
|
self.windowLocData[0] = self._offset[1]
|
||||||
|
self.windowLocData[1] = y
|
||||||
|
self.windowLocData[2] = self._offset[1]
|
||||||
|
self.windowLocData[3] = y
|
||||||
|
self._writedata(self.windowLocData)
|
||||||
|
self._writecommand(TFT.RAMWR) #Write to RAM.
|
||||||
|
|
||||||
|
# @micropython.native
|
||||||
|
def _setwindowloc( self, aPos0, aPos1 ) :
|
||||||
|
'''Set a rectangular area for drawing a color to.'''
|
||||||
|
self._writecommand(TFT.CASET) #Column address set.
|
||||||
|
self.windowLocData[0] = self._offset[0]
|
||||||
|
self.windowLocData[1] = self._offset[0] + int(aPos0[0])
|
||||||
|
self.windowLocData[2] = self._offset[0]
|
||||||
|
self.windowLocData[3] = self._offset[0] + int(aPos1[0])
|
||||||
|
self._writedata(self.windowLocData)
|
||||||
|
|
||||||
|
self._writecommand(TFT.RASET) #Row address set.
|
||||||
|
self.windowLocData[0] = self._offset[1]
|
||||||
|
self.windowLocData[1] = self._offset[1] + int(aPos0[1])
|
||||||
|
self.windowLocData[2] = self._offset[1]
|
||||||
|
self.windowLocData[3] = self._offset[1] + int(aPos1[1])
|
||||||
|
self._writedata(self.windowLocData)
|
||||||
|
|
||||||
|
self._writecommand(TFT.RAMWR) #Write to RAM.
|
||||||
|
|
||||||
|
#@micropython.native
|
||||||
|
def _writecommand( self, aCommand ) :
|
||||||
|
'''Write given command to the device.'''
|
||||||
|
self.dc(0)
|
||||||
|
self.cs(0)
|
||||||
|
self.spi.write(bytearray([aCommand]))
|
||||||
|
self.cs(1)
|
||||||
|
|
||||||
|
#@micropython.native
|
||||||
|
def _writedata( self, aData ) :
|
||||||
|
'''Write given data to the device. This may be
|
||||||
|
either a single int or a bytearray of values.'''
|
||||||
|
self.dc(1)
|
||||||
|
self.cs(0)
|
||||||
|
self.spi.write(aData)
|
||||||
|
self.cs(1)
|
||||||
|
|
||||||
|
#@micropython.native
|
||||||
|
def _pushcolor( self, aColor ) :
|
||||||
|
'''Push given color to the device.'''
|
||||||
|
self.colorData[0] = aColor >> 8
|
||||||
|
self.colorData[1] = aColor
|
||||||
|
self._writedata(self.colorData)
|
||||||
|
|
||||||
|
#@micropython.native
|
||||||
|
def _setMADCTL( self ) :
|
||||||
|
'''Set screen rotation and RGB/BGR format.'''
|
||||||
|
self._writecommand(TFT.MADCTL)
|
||||||
|
rgb = TFTRGB if self._rgb else TFTBGR
|
||||||
|
self._writedata(bytearray([TFTRotations[self.rotate] | rgb]))
|
||||||
|
|
||||||
|
#@micropython.native
|
||||||
|
def _reset( self ) :
|
||||||
|
'''Reset the device.'''
|
||||||
|
self.dc(0)
|
||||||
|
self.reset(1)
|
||||||
|
time.sleep_us(500)
|
||||||
|
self.reset(0)
|
||||||
|
time.sleep_us(500)
|
||||||
|
self.reset(1)
|
||||||
|
time.sleep_us(500)
|
||||||
|
|
||||||
|
def initb( self ) :
|
||||||
|
'''Initialize blue tab version.'''
|
||||||
|
self._size = (ScreenSize[0] + 2, ScreenSize[1] + 1)
|
||||||
|
self._reset()
|
||||||
|
self._writecommand(TFT.SWRESET) #Software reset.
|
||||||
|
time.sleep_us(50)
|
||||||
|
self._writecommand(TFT.SLPOUT) #out of sleep mode.
|
||||||
|
time.sleep_us(500)
|
||||||
|
|
||||||
|
data1 = bytearray(1)
|
||||||
|
self._writecommand(TFT.COLMOD) #Set color mode.
|
||||||
|
data1[0] = 0x05 #16 bit color.
|
||||||
|
self._writedata(data1)
|
||||||
|
time.sleep_us(10)
|
||||||
|
|
||||||
|
data3 = bytearray([0x00, 0x06, 0x03]) #fastest refresh, 6 lines front, 3 lines back.
|
||||||
|
self._writecommand(TFT.FRMCTR1) #Frame rate control.
|
||||||
|
self._writedata(data3)
|
||||||
|
time.sleep_us(10)
|
||||||
|
|
||||||
|
self._writecommand(TFT.MADCTL)
|
||||||
|
data1[0] = 0x08 #row address/col address, bottom to top refresh
|
||||||
|
self._writedata(data1)
|
||||||
|
|
||||||
|
data2 = bytearray(2)
|
||||||
|
self._writecommand(TFT.DISSET5) #Display settings
|
||||||
|
data2[0] = 0x15 #1 clock cycle nonoverlap, 2 cycle gate rise, 3 cycle oscil, equalize
|
||||||
|
data2[1] = 0x02 #fix on VTL
|
||||||
|
self._writedata(data2)
|
||||||
|
|
||||||
|
self._writecommand(TFT.INVCTR) #Display inversion control
|
||||||
|
data1[0] = 0x00 #Line inversion.
|
||||||
|
self._writedata(data1)
|
||||||
|
|
||||||
|
self._writecommand(TFT.PWCTR1) #Power control
|
||||||
|
data2[0] = 0x02 #GVDD = 4.7V
|
||||||
|
data2[1] = 0x70 #1.0uA
|
||||||
|
self._writedata(data2)
|
||||||
|
time.sleep_us(10)
|
||||||
|
|
||||||
|
self._writecommand(TFT.PWCTR2) #Power control
|
||||||
|
data1[0] = 0x05 #VGH = 14.7V, VGL = -7.35V
|
||||||
|
self._writedata(data1)
|
||||||
|
|
||||||
|
self._writecommand(TFT.PWCTR3) #Power control
|
||||||
|
data2[0] = 0x01 #Opamp current small
|
||||||
|
data2[1] = 0x02 #Boost frequency
|
||||||
|
self._writedata(data2)
|
||||||
|
|
||||||
|
self._writecommand(TFT.VMCTR1) #Power control
|
||||||
|
data2[0] = 0x3C #VCOMH = 4V
|
||||||
|
data2[1] = 0x38 #VCOML = -1.1V
|
||||||
|
self._writedata(data2)
|
||||||
|
time.sleep_us(10)
|
||||||
|
|
||||||
|
self._writecommand(TFT.PWCTR6) #Power control
|
||||||
|
data2[0] = 0x11
|
||||||
|
data2[1] = 0x15
|
||||||
|
self._writedata(data2)
|
||||||
|
|
||||||
|
#These different values don't seem to make a difference.
|
||||||
|
# dataGMCTRP = bytearray([0x0f, 0x1a, 0x0f, 0x18, 0x2f, 0x28, 0x20, 0x22, 0x1f,
|
||||||
|
# 0x1b, 0x23, 0x37, 0x00, 0x07, 0x02, 0x10])
|
||||||
|
dataGMCTRP = bytearray([0x02, 0x1c, 0x07, 0x12, 0x37, 0x32, 0x29, 0x2d, 0x29,
|
||||||
|
0x25, 0x2b, 0x39, 0x00, 0x01, 0x03, 0x10])
|
||||||
|
self._writecommand(TFT.GMCTRP1)
|
||||||
|
self._writedata(dataGMCTRP)
|
||||||
|
|
||||||
|
# dataGMCTRN = bytearray([0x0f, 0x1b, 0x0f, 0x17, 0x33, 0x2c, 0x29, 0x2e, 0x30,
|
||||||
|
# 0x30, 0x39, 0x3f, 0x00, 0x07, 0x03, 0x10])
|
||||||
|
dataGMCTRN = bytearray([0x03, 0x1d, 0x07, 0x06, 0x2e, 0x2c, 0x29, 0x2d, 0x2e,
|
||||||
|
0x2e, 0x37, 0x3f, 0x00, 0x00, 0x02, 0x10])
|
||||||
|
self._writecommand(TFT.GMCTRN1)
|
||||||
|
self._writedata(dataGMCTRN)
|
||||||
|
time.sleep_us(10)
|
||||||
|
|
||||||
|
self._writecommand(TFT.CASET) #Column address set.
|
||||||
|
self.windowLocData[0] = 0x00
|
||||||
|
self.windowLocData[1] = 2 #Start at column 2
|
||||||
|
self.windowLocData[2] = 0x00
|
||||||
|
self.windowLocData[3] = self._size[0] - 1
|
||||||
|
self._writedata(self.windowLocData)
|
||||||
|
|
||||||
|
self._writecommand(TFT.RASET) #Row address set.
|
||||||
|
self.windowLocData[1] = 1 #Start at row 2.
|
||||||
|
self.windowLocData[3] = self._size[1] - 1
|
||||||
|
self._writedata(self.windowLocData)
|
||||||
|
|
||||||
|
self._writecommand(TFT.NORON) #Normal display on.
|
||||||
|
time.sleep_us(10)
|
||||||
|
|
||||||
|
self._writecommand(TFT.RAMWR)
|
||||||
|
time.sleep_us(500)
|
||||||
|
|
||||||
|
self._writecommand(TFT.DISPON)
|
||||||
|
self.cs(1)
|
||||||
|
time.sleep_us(500)
|
||||||
|
|
||||||
|
def initr( self ) :
|
||||||
|
'''Initialize a red tab version.'''
|
||||||
|
self._reset()
|
||||||
|
|
||||||
|
self._writecommand(TFT.SWRESET) #Software reset.
|
||||||
|
time.sleep_us(150)
|
||||||
|
self._writecommand(TFT.SLPOUT) #out of sleep mode.
|
||||||
|
time.sleep_us(500)
|
||||||
|
|
||||||
|
data3 = bytearray([0x01, 0x2C, 0x2D]) #fastest refresh, 6 lines front, 3 lines back.
|
||||||
|
self._writecommand(TFT.FRMCTR1) #Frame rate control.
|
||||||
|
self._writedata(data3)
|
||||||
|
|
||||||
|
self._writecommand(TFT.FRMCTR2) #Frame rate control.
|
||||||
|
self._writedata(data3)
|
||||||
|
|
||||||
|
data6 = bytearray([0x01, 0x2c, 0x2d, 0x01, 0x2c, 0x2d])
|
||||||
|
self._writecommand(TFT.FRMCTR3) #Frame rate control.
|
||||||
|
self._writedata(data6)
|
||||||
|
time.sleep_us(10)
|
||||||
|
|
||||||
|
data1 = bytearray(1)
|
||||||
|
self._writecommand(TFT.INVCTR) #Display inversion control
|
||||||
|
data1[0] = 0x07 #Line inversion.
|
||||||
|
self._writedata(data1)
|
||||||
|
|
||||||
|
self._writecommand(TFT.PWCTR1) #Power control
|
||||||
|
data3[0] = 0xA2
|
||||||
|
data3[1] = 0x02
|
||||||
|
data3[2] = 0x84
|
||||||
|
self._writedata(data3)
|
||||||
|
|
||||||
|
self._writecommand(TFT.PWCTR2) #Power control
|
||||||
|
data1[0] = 0xC5 #VGH = 14.7V, VGL = -7.35V
|
||||||
|
self._writedata(data1)
|
||||||
|
|
||||||
|
data2 = bytearray(2)
|
||||||
|
self._writecommand(TFT.PWCTR3) #Power control
|
||||||
|
data2[0] = 0x0A #Opamp current small
|
||||||
|
data2[1] = 0x00 #Boost frequency
|
||||||
|
self._writedata(data2)
|
||||||
|
|
||||||
|
self._writecommand(TFT.PWCTR4) #Power control
|
||||||
|
data2[0] = 0x8A #Opamp current small
|
||||||
|
data2[1] = 0x2A #Boost frequency
|
||||||
|
self._writedata(data2)
|
||||||
|
|
||||||
|
self._writecommand(TFT.PWCTR5) #Power control
|
||||||
|
data2[0] = 0x8A #Opamp current small
|
||||||
|
data2[1] = 0xEE #Boost frequency
|
||||||
|
self._writedata(data2)
|
||||||
|
|
||||||
|
self._writecommand(TFT.VMCTR1) #Power control
|
||||||
|
data1[0] = 0x0E
|
||||||
|
self._writedata(data1)
|
||||||
|
|
||||||
|
self._writecommand(TFT.INVOFF)
|
||||||
|
|
||||||
|
self._writecommand(TFT.MADCTL) #Power control
|
||||||
|
data1[0] = 0xC8
|
||||||
|
self._writedata(data1)
|
||||||
|
|
||||||
|
self._writecommand(TFT.COLMOD)
|
||||||
|
data1[0] = 0x05
|
||||||
|
self._writedata(data1)
|
||||||
|
|
||||||
|
self._writecommand(TFT.CASET) #Column address set.
|
||||||
|
self.windowLocData[0] = 0x00
|
||||||
|
self.windowLocData[1] = 0x00
|
||||||
|
self.windowLocData[2] = 0x00
|
||||||
|
self.windowLocData[3] = self._size[0] - 1
|
||||||
|
self._writedata(self.windowLocData)
|
||||||
|
|
||||||
|
self._writecommand(TFT.RASET) #Row address set.
|
||||||
|
self.windowLocData[3] = self._size[1] - 1
|
||||||
|
self._writedata(self.windowLocData)
|
||||||
|
|
||||||
|
dataGMCTRP = bytearray([0x0f, 0x1a, 0x0f, 0x18, 0x2f, 0x28, 0x20, 0x22, 0x1f,
|
||||||
|
0x1b, 0x23, 0x37, 0x00, 0x07, 0x02, 0x10])
|
||||||
|
self._writecommand(TFT.GMCTRP1)
|
||||||
|
self._writedata(dataGMCTRP)
|
||||||
|
|
||||||
|
dataGMCTRN = bytearray([0x0f, 0x1b, 0x0f, 0x17, 0x33, 0x2c, 0x29, 0x2e, 0x30,
|
||||||
|
0x30, 0x39, 0x3f, 0x00, 0x07, 0x03, 0x10])
|
||||||
|
self._writecommand(TFT.GMCTRN1)
|
||||||
|
self._writedata(dataGMCTRN)
|
||||||
|
time.sleep_us(10)
|
||||||
|
|
||||||
|
self._writecommand(TFT.DISPON)
|
||||||
|
time.sleep_us(100)
|
||||||
|
|
||||||
|
self._writecommand(TFT.NORON) #Normal display on.
|
||||||
|
time.sleep_us(10)
|
||||||
|
|
||||||
|
self.cs(1)
|
||||||
|
|
||||||
|
def initb2( self ) :
|
||||||
|
'''Initialize another blue tab version.'''
|
||||||
|
self._size = (ScreenSize[0] + 2, ScreenSize[1] + 1)
|
||||||
|
self._offset[0] = 2
|
||||||
|
self._offset[1] = 1
|
||||||
|
self._reset()
|
||||||
|
self._writecommand(TFT.SWRESET) #Software reset.
|
||||||
|
time.sleep_us(50)
|
||||||
|
self._writecommand(TFT.SLPOUT) #out of sleep mode.
|
||||||
|
time.sleep_us(500)
|
||||||
|
|
||||||
|
data3 = bytearray([0x01, 0x2C, 0x2D]) #
|
||||||
|
self._writecommand(TFT.FRMCTR1) #Frame rate control.
|
||||||
|
self._writedata(data3)
|
||||||
|
time.sleep_us(10)
|
||||||
|
|
||||||
|
self._writecommand(TFT.FRMCTR2) #Frame rate control.
|
||||||
|
self._writedata(data3)
|
||||||
|
time.sleep_us(10)
|
||||||
|
|
||||||
|
self._writecommand(TFT.FRMCTR3) #Frame rate control.
|
||||||
|
self._writedata(data3)
|
||||||
|
time.sleep_us(10)
|
||||||
|
|
||||||
|
self._writecommand(TFT.INVCTR) #Display inversion control
|
||||||
|
data1 = bytearray(1) #
|
||||||
|
data1[0] = 0x07
|
||||||
|
self._writedata(data1)
|
||||||
|
|
||||||
|
self._writecommand(TFT.PWCTR1) #Power control
|
||||||
|
data3[0] = 0xA2 #
|
||||||
|
data3[1] = 0x02 #
|
||||||
|
data3[2] = 0x84 #
|
||||||
|
self._writedata(data3)
|
||||||
|
time.sleep_us(10)
|
||||||
|
|
||||||
|
self._writecommand(TFT.PWCTR2) #Power control
|
||||||
|
data1[0] = 0xC5 #
|
||||||
|
self._writedata(data1)
|
||||||
|
|
||||||
|
self._writecommand(TFT.PWCTR3) #Power control
|
||||||
|
data2 = bytearray(2)
|
||||||
|
data2[0] = 0x0A #
|
||||||
|
data2[1] = 0x00 #
|
||||||
|
self._writedata(data2)
|
||||||
|
|
||||||
|
self._writecommand(TFT.PWCTR4) #Power control
|
||||||
|
data2[0] = 0x8A #
|
||||||
|
data2[1] = 0x2A #
|
||||||
|
self._writedata(data2)
|
||||||
|
|
||||||
|
self._writecommand(TFT.PWCTR5) #Power control
|
||||||
|
data2[0] = 0x8A #
|
||||||
|
data2[1] = 0xEE #
|
||||||
|
self._writedata(data2)
|
||||||
|
|
||||||
|
self._writecommand(TFT.VMCTR1) #Power control
|
||||||
|
data1[0] = 0x0E #
|
||||||
|
self._writedata(data1)
|
||||||
|
time.sleep_us(10)
|
||||||
|
|
||||||
|
self._writecommand(TFT.MADCTL)
|
||||||
|
data1[0] = 0xC8 #row address/col address, bottom to top refresh
|
||||||
|
self._writedata(data1)
|
||||||
|
|
||||||
|
#These different values don't seem to make a difference.
|
||||||
|
# dataGMCTRP = bytearray([0x0f, 0x1a, 0x0f, 0x18, 0x2f, 0x28, 0x20, 0x22, 0x1f,
|
||||||
|
# 0x1b, 0x23, 0x37, 0x00, 0x07, 0x02, 0x10])
|
||||||
|
dataGMCTRP = bytearray([0x02, 0x1c, 0x07, 0x12, 0x37, 0x32, 0x29, 0x2d, 0x29,
|
||||||
|
0x25, 0x2b, 0x39, 0x00, 0x01, 0x03, 0x10])
|
||||||
|
self._writecommand(TFT.GMCTRP1)
|
||||||
|
self._writedata(dataGMCTRP)
|
||||||
|
|
||||||
|
# dataGMCTRN = bytearray([0x0f, 0x1b, 0x0f, 0x17, 0x33, 0x2c, 0x29, 0x2e, 0x30,
|
||||||
|
# 0x30, 0x39, 0x3f, 0x00, 0x07, 0x03, 0x10])
|
||||||
|
dataGMCTRN = bytearray([0x03, 0x1d, 0x07, 0x06, 0x2e, 0x2c, 0x29, 0x2d, 0x2e,
|
||||||
|
0x2e, 0x37, 0x3f, 0x00, 0x00, 0x02, 0x10])
|
||||||
|
self._writecommand(TFT.GMCTRN1)
|
||||||
|
self._writedata(dataGMCTRN)
|
||||||
|
time.sleep_us(10)
|
||||||
|
|
||||||
|
self._writecommand(TFT.CASET) #Column address set.
|
||||||
|
self.windowLocData[0] = 0x00
|
||||||
|
self.windowLocData[1] = 0x02 #Start at column 2
|
||||||
|
self.windowLocData[2] = 0x00
|
||||||
|
self.windowLocData[3] = self._size[0] - 1
|
||||||
|
self._writedata(self.windowLocData)
|
||||||
|
|
||||||
|
self._writecommand(TFT.RASET) #Row address set.
|
||||||
|
self.windowLocData[1] = 0x01 #Start at row 2.
|
||||||
|
self.windowLocData[3] = self._size[1] - 1
|
||||||
|
self._writedata(self.windowLocData)
|
||||||
|
|
||||||
|
data1 = bytearray(1)
|
||||||
|
self._writecommand(TFT.COLMOD) #Set color mode.
|
||||||
|
data1[0] = 0x05 #16 bit color.
|
||||||
|
self._writedata(data1)
|
||||||
|
time.sleep_us(10)
|
||||||
|
|
||||||
|
self._writecommand(TFT.NORON) #Normal display on.
|
||||||
|
time.sleep_us(10)
|
||||||
|
|
||||||
|
self._writecommand(TFT.RAMWR)
|
||||||
|
time.sleep_us(500)
|
||||||
|
|
||||||
|
self._writecommand(TFT.DISPON)
|
||||||
|
self.cs(1)
|
||||||
|
time.sleep_us(500)
|
||||||
|
|
||||||
|
#@micropython.native
|
||||||
|
def initg( self ) :
|
||||||
|
'''Initialize a green tab version.'''
|
||||||
|
self._reset()
|
||||||
|
|
||||||
|
self._writecommand(TFT.SWRESET) #Software reset.
|
||||||
|
time.sleep_us(150)
|
||||||
|
self._writecommand(TFT.SLPOUT) #out of sleep mode.
|
||||||
|
time.sleep_us(255)
|
||||||
|
|
||||||
|
data3 = bytearray([0x01, 0x2C, 0x2D]) #fastest refresh, 6 lines front, 3 lines back.
|
||||||
|
self._writecommand(TFT.FRMCTR1) #Frame rate control.
|
||||||
|
self._writedata(data3)
|
||||||
|
|
||||||
|
self._writecommand(TFT.FRMCTR2) #Frame rate control.
|
||||||
|
self._writedata(data3)
|
||||||
|
|
||||||
|
data6 = bytearray([0x01, 0x2c, 0x2d, 0x01, 0x2c, 0x2d])
|
||||||
|
self._writecommand(TFT.FRMCTR3) #Frame rate control.
|
||||||
|
self._writedata(data6)
|
||||||
|
time.sleep_us(10)
|
||||||
|
|
||||||
|
self._writecommand(TFT.INVCTR) #Display inversion control
|
||||||
|
self._writedata(bytearray([0x07]))
|
||||||
|
self._writecommand(TFT.PWCTR1) #Power control
|
||||||
|
data3[0] = 0xA2
|
||||||
|
data3[1] = 0x02
|
||||||
|
data3[2] = 0x84
|
||||||
|
self._writedata(data3)
|
||||||
|
|
||||||
|
self._writecommand(TFT.PWCTR2) #Power control
|
||||||
|
self._writedata(bytearray([0xC5]))
|
||||||
|
|
||||||
|
data2 = bytearray(2)
|
||||||
|
self._writecommand(TFT.PWCTR3) #Power control
|
||||||
|
data2[0] = 0x0A #Opamp current small
|
||||||
|
data2[1] = 0x00 #Boost frequency
|
||||||
|
self._writedata(data2)
|
||||||
|
|
||||||
|
self._writecommand(TFT.PWCTR4) #Power control
|
||||||
|
data2[0] = 0x8A #Opamp current small
|
||||||
|
data2[1] = 0x2A #Boost frequency
|
||||||
|
self._writedata(data2)
|
||||||
|
|
||||||
|
self._writecommand(TFT.PWCTR5) #Power control
|
||||||
|
data2[0] = 0x8A #Opamp current small
|
||||||
|
data2[1] = 0xEE #Boost frequency
|
||||||
|
self._writedata(data2)
|
||||||
|
|
||||||
|
self._writecommand(TFT.VMCTR1) #Power control
|
||||||
|
self._writedata(bytearray([0x0E]))
|
||||||
|
|
||||||
|
self._writecommand(TFT.INVOFF)
|
||||||
|
|
||||||
|
self._setMADCTL()
|
||||||
|
|
||||||
|
self._writecommand(TFT.COLMOD)
|
||||||
|
self._writedata(bytearray([0x05]))
|
||||||
|
|
||||||
|
self._writecommand(TFT.CASET) #Column address set.
|
||||||
|
self.windowLocData[0] = 0x00
|
||||||
|
self.windowLocData[1] = 0x01 #Start at row/column 1.
|
||||||
|
self.windowLocData[2] = 0x00
|
||||||
|
self.windowLocData[3] = self._size[0] - 1
|
||||||
|
self._writedata(self.windowLocData)
|
||||||
|
|
||||||
|
self._writecommand(TFT.RASET) #Row address set.
|
||||||
|
self.windowLocData[3] = self._size[1] - 1
|
||||||
|
self._writedata(self.windowLocData)
|
||||||
|
|
||||||
|
dataGMCTRP = bytearray([0x02, 0x1c, 0x07, 0x12, 0x37, 0x32, 0x29, 0x2d, 0x29,
|
||||||
|
0x25, 0x2b, 0x39, 0x00, 0x01, 0x03, 0x10])
|
||||||
|
self._writecommand(TFT.GMCTRP1)
|
||||||
|
self._writedata(dataGMCTRP)
|
||||||
|
|
||||||
|
dataGMCTRN = bytearray([0x03, 0x1d, 0x07, 0x06, 0x2e, 0x2c, 0x29, 0x2d, 0x2e,
|
||||||
|
0x2e, 0x37, 0x3f, 0x00, 0x00, 0x02, 0x10])
|
||||||
|
self._writecommand(TFT.GMCTRN1)
|
||||||
|
self._writedata(dataGMCTRN)
|
||||||
|
|
||||||
|
self._writecommand(TFT.NORON) #Normal display on.
|
||||||
|
time.sleep_us(10)
|
||||||
|
|
||||||
|
self._writecommand(TFT.DISPON)
|
||||||
|
time.sleep_us(100)
|
||||||
|
|
||||||
|
self.cs(1)
|
||||||
|
|
||||||
|
def maker( ) :
|
||||||
|
t = TFT(1, "X1", "X2")
|
||||||
|
print("Initializing")
|
||||||
|
t.initr()
|
||||||
|
t.fill(0)
|
||||||
|
return t
|
||||||
|
|
||||||
|
def makeb( ) :
|
||||||
|
t = TFT(1, "X1", "X2")
|
||||||
|
print("Initializing")
|
||||||
|
t.initb()
|
||||||
|
t.fill(0)
|
||||||
|
return t
|
||||||
|
|
||||||
|
def makeg( ) :
|
||||||
|
t = TFT(1, "X1", "X2")
|
||||||
|
print("Initializing")
|
||||||
|
t.initg()
|
||||||
|
t.fill(0)
|
||||||
|
return t
|
380
src/main.py
380
src/main.py
|
@ -1,76 +1,305 @@
|
||||||
# test of printing multiple fonts to the ILI9341 on an M5Stack using H/W SP
|
# test of printing multiple fonts to the ILI9341 on an M5Stack using H/W SP
|
||||||
# MIT License; Copyright (c) 2017 Jeffrey N. Magee
|
# MIT License; Copyright (c) 2017 Jeffrey N. Magee
|
||||||
|
|
||||||
from ili934xnew import ILI9341, color565
|
from ili934xnew import ILI9341, color565
|
||||||
from machine import Pin, SPI,Timer
|
from machine import Pin, SPI,Timer
|
||||||
|
from ST7735 import TFT
|
||||||
import m5stack
|
import m5stack
|
||||||
import tt14
|
import tt14
|
||||||
import glcdfont
|
import glcdfont
|
||||||
import tt14
|
import tt14
|
||||||
import tt24
|
import tt24
|
||||||
import tt32
|
import tt32
|
||||||
|
import uasyncio
|
||||||
from rotary_irq_esp import RotaryIRQ
|
from rotary_irq_esp import RotaryIRQ
|
||||||
fonts = [glcdfont,tt14,tt24,tt32]
|
fonts = [glcdfont,tt14,tt24,tt32]
|
||||||
|
from sysfont import sysfont
|
||||||
|
def splash():
|
||||||
|
# display.fill(0)
|
||||||
|
# display.fill_rect(0, 0, 32, 32, 1)
|
||||||
|
# display.fill_rect(2, 2, 28, 28, 0)
|
||||||
|
# display.vline(9, 8, 22, 1)
|
||||||
|
# display.vline(16, 2, 22, 1)
|
||||||
|
# display.vline(23, 8, 22, 1)
|
||||||
|
# display.fill_rect(26, 24, 2, 4, 1)
|
||||||
|
# display.text("MicroPython", 40, 0, 1)
|
||||||
|
# display.text("SSD1306", 40, 12, 1)
|
||||||
|
# display.text("OLED 128x64", 40, 24, 1)
|
||||||
|
|
||||||
|
#display.fill(0)
|
||||||
|
# display.text("SPIN", 34, 4, 1)
|
||||||
|
# display.text("COATER", 50, 14, 1)
|
||||||
|
# display.print("Spinner")
|
||||||
|
# display.print("COATER")
|
||||||
|
# tft.text((0,y),"Spin Coater",TFT.RED,sysfont,1,nowrap=True)
|
||||||
|
display.print("Spincoater",size=1,nowrap=True)
|
||||||
|
display.print("Spincoater",size=3,nowrap=True)
|
||||||
|
|
||||||
|
# #display.show()
|
||||||
|
|
||||||
|
# def tftprinttest():
|
||||||
|
# tft.fill(TFT.BLACK);
|
||||||
|
# v = 30
|
||||||
|
# tft.text((0, v), "Hello World!", TFT.RED, sysfont, 1, nowrap=True)
|
||||||
|
# v += sysfont["Height"]
|
||||||
|
# tft.text((0, v), "Hello World!", TFT.YELLOW, sysfont, 2, nowrap=True)
|
||||||
|
# v += sysfont["Height"] * 2
|
||||||
|
# tft.text((0, v), "Hello World!", TFT.GREEN, sysfont, 3, nowrap=True)
|
||||||
|
# v += sysfont["Height"] * 3
|
||||||
|
# tft.text((0, v), str(1234.567), TFT.BLUE, sysfont, 4, nowrap=True)
|
||||||
|
# time.sleep_ms(1500)
|
||||||
|
# tft.fill(TFT.BLACK);
|
||||||
|
# v = 0
|
||||||
|
# tft.text((0, v), "Hello World!", TFT.RED, sysfont)
|
||||||
|
# v += sysfont["Height"]
|
||||||
|
# tft.text((0, v), str(math.pi), TFT.GREEN, sysfont)
|
||||||
|
# v += sysfont["Height"]
|
||||||
|
# tft.text((0, v), " Want pi?", TFT.GREEN, sysfont)
|
||||||
|
# v += sysfont["Height"] * 2
|
||||||
|
# tft.text((0, v), hex(8675309), TFT.GREEN, sysfont)
|
||||||
|
# v += sysfont["Height"]
|
||||||
|
# tft.text((0, v), " Print HEX!", TFT.GREEN, sysfont)
|
||||||
|
# v += sysfont["Height"] * 2
|
||||||
|
# tft.text((0, v), "Sketch has been", TFT.WHITE, sysfont)
|
||||||
|
# v += sysfont["Height"]
|
||||||
|
# tft.text((0, v), "running for: ", TFT.WHITE, sysfont)
|
||||||
|
# v += sysfont["Height"]
|
||||||
|
# tft.text((0, v), str(time.ticks_ms() / 1000), TFT.PURPLE, sysfont)
|
||||||
|
# v += sysfont["Height"]
|
||||||
|
# tft.text((0, v), " seconds.", TFT.WHITE, sysfont)
|
||||||
|
|
||||||
|
def start_view(state, rotary):
|
||||||
|
|
||||||
|
display.set_pos(0,0)
|
||||||
|
text="Spin Coater\n"
|
||||||
|
#display.set_font(tt14)
|
||||||
|
text += "> " if rotary.value() == 0 else " "
|
||||||
|
text+="Edit\n"
|
||||||
|
text+= "> " if rotary.value() == 1 else " "
|
||||||
|
text+= "Start\n"
|
||||||
|
display.print(text)
|
||||||
|
#print(rotary.value())
|
||||||
|
|
||||||
|
def draw_edit_menu(state, rotary):
|
||||||
|
display.text("Deposit speed:", 0, 0, 1)
|
||||||
|
display.text("{: >{w}} RPM".format(config["deposit_rpm"], w=5), 56, 10, 1)
|
||||||
|
display.text("Coating speed:", 0, 21, 1)
|
||||||
|
display.text("{: >{w}} RPM".format(config["coating_rpm"], w=5), 56, 31, 1)
|
||||||
|
display.text("Coating time:", 0, 42, 1)
|
||||||
|
display.text("{: >{w}} sec".format(config["coating_time"], w=5), 56, 52, 1)
|
||||||
|
|
||||||
|
|
||||||
|
def edit_deposit_view(state, rotary):
|
||||||
|
config["deposit_rpm"] = rotary.value() * 100
|
||||||
|
draw_edit_menu(state, rotary)
|
||||||
|
display.text(">", 40, 10, 1)
|
||||||
|
|
||||||
|
|
||||||
|
def edit_coating_rpm_view(state, rotary):
|
||||||
|
config["coating_rpm"] = rotary.value() * 100
|
||||||
|
draw_edit_menu(state, rotary)
|
||||||
|
display.text(">", 40, 32, 1)
|
||||||
|
|
||||||
|
|
||||||
|
def edit_coating_time_view(state, rotary):
|
||||||
|
config["coating_time"] = rotary.value()
|
||||||
|
draw_edit_menu(state, rotary)
|
||||||
|
display.text(">", 40, 54, 1)
|
||||||
|
|
||||||
|
|
||||||
|
def draw_rpm(rpm):
|
||||||
|
display.text("RPM:{: >{w}.0f}".format(rpm, w=5), 30, 27, 1)
|
||||||
|
|
||||||
|
|
||||||
|
def deposit_view(state, rotary):
|
||||||
|
display.fill_rect(0, 0, 127, 14, 1)
|
||||||
|
display.text("Deposit", 36, 3, 0)
|
||||||
|
draw_rpm(state["rpm"])
|
||||||
|
display.text("Press to", 32, 42, 1)
|
||||||
|
display.text("continue", 32, 52, 1)
|
||||||
|
|
||||||
|
|
||||||
|
def coating_view(state, rotary):
|
||||||
|
display.fill_rect(0, 0, 127, 14, 1)
|
||||||
|
display.text("Coating", 36, 3, 0)
|
||||||
|
draw_rpm(state["rpm"])
|
||||||
|
display.text("{: >{w}} sec".format(state["timer"], w=4), 30, 48, 1)
|
||||||
|
|
||||||
|
|
||||||
|
def decode_ESC_telemetry(data, motor_poles=14):
|
||||||
|
if len(data) > 10:
|
||||||
|
# use latest telemetry
|
||||||
|
data = data[-10:]
|
||||||
|
|
||||||
|
temperature = int(data[0]) # degrees Celsius
|
||||||
|
voltage = int((data[1] << 8) | data[2]) * 0.01 # Volt
|
||||||
|
current = (
|
||||||
|
int((data[3] << 8) | data[4]) * 0.01
|
||||||
|
) # Amps, only available if the ESC has a current meter
|
||||||
|
consumption = int(
|
||||||
|
(data[5] << 8) | data[6]
|
||||||
|
) # mAh, only available if the ESC has a current meter
|
||||||
|
erpm = int((data[7] << 8) | data[8]) * 100
|
||||||
|
rpm = erpm / (motor_poles / 2)
|
||||||
|
crc = data[9]
|
||||||
|
|
||||||
|
print(" Temp (C):", temperature)
|
||||||
|
print(" Voltage (V):", voltage)
|
||||||
|
print(" Current (A):", current)
|
||||||
|
print("Consumption (mAh):", consumption)
|
||||||
|
print(" Erpm:", erpm)
|
||||||
|
print(" RPM:", rpm)
|
||||||
|
print(" CRC:", crc)
|
||||||
|
print()
|
||||||
|
|
||||||
|
return temperature, voltage, current, consumption, erpm, rpm
|
||||||
|
|
||||||
|
|
||||||
|
async def update_display():
|
||||||
|
global state
|
||||||
|
global rotary
|
||||||
|
while True:
|
||||||
|
display.fill(color565(0,0,0))
|
||||||
|
state["view"](state, rotary)
|
||||||
|
display.show()
|
||||||
|
await uasyncio.sleep_ms(33)
|
||||||
|
|
||||||
|
|
||||||
|
async def update_motor():
|
||||||
|
global state
|
||||||
|
#we want to use 18 for the SPI-Bus!
|
||||||
|
#https://docs.micropython.org/en/latest/esp32/quickref.html#hardware-spi-bus
|
||||||
|
dshot = Dshot(pin=Pin(26))
|
||||||
|
rpm_pid = PID(
|
||||||
|
Kp=config["PID"]["Kp"],
|
||||||
|
Ki=config["PID"]["Ki"],
|
||||||
|
Kd=config["PID"]["Kd"],
|
||||||
|
setpoint=0,
|
||||||
|
sample_time=None,
|
||||||
|
output_limits=(0.0, 1.0),
|
||||||
|
# proportional_on_measurement=True,
|
||||||
|
)
|
||||||
|
while True:
|
||||||
|
rpm_pid.setpoint = state["target_rpm"]
|
||||||
|
|
||||||
|
# read ESC telemetry
|
||||||
|
if uart.any() >= 10:
|
||||||
|
telemetry = decode_ESC_telemetry(uart.read())
|
||||||
|
if telemetry is not None:
|
||||||
|
state["rpm"] = telemetry[5]
|
||||||
|
throttle = rpm_pid(state["rpm"])
|
||||||
|
# print(
|
||||||
|
# "Throttle:",
|
||||||
|
# throttle,
|
||||||
|
# "pid components:",
|
||||||
|
# rpm_pid.components,
|
||||||
|
# "RPM:",
|
||||||
|
# state["rpm"],
|
||||||
|
# )
|
||||||
|
|
||||||
|
if state["target_rpm"] == 0 and state["rpm"] < 1000:
|
||||||
|
throttle = 0
|
||||||
|
rpm_pid.reset()
|
||||||
|
dshot.set_throttle(throttle)
|
||||||
|
|
||||||
|
await uasyncio.sleep_ms(1)
|
||||||
|
|
||||||
|
|
||||||
def debounce_button(p):
|
def debounce_button(p):
|
||||||
p.irq(trigger=Pin.IRQ_FALLING, handler=None) # remove irq
|
p.irq(trigger=Pin.IRQ_FALLING, handler=None) # remove irq
|
||||||
timer0 = Timer(0)
|
timer0 = Timer(0)
|
||||||
print("Button debounced!")
|
|
||||||
timer0.init(period=20, mode=Timer.ONE_SHOT, callback=lambda t: on_button_press(p))
|
timer0.init(period=20, mode=Timer.ONE_SHOT, callback=lambda t: on_button_press(p))
|
||||||
|
|
||||||
|
|
||||||
def on_button_press(p):
|
def on_button_press(p):
|
||||||
p.irq(trigger=Pin.IRQ_FALLING, handler=debounce_button) # restore irq
|
p.irq(trigger=Pin.IRQ_FALLING, handler=debounce_button) # restore irq
|
||||||
print("Button pressed")
|
|
||||||
if p.value() == 1: # debounce
|
if p.value() == 1: # debounce
|
||||||
return
|
return
|
||||||
|
global state
|
||||||
|
global config
|
||||||
|
global rotary
|
||||||
|
if state["view"] == start_view:
|
||||||
|
if rotary.value() == 0:
|
||||||
|
state["view"] = edit_deposit_view
|
||||||
|
rotary.set(
|
||||||
|
min_val=0,
|
||||||
|
max_val=1000,
|
||||||
|
range_mode=RotaryIRQ.RANGE_BOUNDED,
|
||||||
|
value=int(0.01 * config["deposit_rpm"]),
|
||||||
|
)
|
||||||
|
return
|
||||||
|
if rotary.value() == 1:
|
||||||
|
state["view"] = deposit_view
|
||||||
|
state["target_rpm"] = config["deposit_rpm"]
|
||||||
|
return
|
||||||
|
if state["view"] == edit_deposit_view:
|
||||||
|
state["view"] = edit_coating_rpm_view
|
||||||
|
rotary.set(
|
||||||
|
min_val=0,
|
||||||
|
max_val=1000,
|
||||||
|
range_mode=RotaryIRQ.RANGE_BOUNDED,
|
||||||
|
value=int(0.01 * config["coating_rpm"]),
|
||||||
|
)
|
||||||
|
return
|
||||||
|
if state["view"] == edit_coating_rpm_view:
|
||||||
|
state["view"] = edit_coating_time_view
|
||||||
|
rotary.set(
|
||||||
|
min_val=0,
|
||||||
|
max_val=9999,
|
||||||
|
range_mode=RotaryIRQ.RANGE_BOUNDED,
|
||||||
|
value=config["coating_time"],
|
||||||
|
)
|
||||||
|
return
|
||||||
|
if state["view"] == edit_coating_time_view:
|
||||||
|
save_config()
|
||||||
|
rotary.set(min_val=0, max_val=1, range_mode=RotaryIRQ.RANGE_BOUNDED, value=0)
|
||||||
|
state["view"] = start_view
|
||||||
|
return
|
||||||
|
if state["view"] == deposit_view:
|
||||||
|
state["view"] = coating_view
|
||||||
|
start_coating(state)
|
||||||
|
return
|
||||||
|
if state["view"] == coating_view:
|
||||||
|
stop_coating()
|
||||||
|
return
|
||||||
|
|
||||||
# return
|
|
||||||
# global state
|
def start_coating(state):
|
||||||
# global config
|
global timer1
|
||||||
# global rotary
|
global timer2
|
||||||
# if state["view"] == start_view:
|
|
||||||
# if rotary.value() == 0:
|
state["timer"] = config["coating_time"]
|
||||||
# state["view"] = edit_deposit_view
|
|
||||||
# rotary.set(
|
timer1.init(
|
||||||
# min_val=0,
|
period=config["coating_time"] * 1000,
|
||||||
# max_val=1000,
|
mode=Timer.ONE_SHOT,
|
||||||
# range_mode=RotaryIRQ.RANGE_BOUNDED,
|
callback=lambda t: stop_coating(),
|
||||||
# value=int(0.01 * config["deposit_rpm"]),
|
)
|
||||||
# )
|
|
||||||
# return
|
def decrement_timer(t):
|
||||||
# if rotary.value() == 1:
|
state["timer"] -= 1
|
||||||
# state["view"] = deposit_view
|
|
||||||
# state["target_rpm"] = config["deposit_rpm"]
|
timer2.init(period=1000, mode=Timer.PERIODIC, callback=decrement_timer)
|
||||||
# return
|
|
||||||
# if state["view"] == edit_deposit_view:
|
# state["throttle"] = 0.10
|
||||||
# state["view"] = edit_coating_rpm_view
|
state["target_rpm"] = config["coating_rpm"]
|
||||||
# rotary.set(
|
|
||||||
# min_val=0,
|
|
||||||
# max_val=1000,
|
def stop_coating():
|
||||||
# range_mode=RotaryIRQ.RANGE_BOUNDED,
|
global state
|
||||||
# value=int(0.01 * config["coating_rpm"]),
|
global rotary
|
||||||
# )
|
global timer1
|
||||||
# return
|
global timer2
|
||||||
# if state["view"] == edit_coating_rpm_view:
|
timer1.deinit()
|
||||||
# state["view"] = edit_coating_time_view
|
timer2.deinit()
|
||||||
# rotary.set(
|
state["target_rpm"] = 0
|
||||||
# min_val=0,
|
rotary.set(min_val=0, max_val=1, range_mode=RotaryIRQ.RANGE_BOUNDED, value=0)
|
||||||
# max_val=9999,
|
state["view"] = start_view
|
||||||
# range_mode=RotaryIRQ.RANGE_BOUNDED,
|
|
||||||
# value=config["coating_time"],
|
|
||||||
# )
|
def save_config():
|
||||||
# return
|
global config
|
||||||
# if state["view"] == edit_coating_time_view:
|
with open("config.json", "w") as f:
|
||||||
# save_config()
|
json.dump(config, f)
|
||||||
# rotary.set(min_val=0, max_val=1, range_mode=RotaryIRQ.RANGE_BOUNDED, value=0)
|
|
||||||
# state["view"] = start_view
|
|
||||||
# return
|
|
||||||
# if state["view"] == deposit_view:
|
|
||||||
# state["view"] = coating_view
|
|
||||||
# start_coating(state)
|
|
||||||
# return
|
|
||||||
# if state["view"] == coating_view:
|
|
||||||
# stop_coating()
|
|
||||||
# return
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -79,7 +308,6 @@ text = 'Now is the time for all good men to come to the aid of the party.'
|
||||||
power = Pin(m5stack.TFT_LED_PIN, Pin.OUT)
|
power = Pin(m5stack.TFT_LED_PIN, Pin.OUT)
|
||||||
power.value(1)
|
power.value(1)
|
||||||
|
|
||||||
|
|
||||||
# No need to change the software. It's just a matter of different names.. Use this translation:
|
# No need to change the software. It's just a matter of different names.. Use this translation:
|
||||||
|
|
||||||
# SDO(MISO) <not used>
|
# SDO(MISO) <not used>
|
||||||
|
@ -91,7 +319,7 @@ power.value(1)
|
||||||
# CS CS
|
# CS CS
|
||||||
# GND GND
|
# GND GND
|
||||||
# VCC VCC
|
# VCC VCC
|
||||||
print("BOOOOOOTTTT")
|
print("BOOOOOOTTT2T")
|
||||||
spi = SPI(
|
spi = SPI(
|
||||||
2,
|
2,
|
||||||
baudrate=40000000,
|
baudrate=40000000,
|
||||||
|
@ -99,14 +327,19 @@ spi = SPI(
|
||||||
mosi=Pin(m5stack.TFT_MOSI_PIN),
|
mosi=Pin(m5stack.TFT_MOSI_PIN),
|
||||||
sck=Pin(m5stack.TFT_CLK_PIN))
|
sck=Pin(m5stack.TFT_CLK_PIN))
|
||||||
|
|
||||||
display = ILI9341(
|
# display = ILI9341(
|
||||||
spi,
|
# spi,
|
||||||
cs=Pin(m5stack.TFT_CS_PIN),
|
# cs=Pin(m5stack.TFT_CS_PIN),
|
||||||
dc=Pin(m5stack.TFT_DC_PIN),
|
# dc=Pin(m5stack.TFT_DC_PIN),
|
||||||
rst=Pin(m5stack.TFT_RST_PIN),
|
# rst=Pin(m5stack.TFT_RST_PIN),
|
||||||
w=128,
|
# w=160,
|
||||||
h=160,
|
# h=128,
|
||||||
r=3)
|
# r=5)
|
||||||
|
tft = TFT(spi,m5stack.TFT_DC_PIN,m5stack.TFT_RST_PIN,m5stack.TFT_CS_PIN)
|
||||||
|
tft.initr()
|
||||||
|
tft.rgb(True)
|
||||||
|
#tftprinttest()
|
||||||
|
|
||||||
rotary = RotaryIRQ(
|
rotary = RotaryIRQ(
|
||||||
pin_num_clk=25,
|
pin_num_clk=25,
|
||||||
pin_num_dt=13,
|
pin_num_dt=13,
|
||||||
|
@ -117,12 +350,25 @@ rotary = RotaryIRQ(
|
||||||
)
|
)
|
||||||
button = Pin(15, Pin.IN, Pin.PULL_UP)
|
button = Pin(15, Pin.IN, Pin.PULL_UP)
|
||||||
button.irq(trigger=Pin.IRQ_FALLING, handler=on_button_press)
|
button.irq(trigger=Pin.IRQ_FALLING, handler=on_button_press)
|
||||||
|
state = {
|
||||||
|
"view": start_view,
|
||||||
|
"rpm": 0,
|
||||||
|
"target_rpm": 0,
|
||||||
|
"timer": 0,
|
||||||
|
"rotary_val":-1
|
||||||
|
}
|
||||||
|
|
||||||
|
#display.erase()
|
||||||
|
#display.set_pos(0,0)
|
||||||
|
#display.set_font(tt32)
|
||||||
|
tft.fill(TFT.BLACK)
|
||||||
|
|
||||||
display.erase()
|
splash()
|
||||||
display.set_pos(0,0)
|
# for ff in fonts:
|
||||||
for ff in fonts:
|
# display.set_font(ff)
|
||||||
display.set_font(ff)
|
# display.print(text)
|
||||||
display.print(text)
|
event_loop = uasyncio.get_event_loop()
|
||||||
|
event_loop.create_task(update_display())
|
||||||
|
#event_loop.create_task(update_motor())
|
||||||
|
event_loop.run_forever()
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue