# Driver for 2.4" LCD for P2 Eval Board type headers import array import p2 from machine import Pin import time import uctypes #import gc from time import sleep_ms import gc import framebuf # import asyncio # RJA Doesn't think we need this here as not sharing the bus from drivers.boolpalette import BoolPalette #globals ilicog = -1 # don't want to start a new cog if already running iliarr = array.array('L',[0, 0,0,0,0, 0,0,0,0, 0,0,0,0]) # 12, but only need 11 at this time fontname = "" # Output RGB565 format, 16 bit/pixel: # g4 g3 g2 b7 b6 b5 b4 b3 r7 r6 r5 r4 r3 g7 g6 g5 # ~80μs on RP2 @ 250MHz. #RJA: Format is different for mine... # r4 r3 r2 r1 r0 g5 g4 g3 | g2 g1 g0 b4 b3 b2 b1 b0 def _lcopy(dest, source, length: int): # rgb565 - 16bit/pixel n: int = 0 # print(length) while length: c = source[n] # Source byte holds 8-bit rrrgggbb # source rrrgggbb # dest 000bb000rrr00ggg #newc = (c & 0xE0) | ((c & 0x1C) >> 2) | ((c & 0x03) << 11) newc = ((c & 0xE0)<<8) | ((c & 0x1C) <<6) | ((c & 0x03) << 3) dest[2*n+1] = newc & 0xFF dest[2*n] = (newc>>8) & 0xFF #if c>0: # print(c,dest[n]) # sleep_ms(1000) n += 1 length -= 1 class ILI9341(framebuf.FrameBuffer): #Colors White= 0xFFFF Black= 0x0000 MidnightBlue= 0x18CE MintCream= 0xF7FF Yellow= 0xFFE0 LightYellow= 0xFFFC Aqua= 0x07FF Blue= 0x001F Gray= 0x8410 Green= 0x0400 Lime= 0x07E0 Maroon= 0x8000 Navy= 0x0010 Olive= 0x8400 Purple= 0x8010 Red= 0xF800 Silver= 0xC618 Teal= 0x0410 #Commands TakePins_ = 1 WrByte_CMD_ = 2 WrByte_DAT_ = 3 WrWord_DAT_ = 4 WrWordN_DAT_ = 5 WrBytes_DAT_ = 6 RdBytes_DAT_ = 7 DrawLineCmd_ = 8 SetPixelCmd_ = 9 DrawCircleCmd_ = 10 DrawCharCmd_ = 11 TogglePin_ = 12 GS8RGB_ =13 # Convert r, g, b in range 0-255 to an 8 bit colour value # rrrgggbb. Converted to 16 bit on the fly. @staticmethod def rgb(r, g, b): return (r & 0xE0) | ((g >> 3) & 0x1C) | (b >> 6) def show(self): wd = self.width ht = self.height lb = self._linebuf buf = self.mvb #if self._spi_init: # A callback was passed # self._spi_init(self._spi) # Bus may be shared # Commands needed to start data write self.WaitDone() self.setwindow(0,0,self.width-1,self.height-1) self.WaitDone() self.data[2]=uctypes.addressof(self.buf) self.data[0]=self.GS8RGB_ # self._wcd(b"\x2a", int.to_bytes(self.width, 4, "big")) # SET_COLUMN # self._wcd(b"\x2b", int.to_bytes(ht, 4, "big")) # SET_PAGE # self._wcmd(b"\x2c") # WRITE_RAM # self._dc(1) # self._cs(0) #for start in range(0, wd * ht, wd): # For each line # _lcopy(lb, buf[start:], wd) # Copy and map colors #if start==5*wd: # print("LB: ",lb) #self._spi.write(lb) # self.WrBytes_DAT(uctypes.addressof(lb), wd*2) # self._cs(1) #async def do_refresh(self, split=4): # self.show(self) # Transpose width & height for landscape mode def __init__(self, basepin, height=240, width=320, usd=False, init_spi=False): # Process arguments self.rst = basepin + 8 p2.pinh(self.rst) self.cs = basepin + 12 self.dc = basepin + 11 self.basepin = basepin self.rd = basepin + 9 self.wr = basepin + 10 self.height = height self.width = width global iliarr self.data=iliarr # array.array('L',[0, 0,0,0,0, 0,0,0,0, 0,0,0,0]) # 12, but only need 11 at this time self.mode = framebuf.GS8 self.palette = BoolPalette(self.mode) gc.collect() self.buf = bytearray(height * width) self.mvb = memoryview(self.buf) super().__init__(self.buf, width, height, self.mode) self._linebuf = bytearray(width * 2) # collect garbage gc.collect() # Start driver global ilicog if (ilicog < 0): f=open("ili934x.binary","rb") code=f.read() f.close() self.cog=p2.Cpu() ilicog = self.cog.start(code,self.data) # Hard Reset p2.pinl(self.rst) time.sleep_ms(1) p2.pinh(self.rst) time.sleep_ms(200) # Take Pins self.data[1]=self.basepin self.data[4]=self.rst self.data[5]=self.rd self.data[6]=self.wr self.data[7]=self.dc self.data[8]=self.cs WriteDelay = int(p2.clkfreq()/15000000/2) if (WriteDelay > 8): WriteDelay -= 4 self.data[2]=WriteDelay ReadDelay = int(p2.clkfreq()/2000000/2) if (ReadDelay > 8): ReadDelay-=8 self.data[3]=ReadDelay self.data[0]=self.TakePins_ self.WaitDone() # Configure LCD # Start initial Sequence self.WrByte_CMD(b'\x28') #'display OFF self.WrByte_CMD(b'\x11') self.WrByte_DAT(b'\x00') #'exit SLEEP mode self.WrByte_CMD(b'\xC0') self.WrByte_DAT(b'\x26') self.WrByte_DAT(b'\x04') #'power control 1 self.WrByte_CMD(b'\xC1') self.WrByte_DAT(b'\x04') #'power control 2 self.WrByte_CMD(b'\xC5') self.WrByte_DAT(b'\x34') self.WrByte_DAT(b'\x40') #'VCOM control 1 self.WrByte_CMD(b'\x36') self.WrByte_DAT(b'\xA8') #'memory access control = b'\xA0=RGB, b'\xA8=BGR self.WrByte_CMD(b'\xB1') self.WrByte_DAT(b'\x00') self.WrByte_DAT(b'\x18') #'frame rate control self.WrByte_CMD(b'\xB6') self.WrByte_DAT(b'\x0A') self.WrByte_DAT(b'\xA2') #'display function control self.WrByte_CMD(b'\xC7') self.WrByte_DAT(b'\xC0') #'VCOM control 2 self.WrByte_CMD(b'\x3A') self.WrByte_DAT(b'\x05') #'pixel format: b'\x06 = 18 bits per pixel, b'\x05 = 16 bits per pixel self.WrByte_CMD(b'\xE0') self.WrByte_DAT(b'\x1F') #'positive gamma correction self.WrByte_DAT(b'\x1B') self.WrByte_DAT(b'\x18') self.WrByte_DAT(b'\x0B') self.WrByte_DAT(b'\x0F') self.WrByte_DAT(b'\x09') self.WrByte_DAT(b'\x46') self.WrByte_DAT(b'\xB5') self.WrByte_DAT(b'\x37') self.WrByte_DAT(b'\x0A') self.WrByte_DAT(b'\x0C') self.WrByte_DAT(b'\x07') self.WrByte_DAT(b'\x07') self.WrByte_DAT(b'\x05') self.WrByte_DAT(b'\x00') self.WrByte_CMD(b'\xE1') self.WrByte_DAT(b'\x00') #'negative gamma correction self.WrByte_DAT(b'\x24') self.WrByte_DAT(b'\x27') self.WrByte_DAT(b'\x04') self.WrByte_DAT(b'\x10') self.WrByte_DAT(b'\x06') self.WrByte_DAT(b'\x39') self.WrByte_DAT(b'\x74') self.WrByte_DAT(b'\x48') self.WrByte_DAT(b'\x05') self.WrByte_DAT(b'\x13') self.WrByte_DAT(b'\x38') self.WrByte_DAT(b'\x38') self.WrByte_DAT(b'\x3A') self.WrByte_DAT(b'\x1F') self.WrByte_CMD(b'\x2A') self.WrByte_DAT(b'\x00') #'column address set (set horizontal window to full screen) self.WrByte_DAT(b'\x00') #'start b'\x00 self.WrByte_DAT(b'\x01') self.WrByte_DAT(b'\x3F') #'end b'\x013F =320-1 self.WrByte_CMD(b'\x2B') self.WrByte_DAT(b'\x00') #'page address set (set vertical window to full screen) self.WrByte_DAT(b'\x00') #start b'\x00 self.WrByte_DAT(b'\x00') self.WrByte_DAT(b'\xEF') #end b'\xEF =240-1 self.WrByte_CMD(b'\x29') #display on self.forecolor=self.White self.backcolor=self.Navy self.cls(self.backcolor) self.flag = 0 def WrByte_CMD(self, d): self.WaitDone() self.data[1]=int.from_bytes(d,"big") self.data[0]=self.WrByte_CMD_ def WrByte_DAT(self, d): self.WaitDone() self.data[1]=int.from_bytes(d,"big") self.data[0]=self.WrByte_DAT_ def WrBytes_DAT(self, a, n): self.WaitDone() self.data[1]=a self.data[2]=n self.data[0]=self.WrBytes_DAT_ def WrWord_DAT(self, d): self.WaitDone() self.data[1]=d self.data[0]=self.WrWord_DAT_ def WrWordN_DAT(self, d, n): self.WaitDone() self.data[1]=d self.data[2]=n self.data[0]=self.WrWordN_DAT_ def TogglePin(self, pin): self.data[1]=pin self.WaitDone() self.data[0]=self.TogglePin_ def WaitDone(self): i=self.data[0] while (i!=0): i=self.data[0] def cls(self, c): self.WaitDone() self.setwindow(0,0,self.width-1,self.height-1) self.WrWordN_DAT(c, self.width*self.height) self.backcolor=c self.row=0 self.col=0 def setwindow(self,x1,y1,x2,y2): if (x2self.FntEndChar): return i = a - self.FntStartChar w = int(self.FntMaxWidth/8) p = int(self.FntAdd+12+i*w*self.FntHeight) self.setwindow(x,y,x+self.FntMaxWidth-1, y+self.FntHeight-1) # print(x,y,x+self.FntMaxWidth-1, y+self.FntHeight-1) self.WaitDone() self.data[2]=self.FntHeight self.data[3]=w self.data[4]=p self.data[5]=self.forecolor self.data[6]=self.backcolor # print(self.data[2],self.data[3],self.data[4],self.data[5],self.data[6]) self.data[0]=self.DrawCharCmd_ def setwindow(self,x1,y1,x2,y2): if (x20: self.col -=1 elif c == 0x09: # tab self.print(" ") while self.col & 3: self.print(" ") elif c == 0x0C or c == 0x0B: self.flag = 1 return #before setting flag to 0 elif c == 0x0D or c == 0x0A: self.newline() else: self.print(c) else: if c == 0x0C: self.col = c % self.cols elif c == 0x0B: self.row = c % self.rows self.flag = 0 def printchar(self, c): y = self.row*self.FntHeight self.char(c, self.col*self.FntMaxWidth, y) self.col += 1 if (self.col == self.cols): self.newline() def print(self, s): # print a character (or string) at current row, col if isinstance(s,str): for c in s: self.printchar(c) elif isinstance(s,int): self.printchar(s) def newline(self): self.col = 0 self.row += 1 if (self.row == self.rows): self.row -= 1 def fore(self, c): self.forecolor=c def back(self, c): self.backcolor=c def __init__(self, basepin, height=240, width=320): # self, spi, cs, dc, rst, height=240, width=320, usd=False, init_spi=False): # Process arguments self.rst = basepin + 8 #self._rst = Pin(self.rst, value=1) p2.pinh(self.rst) self.cs = basepin + 12 self.dc = basepin + 11 self.basepin = basepin self.rd = basepin + 9 self.wr = basepin + 10 self.height = height self.width = width #self.pins = array.array('L',[self.basepin, self.rst, self.rd, self.wr, self.dc, self.cs]) #pins = [self.basepin, self.rst, self.rd, self.wr, self.dc, self.cs] #pina = bytearray(pins) #pina = uctypes.addressof(self.pins)+5 global iliarr self.data=iliarr # array.array('L',[0, 0,0,0,0, 0,0,0,0, 0,0,0,0]) # 12, but only need 11 at this time #testa = uctypes.bytearray_at(self.pins, 4) #print("Testing Pins = ",testa) # collect garbage gc.collect() #Start driver global ilicog #print(ilicog) if (ilicog < 0): f=open("ili934x.binary","rb") code=f.read() f.close() self.cog=p2.Cpu() ilicog = self.cog.start(code,self.data) #print(ilicog) #Hard Reset #self._rst.value(0) p2.pinl(self.rst) time.sleep_ms(1) #self._rst.value(1) p2.pinh(self.rst) time.sleep_ms(200) #TakePins self.data[1]=self.basepin self.data[4]=self.rst self.data[5]=self.rd self.data[6]=self.wr self.data[7]=self.dc self.data[8]=self.cs WriteDelay = int(p2.clkfreq()/15000000/2) if (WriteDelay > 8): WriteDelay -= 4 self.data[2]=WriteDelay ReadDelay = int(p2.clkfreq()/2000000/2) if (ReadDelay > 8): ReadDelay-=8 self.data[3]=ReadDelay #print("Taking Pins:",self.data) self.data[0]=self.TakePins_ self.WaitDone() #ConfigureLCD # Start initial Sequence self.WrByte_CMD(b'\x28') #'display OFF self.WrByte_CMD(b'\x11') self.WrByte_DAT(b'\x00') #'exit SLEEP mode self.WrByte_CMD(b'\xC0') self.WrByte_DAT(b'\x26') self.WrByte_DAT(b'\x04') #'power control 1 self.WrByte_CMD(b'\xC1') self.WrByte_DAT(b'\x04') #'power control 2 self.WrByte_CMD(b'\xC5') self.WrByte_DAT(b'\x34') self.WrByte_DAT(b'\x40') #'VCOM control 1 self.WrByte_CMD(b'\x36') self.WrByte_DAT(b'\xA8') #'memory access control = b'\xA0=RGB, b'\xA8=BGR self.WrByte_CMD(b'\xB1') self.WrByte_DAT(b'\x00') self.WrByte_DAT(b'\x18') #'frame rate control self.WrByte_CMD(b'\xB6') self.WrByte_DAT(b'\x0A') self.WrByte_DAT(b'\xA2') #'display function control self.WrByte_CMD(b'\xC7') self.WrByte_DAT(b'\xC0') #'VCOM control 2 self.WrByte_CMD(b'\x3A') self.WrByte_DAT(b'\x05') #'pixel format: b'\x06 = 18 bits per pixel, b'\x05 = 16 bits per pixel self.WrByte_CMD(b'\xE0') self.WrByte_DAT(b'\x1F') #'positive gamma correction self.WrByte_DAT(b'\x1B') self.WrByte_DAT(b'\x18') self.WrByte_DAT(b'\x0B') self.WrByte_DAT(b'\x0F') self.WrByte_DAT(b'\x09') self.WrByte_DAT(b'\x46') self.WrByte_DAT(b'\xB5') self.WrByte_DAT(b'\x37') self.WrByte_DAT(b'\x0A') self.WrByte_DAT(b'\x0C') self.WrByte_DAT(b'\x07') self.WrByte_DAT(b'\x07') self.WrByte_DAT(b'\x05') self.WrByte_DAT(b'\x00') self.WrByte_CMD(b'\xE1') self.WrByte_DAT(b'\x00') #'negative gamma correction self.WrByte_DAT(b'\x24') self.WrByte_DAT(b'\x27') self.WrByte_DAT(b'\x04') self.WrByte_DAT(b'\x10') self.WrByte_DAT(b'\x06') self.WrByte_DAT(b'\x39') self.WrByte_DAT(b'\x74') self.WrByte_DAT(b'\x48') self.WrByte_DAT(b'\x05') self.WrByte_DAT(b'\x13') self.WrByte_DAT(b'\x38') self.WrByte_DAT(b'\x38') self.WrByte_DAT(b'\x3A') self.WrByte_DAT(b'\x1F') self.WrByte_CMD(b'\x2A') self.WrByte_DAT(b'\x00') #'column address set (set horizontal window to full screen) self.WrByte_DAT(b'\x00') #'start b'\x00 self.WrByte_DAT(b'\x01') self.WrByte_DAT(b'\x3F') #'end b'\x013F =320-1 self.WrByte_CMD(b'\x2B') self.WrByte_DAT(b'\x00') #'page address set (set vertical window to full screen) self.WrByte_DAT(b'\x00') #start b'\x00 self.WrByte_DAT(b'\x00') self.WrByte_DAT(b'\xEF') #end b'\xEF =240-1 self.WrByte_CMD(b'\x29') #display on #self.WrByte_CMD(b'\x2C') #write pixels self.forecolor=self.White self.backcolor=self.Navy self.cls(self.backcolor) self.flag = 0 def WrByte_CMD(self, d): self.WaitDone() self.data[1]=int.from_bytes(d,"big") self.data[0]=self.WrByte_CMD_ def WrByte_DAT(self, d): self.WaitDone() self.data[1]=int.from_bytes(d,"big") self.data[0]=self.WrByte_DAT_ def WrBytes_DAT(self, a, n): self.WaitDone() self.data[1]=a self.data[2]=n self.data[0]=self.WrBytes_DAT_ def WrWord_DAT(self, d): self.WaitDone() self.data[1]=d self.data[0]=self.WrWord_DAT_ def WrWordN_DAT(self, d, n): self.WaitDone() self.data[1]=d self.data[2]=n self.data[0]=self.WrWordN_DAT_ def TogglePin(self, pin): self.data[1]=pin self.WaitDone() self.data[0]=self.TogglePin_ def WaitDone(self): i=self.data[0] while (i!=0): i=self.data[0]