Adding support for Waveshare LCD Hat (ST7789 chip)

This commit is contained in:
root 2019-10-19 04:49:38 +01:00
parent be2cd8293f
commit 0ea67cb97f
8 changed files with 324 additions and 0 deletions

@ -123,6 +123,10 @@ class Display(View):
def is_oledhat(self): def is_oledhat(self):
return self._implementation.name == 'oledhat' return self._implementation.name == 'oledhat'
def is_lcdhat(self):
return self._implementation.name == 'lcdhat'
def is_waveshare_any(self): def is_waveshare_any(self):
return self.is_waveshare_v1() or self.is_waveshare_v2() return self.is_waveshare_v1() or self.is_waveshare_v2()

@ -1,6 +1,7 @@
from pwnagotchi.ui.hw.inky import Inky from pwnagotchi.ui.hw.inky import Inky
from pwnagotchi.ui.hw.papirus import Papirus from pwnagotchi.ui.hw.papirus import Papirus
from pwnagotchi.ui.hw.oledhat import OledHat from pwnagotchi.ui.hw.oledhat import OledHat
from pwnagotchi.ui.hw.lcdhat import LcdHat
from pwnagotchi.ui.hw.waveshare1 import WaveshareV1 from pwnagotchi.ui.hw.waveshare1 import WaveshareV1
from pwnagotchi.ui.hw.waveshare2 import WaveshareV2 from pwnagotchi.ui.hw.waveshare2 import WaveshareV2
@ -16,6 +17,10 @@ def display_for(config):
if config['ui']['display']['type'] == 'oledhat': if config['ui']['display']['type'] == 'oledhat':
return OledHat(config) return OledHat(config)
if config['ui']['display']['type'] == 'lcdhat':
return LcdHat(config)
elif config['ui']['display']['type'] == 'waveshare_1': elif config['ui']['display']['type'] == 'waveshare_1':
return WaveshareV1(config) return WaveshareV1(config)

@ -0,0 +1,46 @@
import logging
import pwnagotchi.ui.fonts as fonts
from pwnagotchi.ui.hw.base import DisplayImpl
class LcdHat(DisplayImpl):
def __init__(self, config):
super(LcdHat, self).__init__(config, 'lcdhat')
self._display = None
def layout(self):
fonts.setup(10, 9, 10, 35)
self._layout['width'] = 240
self._layout['height'] = 240
self._layout['face'] = (0, 40)
self._layout['name'] = (5, 20)
self._layout['channel'] = (0, 0)
self._layout['aps'] = (28, 0)
self._layout['uptime'] = (175, 0)
self._layout['line1'] = [0, 14, 240, 14]
self._layout['line2'] = [0, 108, 240, 108]
self._layout['friend_face'] = (0, 92)
self._layout['friend_name'] = (40, 94)
self._layout['shakes'] = (0, 109)
self._layout['mode'] = (215, 109)
self._layout['status'] = {
'pos': (125, 20),
'font': fonts.Medium,
'max': 20
}
return self._layout
def initialize(self):
logging.info("initializing lcdhat display")
from pwnagotchi.ui.hw.libs.waveshare.lcdhat.epd import EPD
self._display = EPD()
self._display.init()
self._display.Clear()
def render(self, canvas):
self._display.display(canvas)
def clear(self):
self._display.clear()

@ -0,0 +1,165 @@
import spidev
import RPi.GPIO as GPIO
import time
import numpy as np
class ST7789(object):
"""class for ST7789 240*240 1.3inch OLED displays."""
def __init__(self,spi,rst = 27,dc = 25,bl = 24):
self.width = 240
self.height = 240
#Initialize DC RST pin
self._dc = dc
self._rst = rst
self._bl = bl
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
GPIO.setup(self._dc,GPIO.OUT)
GPIO.setup(self._rst,GPIO.OUT)
GPIO.setup(self._bl,GPIO.OUT)
GPIO.output(self._bl, GPIO.HIGH)
#Initialize SPI
self._spi = spi
self._spi.max_speed_hz = 40000000
""" Write register address and data """
def command(self, cmd):
GPIO.output(self._dc, GPIO.LOW)
self._spi.writebytes([cmd])
def data(self, val):
GPIO.output(self._dc, GPIO.HIGH)
self._spi.writebytes([val])
def Init(self):
"""Initialize dispaly"""
self.reset()
self.command(0x36)
self.data(0x70) #self.data(0x00)
self.command(0x3A)
self.data(0x05)
self.command(0xB2)
self.data(0x0C)
self.data(0x0C)
self.data(0x00)
self.data(0x33)
self.data(0x33)
self.command(0xB7)
self.data(0x35)
self.command(0xBB)
self.data(0x19)
self.command(0xC0)
self.data(0x2C)
self.command(0xC2)
self.data(0x01)
self.command(0xC3)
self.data(0x12)
self.command(0xC4)
self.data(0x20)
self.command(0xC6)
self.data(0x0F)
self.command(0xD0)
self.data(0xA4)
self.data(0xA1)
self.command(0xE0)
self.data(0xD0)
self.data(0x04)
self.data(0x0D)
self.data(0x11)
self.data(0x13)
self.data(0x2B)
self.data(0x3F)
self.data(0x54)
self.data(0x4C)
self.data(0x18)
self.data(0x0D)
self.data(0x0B)
self.data(0x1F)
self.data(0x23)
self.command(0xE1)
self.data(0xD0)
self.data(0x04)
self.data(0x0C)
self.data(0x11)
self.data(0x13)
self.data(0x2C)
self.data(0x3F)
self.data(0x44)
self.data(0x51)
self.data(0x2F)
self.data(0x1F)
self.data(0x1F)
self.data(0x20)
self.data(0x23)
self.command(0x21)
self.command(0x11)
self.command(0x29)
def reset(self):
"""Reset the display"""
GPIO.output(self._rst,GPIO.HIGH)
time.sleep(0.01)
GPIO.output(self._rst,GPIO.LOW)
time.sleep(0.01)
GPIO.output(self._rst,GPIO.HIGH)
time.sleep(0.01)
def SetWindows(self, Xstart, Ystart, Xend, Yend):
#set the X coordinates
self.command(0x2A)
self.data(0x00) #Set the horizontal starting point to the high octet
self.data(Xstart & 0xff) #Set the horizontal starting point to the low octet
self.data(0x00) #Set the horizontal end to the high octet
self.data((Xend - 1) & 0xff) #Set the horizontal end to the low octet
#set the Y coordinates
self.command(0x2B)
self.data(0x00)
self.data((Ystart & 0xff))
self.data(0x00)
self.data((Yend - 1) & 0xff )
self.command(0x2C)
def ShowImage(self,Image,Xstart,Ystart):
"""Set buffer to value of Python Imaging Library image."""
"""Write display buffer to physical display"""
imwidth, imheight = Image.size
if imwidth != self.width or imheight != self.height:
raise ValueError('Image must be same dimensions as display \
({0}x{1}).' .format(self.width, self.height))
img = np.asarray(Image)
pix = np.zeros((self.width,self.height,2), dtype = np.uint8)
pix[...,[0]] = np.add(np.bitwise_and(img[...,[0]],0xF8),np.right_shift(img[...,[1]],5))
pix[...,[1]] = np.add(np.bitwise_and(np.left_shift(img[...,[1]],3),0xE0),np.right_shift(img[...,[2]],3))
pix = pix.flatten().tolist()
self.SetWindows ( 0, 0, self.width, self.height)
GPIO.output(self._dc,GPIO.HIGH)
for i in range(0,len(pix),4096):
self._spi.writebytes(pix[i:i+4096])
def clear(self):
"""Clear contents of image buffer"""
_buffer = [0xff]*(self.width * self.height * 2)
self.SetWindows ( 0, 0, self.width, self.height)
GPIO.output(self._dc,GPIO.HIGH)
for i in range(0,len(_buffer),4096):
self._spi.writebytes(_buffer[i:i+4096])

Binary file not shown.

@ -0,0 +1,76 @@
# /*****************************************************************************
# * | File : config.py
# * | Author : Guillaume Giraudon
# * | Info :
# *----------------
# * | This version: V1.0
# * | Date : 2019-10-18
# * | Info :
# ******************************************************************************/
import RPi.GPIO as GPIO
import time
from smbus import SMBus
import spidev
import ctypes
# import spidev
# Pin definition
RST_PIN = 27
DC_PIN = 25
BL_PIN = 24
Device_SPI = 1
Device_I2C = 0
Device = Device_SPI
spi = spidev.SpiDev(0, 0)
def digital_write(pin, value):
GPIO.output(pin, value)
def digital_read(pin):
return GPIO.input(BUSY_PIN)
def delay_ms(delaytime):
time.sleep(delaytime / 1000.0)
def spi_writebyte(data):
# SPI.writebytes(data)
spi.writebytes([data[0]])
def i2c_writebyte(reg, value):
bus.write_byte_data(address, reg, value)
# time.sleep(0.01)
def module_init():
# print("module_init")
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
GPIO.setup(RST_PIN, GPIO.OUT)
GPIO.setup(DC_PIN, GPIO.OUT)
# SPI.max_speed_hz = 2000000
# SPI.mode = 0b00
# i2c_writebyte(0xff,0xff)
# spi.SYSFS_software_spi_begin()
# spi.SYSFS_software_spi_setDataMode(0);
# spi.SYSFS_software_spi_setClockDivider(1);
#spi.max_speed_hz = 2000000
#spi.mode = 0b00
GPIO.output(BL_PIN, 1)
GPIO.output(DC_PIN, 0)
return 0
def module_exit():
spi.SYSFS_software_spi_end()
GPIO.output(RST_PIN, 0)
GPIO.output(DC_PIN, 0)
### END OF FILE ###

@ -0,0 +1,28 @@
from . import ST7789
from . import config
# Display resolution
EPD_WIDTH = 240
EPD_HEIGHT = 240
disp = ST7789.ST7789(config.spi,config.RST_PIN, config.DC_PIN, config.BL_PIN)
class EPD(object):
def __init__(self):
self.reset_pin = config.RST_PIN
self.dc_pin = config.DC_PIN
#self.busy_pin = config.BUSY_PIN
#self.cs_pin = config.CS_PIN
self.width = EPD_WIDTH
self.height = EPD_HEIGHT
def init(self):
disp.Init()
def Clear(self):
disp.clear()
def display(self, image):
rgb_im = image.convert('RGB')
disp.ShowImage(rgb_im,0,0)