Merge pull request #694 from Evg33/fr_waveshare144lcd

waveshare 1.44inch lcd hat
This commit is contained in:
evilsocket 2019-12-07 14:11:25 +02:00 committed by GitHub
commit 4b651cd17b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 489 additions and 1 deletions

View File

@ -260,7 +260,7 @@ ui:
display:
enabled: true
rotation: 180
# Possible options inkyphat/inky, papirus/papi, waveshare_1/ws_1 or waveshare_2/ws_2, oledhat, lcdhat, waveshare154inch, waveshare27inch, waveshare29inch, dfrobot/df
# Possible options inkyphat/inky, papirus/papi, waveshare_1/ws_1 or waveshare_2/ws_2, oledhat, lcdhat, waveshare154inch, waveshare27inch, waveshare29inch, dfrobot/df, waveshare144lcd/ws144inch
type: 'waveshare_2'
# Possible options red/yellow/black (black used for monocromatic displays)
# Waveshare tri-color 2.13in display can be over-driven with color set as 'fastAndFurious'

View File

@ -59,6 +59,11 @@ class GPS(plugins.Plugin):
lat_pos = (112, 30)
lon_pos = (112, 49)
alt_pos = (87, 63)
elif ui.is_waveshare144lcd():
# guessed values, add tested ones if you can
lat_pos = (67, 73)
lon_pos = (62, 83)
alt_pos = (67, 93)
else:
# guessed values, add tested ones if you can
lat_pos = (127, 51)

View File

@ -44,6 +44,9 @@ class MemTemp(plugins.Plugin):
if ui.is_waveshare_v2():
h_pos = (180, 80)
v_pos = (180, 61)
elif ui.is_waveshare144lcd():
h_pos = (53, 77)
v_pos = (78, 67)
elif ui.is_inky():
h_pos = (140, 68)
v_pos = (165, 54)

View File

@ -52,6 +52,9 @@ class Display(View):
def is_dfrobot(self):
return self._implementation.name == 'dfrobot'
def is_waveshare144lcd(self):
return self._implementation.name == 'waveshare144lcd'
def is_waveshare154inch(self):
return self._implementation.name == 'waveshare154inch'

View File

@ -7,6 +7,7 @@ from pwnagotchi.ui.hw.waveshare1 import WaveshareV1
from pwnagotchi.ui.hw.waveshare2 import WaveshareV2
from pwnagotchi.ui.hw.waveshare27inch import Waveshare27inch
from pwnagotchi.ui.hw.waveshare29inch import Waveshare29inch
from pwnagotchi.ui.hw.waveshare144lcd import Waveshare144lcd
from pwnagotchi.ui.hw.waveshare154inch import Waveshare154inch
from pwnagotchi.ui.hw.waveshare213d import Waveshare213d
from pwnagotchi.ui.hw.spotpear24inch import Spotpear24inch
@ -40,6 +41,9 @@ def display_for(config):
elif config['ui']['display']['type'] == 'waveshare29inch':
return Waveshare29inch(config)
elif config['ui']['display']['type'] == 'waveshare144lcd':
return Waveshare144lcd(config)
elif config['ui']['display']['type'] == 'waveshare154inch':
return Waveshare154inch(config)

View File

@ -0,0 +1,319 @@
# -*- coding:UTF-8 -*-
##
# | file : LCD_1IN44.py
# | version : V2.0
# | date : 2018-07-16
# | function : On the ST7735S chip driver and clear screen, drawing lines, drawing, writing
# and other functions to achieve
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documnetation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
import RPi.GPIO as GPIO
import time
import numpy as np
from . import config
LCD_1IN44 = 1
LCD_1IN8 = 0
if LCD_1IN44 == 1:
LCD_WIDTH = 128 #LCD width
LCD_HEIGHT = 128 #LCD height
LCD_X = 2
LCD_Y = 1
if LCD_1IN8 == 1:
LCD_WIDTH = 160
LCD_HEIGHT = 128
LCD_X = 1
LCD_Y = 2
LCD_X_MAXPIXEL = 132 #LCD width maximum memory
LCD_Y_MAXPIXEL = 162 #LCD height maximum memory
#scanning method
L2R_U2D = 1
L2R_D2U = 2
R2L_U2D = 3
R2L_D2U = 4
U2D_L2R = 5
U2D_R2L = 6
D2U_L2R = 7
D2U_R2L = 8
SCAN_DIR_DFT = U2D_R2L
class LCD:
def __init__(self):
GPIO.setmode(GPIO.BCM)
self.width = LCD_WIDTH
self.height = LCD_HEIGHT
self.LCD_Scan_Dir = SCAN_DIR_DFT
self.LCD_X_Adjust = LCD_X
self.LCD_Y_Adjust = LCD_Y
""" Hardware reset """
def LCD_Reset(self):
GPIO.output(config.LCD_RST_PIN, GPIO.HIGH)
config.Driver_Delay_ms(100)
GPIO.output(config.LCD_RST_PIN, GPIO.LOW)
config.Driver_Delay_ms(100)
GPIO.output(config.LCD_RST_PIN, GPIO.HIGH)
config.Driver_Delay_ms(100)
""" Write register address and data """
def LCD_WriteReg(self, Reg):
GPIO.setmode(GPIO.BCM)
GPIO.setup(config.LCD_DC_PIN, GPIO.OUT)
GPIO.output(config.LCD_DC_PIN, GPIO.LOW)
config.SPI_Write_Byte([Reg])
def LCD_WriteData_8bit(self, Data):
GPIO.output(config.LCD_DC_PIN, GPIO.HIGH)
config.SPI_Write_Byte([Data])
def LCD_WriteData_NLen16Bit(self, Data, DataLen):
GPIO.output(config.LCD_DC_PIN, GPIO.HIGH)
for i in range(0, DataLen):
config.SPI_Write_Byte([Data >> 8])
config.SPI_Write_Byte([Data & 0xff])
""" Common register initialization """
def LCD_InitReg(self):
#ST7735R Frame Rate
self.LCD_WriteReg(0xB1)
self.LCD_WriteData_8bit(0x01)
self.LCD_WriteData_8bit(0x2C)
self.LCD_WriteData_8bit(0x2D)
self.LCD_WriteReg(0xB2)
self.LCD_WriteData_8bit(0x01)
self.LCD_WriteData_8bit(0x2C)
self.LCD_WriteData_8bit(0x2D)
self.LCD_WriteReg(0xB3)
self.LCD_WriteData_8bit(0x01)
self.LCD_WriteData_8bit(0x2C)
self.LCD_WriteData_8bit(0x2D)
self.LCD_WriteData_8bit(0x01)
self.LCD_WriteData_8bit(0x2C)
self.LCD_WriteData_8bit(0x2D)
#Column inversion
self.LCD_WriteReg(0xB4)
self.LCD_WriteData_8bit(0x07)
#ST7735R Power Sequence
self.LCD_WriteReg(0xC0)
self.LCD_WriteData_8bit(0xA2)
self.LCD_WriteData_8bit(0x02)
self.LCD_WriteData_8bit(0x84)
self.LCD_WriteReg(0xC1)
self.LCD_WriteData_8bit(0xC5)
self.LCD_WriteReg(0xC2)
self.LCD_WriteData_8bit(0x0A)
self.LCD_WriteData_8bit(0x00)
self.LCD_WriteReg(0xC3)
self.LCD_WriteData_8bit(0x8A)
self.LCD_WriteData_8bit(0x2A)
self.LCD_WriteReg(0xC4)
self.LCD_WriteData_8bit(0x8A)
self.LCD_WriteData_8bit(0xEE)
self.LCD_WriteReg(0xC5)#VCOM
self.LCD_WriteData_8bit(0x0E)
#ST7735R Gamma Sequence
self.LCD_WriteReg(0xe0)
self.LCD_WriteData_8bit(0x0f)
self.LCD_WriteData_8bit(0x1a)
self.LCD_WriteData_8bit(0x0f)
self.LCD_WriteData_8bit(0x18)
self.LCD_WriteData_8bit(0x2f)
self.LCD_WriteData_8bit(0x28)
self.LCD_WriteData_8bit(0x20)
self.LCD_WriteData_8bit(0x22)
self.LCD_WriteData_8bit(0x1f)
self.LCD_WriteData_8bit(0x1b)
self.LCD_WriteData_8bit(0x23)
self.LCD_WriteData_8bit(0x37)
self.LCD_WriteData_8bit(0x00)
self.LCD_WriteData_8bit(0x07)
self.LCD_WriteData_8bit(0x02)
self.LCD_WriteData_8bit(0x10)
self.LCD_WriteReg(0xe1)
self.LCD_WriteData_8bit(0x0f)
self.LCD_WriteData_8bit(0x1b)
self.LCD_WriteData_8bit(0x0f)
self.LCD_WriteData_8bit(0x17)
self.LCD_WriteData_8bit(0x33)
self.LCD_WriteData_8bit(0x2c)
self.LCD_WriteData_8bit(0x29)
self.LCD_WriteData_8bit(0x2e)
self.LCD_WriteData_8bit(0x30)
self.LCD_WriteData_8bit(0x30)
self.LCD_WriteData_8bit(0x39)
self.LCD_WriteData_8bit(0x3f)
self.LCD_WriteData_8bit(0x00)
self.LCD_WriteData_8bit(0x07)
self.LCD_WriteData_8bit(0x03)
self.LCD_WriteData_8bit(0x10)
#Enable test command
self.LCD_WriteReg(0xF0)
self.LCD_WriteData_8bit(0x01)
#Disable ram power save mode
self.LCD_WriteReg(0xF6)
self.LCD_WriteData_8bit(0x00)
#65k mode
self.LCD_WriteReg(0x3A)
self.LCD_WriteData_8bit(0x05)
#********************************************************************************
#function: Set the display scan and color transfer modes
#parameter:
# Scan_dir : Scan direction
# Colorchose : RGB or GBR color format
#********************************************************************************
def LCD_SetGramScanWay(self, Scan_dir):
#Get the screen scan direction
self.LCD_Scan_Dir = Scan_dir
#Get GRAM and LCD width and height
if (Scan_dir == L2R_U2D) or (Scan_dir == L2R_D2U) or (Scan_dir == R2L_U2D) or (Scan_dir == R2L_D2U) :
self.width = LCD_HEIGHT
self.height = LCD_WIDTH
if Scan_dir == L2R_U2D:
MemoryAccessReg_Data = 0X00 | 0x00
elif Scan_dir == L2R_D2U:
MemoryAccessReg_Data = 0X00 | 0x80
elif Scan_dir == R2L_U2D:
MemoryAccessReg_Data = 0x40 | 0x00
else: #R2L_D2U:
MemoryAccessReg_Data = 0x40 | 0x80
else:
self.width = LCD_WIDTH
self.height = LCD_HEIGHT
if Scan_dir == U2D_L2R:
MemoryAccessReg_Data = 0X00 | 0x00 | 0x20
elif Scan_dir == U2D_R2L:
MemoryAccessReg_Data = 0X00 | 0x40 | 0x20
elif Scan_dir == D2U_L2R:
MemoryAccessReg_Data = 0x80 | 0x00 | 0x20
else: #R2L_D2U
MemoryAccessReg_Data = 0x40 | 0x80 | 0x20
#please set (MemoryAccessReg_Data & 0x10) != 1
if (MemoryAccessReg_Data & 0x10) != 1:
self.LCD_X_Adjust = LCD_Y
self.LCD_Y_Adjust = LCD_X
else:
self.LCD_X_Adjust = LCD_X
self.LCD_Y_Adjust = LCD_Y
# Set the read / write scan direction of the frame memory
self.LCD_WriteReg(0x36) #MX, MY, RGB mode
if LCD_1IN44 == 1:
self.LCD_WriteData_8bit( MemoryAccessReg_Data | 0x08) #0x08 set RGB
else:
self.LCD_WriteData_8bit( MemoryAccessReg_Data & 0xf7) #RGB color filter panel
#/********************************************************************************
#function:
# initialization
#********************************************************************************/
def LCD_Init(self, Lcd_ScanDir):
if (config.GPIO_Init() != 0):
return -1
#Turn on the backlight
#GPIO.setup(config.LCD_BL_PIN, GPIO.OUT)
GPIO.output(config.LCD_BL_PIN,GPIO.HIGH)
#Hardware reset
self.LCD_Reset()
#Set the initialization register
self.LCD_InitReg()
#Set the display scan and color transfer modes
self.LCD_SetGramScanWay(Lcd_ScanDir)
config.Driver_Delay_ms(200)
#sleep out
self.LCD_WriteReg(0x11)
config.Driver_Delay_ms(120)
#Turn on the LCD display
self.LCD_WriteReg(0x29)
#/********************************************************************************
#function: Sets the start position and size of the display area
#parameter:
# Xstart : X direction Start coordinates
# Ystart : Y direction Start coordinates
# Xend : X direction end coordinates
# Yend : Y direction end coordinates
#********************************************************************************/
def LCD_SetWindows(self, Xstart, Ystart, Xend, Yend):
#set the X coordinates
self.LCD_WriteReg(0x2A)
self.LCD_WriteData_8bit(0x00)
self.LCD_WriteData_8bit((Xstart & 0xff) + self.LCD_X_Adjust)
self.LCD_WriteData_8bit(0x00)
self.LCD_WriteData_8bit(((Xend - 1) & 0xff) + self.LCD_X_Adjust)
#set the Y coordinates
self.LCD_WriteReg (0x2B)
self.LCD_WriteData_8bit(0x00)
self.LCD_WriteData_8bit((Ystart & 0xff) + self.LCD_Y_Adjust)
self.LCD_WriteData_8bit(0x00)
self.LCD_WriteData_8bit(((Yend - 1) & 0xff )+ self.LCD_Y_Adjust)
self.LCD_WriteReg(0x2C)
def LCD_Clear(self):
#hello
_buffer = [0xff]*(self.width * self.height * 2)
self.LCD_SetWindows(0, 0, self.width, self.height)
GPIO.output(config.LCD_DC_PIN, GPIO.HIGH)
for i in range(0,len(_buffer),4096):
config.SPI_Write_Byte(_buffer[i:i+4096])
def LCD_ShowImage(self,Image,Xstart,Ystart):
if (Image == None):
return
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.LCD_SetWindows(0, 0, self.width , self.height)
GPIO.output(config.LCD_DC_PIN, GPIO.HIGH)
for i in range(0,len(pix),4096):
config.SPI_Write_Byte(pix[i:i+4096])

View File

@ -0,0 +1,73 @@
# /*****************************************************************************
# * | File : config.py
# * | Author :
# * | Info :
# *----------------
# * | This version: V1.0
# * | Date : 2019-12-06
# * | Info :
# ******************************************************************************/
Device_SPI = 1
Device_I2C = 0
Device = Device_SPI
#spi = spidev.SpiDev(0, 0)
##
# @filename : DEV_Config.py
# @brief : LCD hardware interface implements (GPIO, SPI)
# @author : Yehui from Waveshare
#
# Copyright (C) Waveshare July 10 2017
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documnetation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
import spidev
import RPi.GPIO as GPIO
import time
# Pin definition
LCD_RST_PIN = 27
LCD_DC_PIN = 25
LCD_CS_PIN = 8
LCD_BL_PIN = 24
# SPI device, bus = 0, device = 0
SPI = spidev.SpiDev(0, 0)
def epd_digital_write(pin, value):
GPIO.output(pin, value)
def Driver_Delay_ms(xms):
time.sleep(xms / 1000.0)
def SPI_Write_Byte(data):
SPI.writebytes(data)
def GPIO_Init():
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
GPIO.setup(LCD_RST_PIN, GPIO.OUT)
GPIO.setup(LCD_DC_PIN, GPIO.OUT)
GPIO.setup(LCD_CS_PIN, GPIO.OUT)
GPIO.setup(LCD_BL_PIN, GPIO.OUT)
SPI.max_speed_hz = 9000000
SPI.mode = 0b00
return 0;
### END OF FILE ###

View File

@ -0,0 +1,32 @@
# Waveshare 1.44inch LCD HAT
# https://www.waveshare.com/1.44inch-lcd-hat.htm
# https://www.waveshare.com/wiki/1.44inch_LCD_HAT
# Driver: ST7735S
# Interface: SPI
# Display color: RGB, 65K color
# Resolution: 128x128
# Backlight: LED
# Operating voltage: 3.3V
from . import config
from . import LCD_1in44
from PIL import ImageOps
class EPD(object):
def __init__(self):
self.width = 128
self.height = 128
self.LCD = LCD_1in44.LCD()
self.LCD.Lcd_ScanDir = LCD_1in44.SCAN_DIR_DFT #SCAN_DIR_DFT = D2U_L2R
self.LCD.LCD_Init(self.LCD.Lcd_ScanDir)
def init(self):
pass
def clear(self):
#self.LCD.LCD_Clear()
pass
def display(self, image):
rgb_im = ImageOps.colorize(image.convert("L"), black ="green", white ="black")
self.LCD.LCD_ShowImage(rgb_im, 0, 0)

View File

@ -0,0 +1,46 @@
import logging
import pwnagotchi.ui.fonts as fonts
from pwnagotchi.ui.hw.base import DisplayImpl
class Waveshare144lcd(DisplayImpl):
def __init__(self, config):
super(Waveshare144lcd, self).__init__(config, 'waveshare144lcd')
self._display = None
def layout(self):
fonts.setup(10, 8, 10, 18)
self._layout['width'] = 128
self._layout['height'] = 128
self._layout['face'] = (0, 43)
self._layout['name'] = (0, 14)
self._layout['channel'] = (0, 0)
self._layout['aps'] = (0, 71)
self._layout['uptime'] = (0, 25)
self._layout['line1'] = [0, 12, 127, 12]
self._layout['line2'] = [0, 116, 127, 116]
self._layout['friend_face'] = (12, 88)
self._layout['friend_name'] = (1, 103)
self._layout['shakes'] = (26, 117)
self._layout['mode'] = (0, 117)
self._layout['status'] = {
'pos': (65, 26),
'font': fonts.Small,
'max': 12
}
return self._layout
def initialize(self):
logging.info("initializing waveshare 1.44 inch lcd display")
from pwnagotchi.ui.hw.libs.waveshare.lcdhat144.epd import EPD
self._display = EPD()
self._display.init()
self._display.clear()
def render(self, canvas):
self._display.display(canvas)
def clear(self):
pass
#self._display.clear()

View File

@ -109,6 +109,9 @@ def load_config(args):
elif config['ui']['display']['type'] in ('ws_154inch', 'ws154inch', 'waveshare_154inch', 'waveshare154inch'):
config['ui']['display']['type'] = 'waveshare154inch'
elif config['ui']['display']['type'] in ('waveshare144lcd', 'ws_144inch', 'ws144inch', 'waveshare_144inch', 'waveshare144inch'):
config['ui']['display']['type'] = 'waveshare144lcd'
elif config['ui']['display']['type'] in ('ws_213d', 'ws213d', 'waveshare_213d', 'waveshare213d'):
config['ui']['display']['type'] = 'waveshare213d'