# Seengreat 2 Inch LCD Display demo
# Author(s):Andy Li from Seengreat

from machine import Pin,SPI,PWM
import framebuf
import time
import os

# Pin definition
BL = 20
DC = 16
RST = 21
MOSI = 19
SCK = 18    
CS = 17
# color definition RBG
WHITE  =  0xFFFF
BLACK  =  0x0000
GREEN  =  0x001F
RED    =  0x07E0
BLUE   =  0xF800

class LCD_2Inch():
    def __init__(self):
        self.w = 240
        self.h = 320       

        self.spi = SPI(0,5000_000,polarity=0, phase=0,sck=Pin(SCK),mosi=Pin(MOSI),miso=None)
        self.cs = Pin(CS,Pin.OUT)
        self.rst = Pin(RST,Pin.OUT)
        self.dc = Pin(DC,Pin.OUT)
        self.cs(1)
        self.dc(1)         
        self.buff = bytearray(self.h * self.w * 2) # set the lcd buffer size
        self.draw = framebuf.FrameBuffer(self.buff, self.w, self.h, framebuf.RGB565)
        self.lcd_init()
        
    def write_cmd(self, cmd):
        """write command"""
        self.dc(0)
        self.cs(0)
        self.spi.write(bytearray([cmd]))
        self.cs(1)
        
    def write_data(self, value):
        """write data"""
        self.dc(1)
        self.cs(0)
        self.spi.write(bytearray([value]))
        self.cs(1)
        
    def reset(self):
        """reset the lcd"""
        self.rst(1)
        time.sleep(0.02)
        self.rst(0)
        time.sleep(0.02)
        self.rst(1)
        time.sleep(0.02)

    def lcd_init(self):
        """lcd init..."""
        self.reset()
        
        self.write_cmd(0x36)
        self.write_data(0x00)
        
        self.write_cmd(0x3A) # set interface pixel format
        self.write_data(0x05)

        self.write_cmd(0x21)
        
        self.write_cmd(0x2A) # set x address form 0 to 320
        self.write_data(0x00)
        self.write_data(0x00)
        self.write_data(0x01) 
        self.write_data(0x3F)
        
        self.write_cmd(0x2B)  # set y address form 0 to 240
        self.write_data(0x00)
        self.write_data(0x00)
        self.write_data(0x00)
        self.write_data(0xEF)
        
        self.write_cmd(0xB2) # porch control
        self.write_data(0x0C)
        self.write_data(0x0C)
        self.write_data(0x00)
        self.write_data(0x33)
        self.write_data(0x33)

        self.write_cmd(0xB7) # gate control 
        self.write_data(0x35)
        
        self.write_cmd(0xBB)  # VCOMS setting
        self.write_data(0x1F)

        self.write_cmd(0xC0) #LCM control
        self.write_data(0x2C)
        
        self.write_cmd(0xC2)
        self.write_data(0x01)
        
        self.write_cmd(0xC3)
        self.write_data(0x12) 

        self.write_cmd(0xC4) # VDV setting
        self.write_data(0x20)

        self.write_cmd(0xC6)  # FR control 2
        self.write_data(0x0F)
        
        self.write_cmd(0xD0) # power control 1
        self.write_data(0xA4)
        self.write_data(0xA1)
        
        self.write_cmd(0xE0) # positive voltage gamma control
        self.write_data(0xD0)
        self.write_data(0x08)
        self.write_data(0x11)
        self.write_data(0x08)
        self.write_data(0x0C)
        self.write_data(0x15)
        self.write_data(0x39)
        self.write_data(0x33)
        self.write_data(0x50)
        self.write_data(0x36)
        self.write_data(0x13)
        self.write_data(0x14)
        self.write_data(0x29)
        self.write_data(0x2D)
        
        self.write_cmd(0xE1) # negative voltage gamma control 
        self.write_data(0xD0)
        self.write_data(0x08)
        self.write_data(0x10)
        self.write_data(0x08)
        self.write_data(0x06)
        self.write_data(0x06)
        self.write_data(0x39)
        self.write_data(0x44)
        self.write_data(0x51)
        self.write_data(0x0B)
        self.write_data(0x16)
        self.write_data(0x14)
        self.write_data(0x2F)
        self.write_data(0x31)
        self.write_cmd(0x21)
        self.write_cmd(0x11)
        self.write_cmd(0x29)
        
    def set_windows(self, start_x, start_y, end_x, end_y):
        """display the windows of start point and end point"""
        self.write_cmd(0x2A) # set the start point and end point of x
        self.write_data(start_x >> 8)  # x address start
        self.write_data(start_x & 0xff)
        self.write_data(end_x >> 8)  # x address end
        temp = end_x - 1
        self.write_data(temp & 0xff)
        
        self.write_cmd(0x2B) # set the start point and end point of y
        self.write_data(start_y >> 8)  # y address start
        self.write_data(start_y & 0xff)
        self.write_data(end_y >> 8)  # y address end
        temp = end_y - 1
        self.write_data(temp & 0xff)
        
        self.write_cmd(0x2C)
        
    def show(self,buff):
        self.set_windows(0, 0, self.w, self.h) # 36H=0XEC:2, 3, 129, 130; 36H=0X68:1, 2, 128, 129         
        
        self.dc(1)
        self.cs(0)
        self.spi.write(buff)
        self.cs(1)
        self.dc(0)


if __name__ == '__main__':
    lcd = LCD_2Inch()
    bl = PWM(Pin(BL))
    bl.freq(1000)
    bl.duty_u16(58982) #75%, max 65535, 65536*75%=49152

    lcd.draw.fill(WHITE)
    lcd.show(lcd.buff)
    lcd.draw.text('SEENGREAT!', 2, 5, RED)
    lcd.draw.text('PICO-1.44in-LCD', 2, 20, GREEN)
    lcd.draw.text('ABC123456789!', 2, 35, BLUE)
    lcd.draw.hline(2,50,127,BLUE)
    lcd.draw.vline(2,50,127,BLUE)
    lcd.draw.fill_rect(20,80,20,20,RED)
    lcd.draw.fill_rect(50,80,20,20,GREEN)
    lcd.draw.fill_rect(80,80,20,20,BLUE)
    lcd.show(lcd.buff)
    while True:
        lcd.show(lcd.buff)
    
    