basic vcard

This commit is contained in:
wieerwill 2023-10-09 19:24:09 +02:00
commit 88f34588b7
18 changed files with 1682 additions and 0 deletions

168
.gitignore vendored Normal file
View File

@ -0,0 +1,168 @@
# others
qr.bmp
ara.bmp
*.pdf
.vscode
*.code-workspace
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
*.save
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock
# pdm
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
#pdm.lock
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
# in version control.
# https://pdm.fming.dev/#use-with-ide
.pdm.toml
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/
# PyCharm
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/

84
Makefile Normal file
View File

@ -0,0 +1,84 @@
DIR_Config = ./lib/Config
DIR_EPD = ./lib/e-Paper
DIR_FONTS = ./lib/Fonts
DIR_GUI = ./lib/GUI
DIR_Examples = ./examples
DIR_BIN = ./bin
OBJ_C = $(wildcard ${DIR_EPD}/*.c ${DIR_GUI}/*.c ${DIR_Examples}/*.c ${DIR_FONTS}/*.c )
OBJ_O = $(patsubst %.c,${DIR_BIN}/%.o,$(notdir ${OBJ_C}))
RPI_DEV_C = $(wildcard $(DIR_BIN)/dev_hardware_SPI.o $(DIR_BIN)/RPI_sysfs_gpio.o $(DIR_BIN)/DEV_Config.o )
JETSON_DEV_C = $(wildcard $(DIR_BIN)/sysfs_software_spi.o $(DIR_BIN)/sysfs_gpio.o $(DIR_BIN)/DEV_Config.o )
DEBUG = -D DEBUG
USELIB_RPI = USE_BCM2835_LIB
#USELIB_RPI = USE_WIRINGPI_LIB
# USELIB_RPI = USE_DEV_LIB
LIB_RPI=-Wl,--gc-sections
ifeq ($(USELIB_RPI), USE_BCM2835_LIB)
LIB_RPI += -lbcm2835 -lm
else ifeq ($(USELIB_RPI), USE_WIRINGPI_LIB)
LIB_RPI += -lwiringPi -lm
else ifeq ($(USELIB_RPI), USE_DEV_LIB)
LIB_RPI += -lm
endif
DEBUG_RPI = -D $(USELIB_RPI) -D RPI
USELIB_JETSONI = USE_DEV_LIB
# USELIB_JETSONI = USE_HARDWARE_LIB
ifeq ($(USELIB_JETSONI), USE_DEV_LIB)
LIB_JETSONI = -lm
else ifeq ($(USELIB_JETSONI), USE_HARDWARE_LIB)
LIB_JETSONI = -lm
endif
DEBUG_JETSONI = -D $(USELIB_JETSONI) -D JETSON
.PHONY : RPI JETSON clean
RPI:RPI_DEV RPI_epd
JETSON: JETSON_DEV JETSON_epd
TARGET = epd
CC = gcc
MSG = -g -O -ffunction-sections -fdata-sections -Wall
CFLAGS += $(MSG)
RPI_epd:${OBJ_O}
echo $(@)
$(CC) $(CFLAGS) -D RPI $(OBJ_O) $(RPI_DEV_C) -o $(TARGET) $(LIB_RPI) $(DEBUG)
JETSON_epd:${OBJ_O}
echo $(@)
$(CC) $(CFLAGS) $(OBJ_O) $(JETSON_DEV_C) -o $(TARGET) $(LIB_JETSONI) $(DEBUG)
$(shell mkdir -p $(DIR_BIN))
${DIR_BIN}/%.o:$(DIR_Examples)/%.c
$(CC) $(CFLAGS) -c $< -o $@ -I $(DIR_Config) -I $(DIR_GUI) -I $(DIR_EPD) $(DEBUG)
${DIR_BIN}/%.o:$(DIR_EPD)/%.c
$(CC) $(CFLAGS) -c $< -o $@ -I $(DIR_Config) $(DEBUG)
${DIR_BIN}/%.o:$(DIR_FONTS)/%.c
$(CC) $(CFLAGS) -c $< -o $@ $(DEBUG)
${DIR_BIN}/%.o:$(DIR_GUI)/%.c
$(CC) $(CFLAGS) -c $< -o $@ -I $(DIR_Config) $(DEBUG)
RPI_DEV:
$(CC) $(CFLAGS) $(DEBUG_RPI) -c $(DIR_Config)/dev_hardware_SPI.c -o $(DIR_BIN)/dev_hardware_SPI.o $(LIB_RPI) $(DEBUG)
$(CC) $(CFLAGS) $(DEBUG_RPI) -c $(DIR_Config)/RPI_sysfs_gpio.c -o $(DIR_BIN)/RPI_sysfs_gpio.o $(LIB_RPI) $(DEBUG)
$(CC) $(CFLAGS) $(DEBUG_RPI) -c $(DIR_Config)/DEV_Config.c -o $(DIR_BIN)/DEV_Config.o $(LIB_RPI) $(DEBUG)
JETSON_DEV:
$(CC) $(CFLAGS) $(DEBUG_JETSONI) -c $(DIR_Config)/sysfs_software_spi.c -o $(DIR_BIN)/sysfs_software_spi.o $(LIB_JETSONI) $(DEBUG)
$(CC) $(CFLAGS) $(DEBUG_JETSONI) -c $(DIR_Config)/sysfs_gpio.c -o $(DIR_BIN)/sysfs_gpio.o $(LIB_JETSONI) $(DEBUG)
$(CC) $(CFLAGS) $(DEBUG_JETSONI) -c $(DIR_Config)/DEV_Config.c -o $(DIR_BIN)/DEV_Config.o $(LIB_JETSONI) $(DEBUG)
clean :
rm $(DIR_BIN)/*.*
rm $(TARGET)

BIN
pic/2in13.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

BIN
pic/2in13_1.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

BIN
pic/2in13_2.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

BIN
pic/Font.ttc Normal file

Binary file not shown.

View File

@ -0,0 +1,58 @@
#!/usr/bin/python
# -*- coding:utf-8 -*-
import sys
import os
libdir = os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), 'lib')
if os.path.exists(libdir):
sys.path.append(libdir)
import logging
from waveshare_epd import epd2in13_V2
from PIL import Image,ImageDraw
logging.basicConfig(level=logging.DEBUG)
try:
epd = epd2in13_V2.EPD()
epd.init(epd.FULL_UPDATE)
epd.Clear(0xFF)
# clear the frame
image = Image.new('1', (epd.height, epd.width), 255)
draw = ImageDraw.Draw(image)
# add text
# x/y coordinates start at left top with 0,0
# empty reactangle with crossed lines inside
draw.rectangle([(5,5),(55,55)], outline = 0)
draw.line([(5,5),(55,55)], fill = 0, width = 1)
draw.line([(5,55),(55,5)], fill = 0, width = 1)
# filled rectangle
draw.rectangle([(60,5),(110,55)],fill = 0)
# draw a chord rotating in the middle
draw.chord((10, 80, 55, 120), 0, 360, fill = 0)
# draw a simple circe
draw.ellipse((55, 60, 95, 100), outline = 0)
# draw four forth parts of a circle to create a single one
draw.pieslice((55, 60, 95, 100), 90, 180, outline = 0)
draw.pieslice((55, 60, 95, 100), 270, 360, fill = 0)
draw.polygon([(110,0),(110,50),(150,25)], outline = 0)
draw.polygon([(190,0),(190,50),(150,25)], fill = 0)
# add new image to display
epd.display(epd.getbuffer(image))
# set display to sleep mode
epd.sleep()
except IOError as e:
logging.info(e)
except KeyboardInterrupt:
logging.info("ctrl + c:")
epd2in13_V2.epdconfig.module_exit()
exit()

View File

@ -0,0 +1,45 @@
#!/usr/bin/python
# -*- coding:utf-8 -*-
import sys
import os
libdir = os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), 'lib')
if os.path.exists(libdir):
sys.path.append(libdir)
import logging
from waveshare_epd import epd2in13_V2
import time
from PIL import Image,ImageDraw,ImageFont
import traceback
logging.basicConfig(level=logging.DEBUG)
try:
epd = epd2in13_V2.EPD()
epd.init(epd.FULL_UPDATE)
epd.Clear(0xFF)
image = Image.new('1', (epd.height, epd.width), 255) # 255: clear the frame
draw = ImageDraw.Draw(image)
draw.rectangle([(0,0),(50,50)],outline = 0)
draw.rectangle([(55,0),(100,50)],fill = 0)
draw.line([(0,0),(50,50)], fill = 0,width = 1)
draw.line([(0,50),(50,0)], fill = 0,width = 1)
draw.chord((10, 60, 50, 100), 0, 360, fill = 0)
draw.ellipse((55, 60, 95, 100), outline = 0)
draw.pieslice((55, 60, 95, 100), 90, 180, outline = 0)
draw.pieslice((55, 60, 95, 100), 270, 360, fill = 0)
draw.polygon([(110,0),(110,50),(150,25)],outline = 0)
draw.polygon([(190,0),(190,50),(150,25)],fill = 0)
epd.display(epd.getbuffer(image))
epd.sleep()
except IOError as e:
logging.info(e)
except KeyboardInterrupt:
logging.info("ctrl + c:")
epd2in13_V2.epdconfig.module_exit()
exit()

View File

@ -0,0 +1,46 @@
#!/usr/bin/python
# -*- coding:utf-8 -*-
import sys
import os
picdir = os.path.join(os.path.realpath(__file__), 'pic')
libdir = os.path.join(os.path.realpath(__file__), 'lib')
if os.path.exists(libdir):
sys.path.append(libdir)
import logging
import lib.waveshare_epd.epd2in13_V2 as epd2in13_V2
from PIL import Image,ImageDraw,ImageFont
logging.basicConfig(level=logging.DEBUG)
try:
epd = epd2in13_V2.EPD()
epd.init(epd.FULL_UPDATE)
epd.Clear(0xFF)
# import and set font
font15 = ImageFont.truetype(os.path.join(picdir, 'Font.ttc'), 15)
font24 = ImageFont.truetype(os.path.join(picdir, 'Font.ttc'), 24)
# clear the frame
image = Image.new('1', (epd.height, epd.width), 255)
draw = ImageDraw.Draw(image)
# add text
draw.text((40, 5), 'Robert Jeutter', font = font24, fill = 0)
draw.text((10, 35), 'FullStack Software Engineer', font = font15, fill = 0)
draw.text((10, 55), 'Working @ AraCom IT Service AG', font = font15, fill = 0)
draw.text((5, 100), 'find me on github.com/WieErWill', font = font15, fill = 0)
# add new image to display
epd.display(epd.getbuffer(image))
# set display to sleep mode
epd.sleep()
except IOError as e:
logging.info(e)
except KeyboardInterrupt:
logging.info("ctrl + c:")
epd2in13_V2.epdconfig.module_exit()
exit()

View File

@ -0,0 +1,47 @@
#!/usr/bin/python
# -*- coding:utf-8 -*-
import sys
import os
picdir = os.path.join(os.path.realpath(__file__), 'pic')
libdir = os.path.join(os.path.realpath(__file__), 'lib')
if os.path.exists(libdir):
sys.path.append(libdir)
import logging
import lib.waveshare_epd.epd2in13_V2 as epd2in13_V2
from PIL import Image,ImageDraw,ImageFont
logging.basicConfig(level=logging.DEBUG)
try:
epd = epd2in13_V2.EPD()
epd.init(epd.FULL_UPDATE)
epd.Clear(0xFF)
# import and set font
font15 = ImageFont.truetype(os.path.join(picdir, 'Font.ttc'), 15)
font24 = ImageFont.truetype(os.path.join(picdir, 'Font.ttc'), 24)
# clear the frame
image = Image.new('1', (epd.height, epd.width), 255)
draw = ImageDraw.Draw(image)
# add text
draw.text((40, 5), 'Johny Doey', font = font24, fill = 0)
draw.text((10, 35), 'Programmer and Coffinated', font = font15, fill = 0)
draw.text((10, 55), 'Working @ Doe Does Beer Inc.', font = font15, fill = 0)
draw.text((10, 75), 'Mail: johny@doe.com.de', font = font15, fill = 0)
draw.text((5, 100), 'find me on github.com/WieErWill', font = font15, fill = 0)
# add new image to display
epd.display(epd.getbuffer(image))
# set display to sleep mode
epd.sleep()
except IOError as e:
logging.info(e)
except KeyboardInterrupt:
logging.info("ctrl + c:")
epd2in13_V2.epdconfig.module_exit()
exit()

View File

@ -0,0 +1,46 @@
#!/usr/bin/python
# -*- coding:utf-8 -*-
import sys
import os
picdir = os.path.join(os.path.realpath(__file__), 'pic')
libdir = os.path.join(os.path.realpath(__file__), 'lib')
if os.path.exists(libdir):
sys.path.append(libdir)
import logging
import lib.waveshare_epd.epd2in13_V2 as epd2in13_V2
from PIL import Image,ImageDraw,ImageFont
logging.basicConfig(level=logging.DEBUG)
try:
epd = epd2in13_V2.EPD()
epd.init(epd.FULL_UPDATE)
epd.Clear(0xFF)
# import and set font
font15 = ImageFont.truetype(os.path.join(picdir, 'Font.ttc'), 15)
font24 = ImageFont.truetype(os.path.join(picdir, 'Font.ttc'), 24)
# clear the frame
image = Image.new('1', (epd.height, epd.width), 255)
draw = ImageDraw.Draw(image)
# add text
# x/y coordinates start at left top with 0,0
draw.text((5, 5), 'Text Example on Waveshare', font = font15, fill = 0)
draw.text((10, 30), 'write text on e-Paper', font = font24, fill = 0)
draw.text((15, 100), 'find more on github.com/wieerwill', font = font15, fill = 0)
# add new image to display
epd.display(epd.getbuffer(image))
# set display to sleep mode
epd.sleep()
except IOError as e:
logging.info(e)
except KeyboardInterrupt:
logging.info("ctrl + c:")
epd2in13_V2.epdconfig.module_exit()
exit()

154
py_examples/vcard.py Normal file
View File

@ -0,0 +1,154 @@
#!/usr/bin/python
# -*- coding:utf-8 -*-
import sys
import os
picdir = os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), 'pic')
libdir = os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), 'lib')
if os.path.exists(libdir):
sys.path.append(libdir)
import logging
from waveshare_epd import epd2in13_V2
import time
from PIL import Image,ImageDraw,ImageFont
import traceback
logging.basicConfig(level=logging.DEBUG)
min_x=0
max_x=249
min_y=0
max_y=121
print_pause=10
try:
logging.info("vCARD startup")
epd = epd2in13_V2.EPD()
logging.info("init and Clear")
epd.init(epd.FULL_UPDATE)
epd.Clear(0xFF)
time.sleep(0.5)
logging.info("clear frame")
image = Image.new('1', (epd.height, epd.width), 255) # 255: clear the frame
draw = ImageDraw.Draw(image)
time.sleep(0.5)
logging.info("update frame")
epd.init(epd.FULL_UPDATE)
epd.Clear(0xFF)
time.sleep(0.5)
# Settings FONTS
font15 = ImageFont.truetype(os.path.join(picdir, 'Font.ttc'), 15)
font20 = ImageFont.truetype(os.path.join(picdir, 'Font.ttc'), 20)
font25 = ImageFont.truetype(os.path.join(picdir, 'Font.ttc'), 25)
font30 = ImageFont.truetype(os.path.join(picdir, 'Font.ttc'), 30)
font35 = ImageFont.truetype(os.path.join(picdir, 'Font.ttc'), 35)
font45 = ImageFont.truetype(os.path.join(picdir, 'Font.ttc'), 45)
font50 = ImageFont.truetype(os.path.join(picdir, 'Font.ttc'), 60)
image = Image.new('1', (epd.height, epd.width), 255) # 255: clear the frame
draw = ImageDraw.Draw(image)
draw.rectangle([(min_x,min_y),(40,40)], outline = 0) #emtpy rectangle
draw.line([(min_x,min_y),(40,40)], fill = 0,width = 1)
draw.line([(min_x,40),(40,min_y)], fill = 0,width = 1)
draw.rectangle([(45,min_y),(85,40)],fill = 0) #filled rectangle
draw.chord((90, min_y, 130, 40), 0, 360, fill = 0) #filled circle
draw.ellipse((135, min_y, 175, 40), outline = 0)
draw.pieslice((135, min_y, 175, 40), 90, 180, outline = 0)
draw.pieslice((135, min_y, 175, 40), 270, 360, fill = 0)
draw.line([(min_x,max_y-60),(min_x,max_y)], fill = 0,width = 1)
draw.line([(min_x+4,max_y-50),(min_x+4,max_y)], fill = 0,width = 1)
draw.line([(min_x+8,max_y-30),(min_x+8,max_y)], fill = 0,width = 1)
draw.line([(min_x+12,max_y-10),(min_x+12,max_y)], fill = 0,width = 1)
draw.line([(max_x,min_y),(max_x,max_y)], fill = 0,width = 1)
draw.line([(max_x-4,min_y),(max_x-4,max_y/2)], fill = 0,width = 1)
draw.line([(max_x-8,min_y),(max_x-8,max_y/3)], fill = 0,width = 1)
draw.line([(max_x-12,min_y),(max_x-12,max_y/4)], fill = 0,width = 1)
draw.line([(max_x-16,min_y),(max_x-16,max_y/5)], fill = 0,width = 1)
draw.line([(max_x-20,min_y),(max_x-20,max_y/6)], fill = 0,width = 1)
draw.text((20, 40), 'e-Paper vCard', font = font25, fill = 0)
draw.text((30, 70), 'by WieErWill', font = font35, fill = 0)
epd.display(epd.getbuffer(image))
time.sleep(3)
while True:
# clear the frame
image = Image.new('1', (epd.height, epd.width), 255)
draw = ImageDraw.Draw(image)
draw.rectangle([(min_x,min_y),(max_x,max_y)], outline = 0) #emtpy rectangle
draw.rectangle([(min_x+3,min_y+3),(max_x-3,max_y-3)], outline = 0) #emtpy rectangle
draw.text((10, 10), 'Robert Jeutter', font = font35, fill = 0)
draw.text((10, 60), 'Software Engineer', font = font25, fill = 0)
draw.text((10, 85), 'working @ AraCom', font = font25, fill = 0)
epd.display(epd.getbuffer(image))
time.sleep(print_pause)
image = Image.new('1', (epd.height, epd.width), 255)
draw = ImageDraw.Draw(image)
draw.text((2, 5), 'Social Robotics', font = font35, fill = 0)
draw.text((2, 50), 'Machine Learning &', font = font25, fill = 0)
draw.text((2, 85), 'Human-Machine-Coop', font = font20, fill = 0)
epd.display(epd.getbuffer(image))
time.sleep(print_pause)
# clear the frame
imageARA = Image.new('1', (epd.height, epd.width), 255)
#bmp = Image.open(os.path.join(picdir, 'ara.bmp'))
#bmp2 = bmp.resize((250,100))
#imageARA.paste(bmp, (2,5))
draw = ImageDraw.Draw(imageARA)
draw.text((15, 5), 'AraCom', font = font50, fill = 0)
draw.text((13, 65), 'IT Services GmbH', font = font30, fill = 0)
draw.text((14, 100), 'Mail: robert.jeutter@aracom.de', font = font15, fill = 0)
epd.display(epd.getbuffer(imageARA))
time.sleep(print_pause)
# clear the frame
epd.init(epd.FULL_UPDATE)
image = Image.new('1', (epd.height, epd.width), 255)
draw = ImageDraw.Draw(image)
draw.text((50, 5), 'Write me', font = font25, fill = 0)
draw.text((20, 35), 'robert.jeutter', font = font35, fill = 0)
draw.text((20, 70), '@aracom.de', font = font35, fill = 0)
epd.display(epd.getbuffer(image))
time.sleep(print_pause)
# clear the frame
epd.init(epd.FULL_UPDATE)
image = Image.new('1', (epd.height, epd.width), 255)
draw = ImageDraw.Draw(image)
draw.text((25, 2), 'find me on', font = font25, fill = 0)
draw.text((15, 25), 'GitHub.com/', font = font35, fill = 0)
draw.text((20, 60), 'WieErWill', font = font45, fill = 0)
epd.display(epd.getbuffer(image))
time.sleep(print_pause)
imageQR = Image.new('1', (epd.height, epd.width), 255) # 255: clear the frame
bmp = Image.open(os.path.join(picdir, 'qr.bmp'))
imageQR.paste(bmp, (2,2))
draw = ImageDraw.Draw(imageQR)
draw.text((130, 5), 'SCAN ME', font = font25, fill = 0)
draw.text((140, 45), '\(0^0)/', font = font25, fill = 0)
draw.text((130, 90), 'SCAN ME', font = font25, fill = 0)
epd.display(epd.getbuffer(imageQR))
time.sleep(print_pause)
# set display to sleep mode
epd.init(epd.FULL_UPDATE)
epd.Clear(0xFF)
epd.sleep()
time.sleep(print_pause)
except IOError as e:
logging.info(e)
except KeyboardInterrupt:
logging.info("ctrl + c:")
epd2in13_V2.epdconfig.module_exit()
exit()

View File

View File

@ -0,0 +1,227 @@
# *****************************************************************************
# * | File : epd2in13.py
# * | Author : Waveshare team
# * | Function : Electronic paper driver
# * | Info :
# *----------------
# * | This version: V4.0
# * | Date : 2019-06-20
# # | Info : python demo
# -----------------------------------------------------------------------------
# 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 logging
from . import epdconfig
# Display resolution
EPD_WIDTH = 122
EPD_HEIGHT = 250
logger = logging.getLogger(__name__)
class EPD:
def __init__(self):
self.reset_pin = epdconfig.RST_PIN
self.dc_pin = epdconfig.DC_PIN
self.busy_pin = epdconfig.BUSY_PIN
self.cs_pin = epdconfig.CS_PIN
self.width = EPD_WIDTH
self.height = EPD_HEIGHT
lut_full_update = [
0x22, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x11,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00
]
lut_partial_update = [
0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x0F, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00
]
# Hardware reset
def reset(self):
epdconfig.digital_write(self.reset_pin, 1)
epdconfig.delay_ms(200)
epdconfig.digital_write(self.reset_pin, 0)
epdconfig.delay_ms(5)
epdconfig.digital_write(self.reset_pin, 1)
epdconfig.delay_ms(200)
def send_command(self, command):
epdconfig.digital_write(self.dc_pin, 0)
epdconfig.digital_write(self.cs_pin, 0)
epdconfig.spi_writebyte([command])
epdconfig.digital_write(self.cs_pin, 1)
def send_data(self, data):
epdconfig.digital_write(self.dc_pin, 1)
epdconfig.digital_write(self.cs_pin, 0)
epdconfig.spi_writebyte([data])
epdconfig.digital_write(self.cs_pin, 1)
def ReadBusy(self):
while(epdconfig.digital_read(self.busy_pin) == 1): # 0: idle, 1: busy
epdconfig.delay_ms(100)
def TurnOnDisplay(self):
self.send_command(0x22) # DISPLAY_UPDATE_CONTROL_2
self.send_data(0xC4)
self.send_command(0x20) # MASTER_ACTIVATION
self.send_command(0xFF) # TERMINATE_FRAME_READ_WRITE
logger.debug("e-Paper busy")
self.ReadBusy()
logger.debug("e-Paper busy release")
def init(self, lut):
if (epdconfig.module_init() != 0):
return -1
# EPD hardware init start
self.reset()
self.send_command(0x01) # DRIVER_OUTPUT_CONTROL
self.send_data((EPD_HEIGHT - 1) & 0xFF)
self.send_data(((EPD_HEIGHT - 1) >> 8) & 0xFF)
self.send_data(0x00) # GD = 0 SM = 0 TB = 0
self.send_command(0x0C) # BOOSTER_SOFT_START_CONTROL
self.send_data(0xD7)
self.send_data(0xD6)
self.send_data(0x9D)
self.send_command(0x2C) # WRITE_VCOM_REGISTER
self.send_data(0xA8) # VCOM 7C
self.send_command(0x3A) # SET_DUMMY_LINE_PERIOD
self.send_data(0x1A) # 4 dummy lines per gate
self.send_command(0x3B) # SET_GATE_TIME
self.send_data(0x08) # 2us per line
self.send_command(0X3C) # BORDER_WAVEFORM_CONTROL
self.send_data(0x03)
self.send_command(0X11) # DATA_ENTRY_MODE_SETTING
self.send_data(0x03) # X increment; Y increment
# WRITE_LUT_REGISTER
self.send_command(0x32)
for count in range(30):
self.send_data(lut[count])
return 0
##
# @brief: specify the memory area for data R/W
##
def SetWindows(self, x_start, y_start, x_end, y_end):
self.send_command(0x44) # SET_RAM_X_ADDRESS_START_END_POSITION
self.send_data((x_start >> 3) & 0xFF)
self.send_data((x_end >> 3) & 0xFF)
self.send_command(0x45) # SET_RAM_Y_ADDRESS_START_END_POSITION
self.send_data(y_start & 0xFF)
self.send_data((y_start >> 8) & 0xFF)
self.send_data(y_end & 0xFF)
self.send_data((y_end >> 8) & 0xFF)
##
# @brief: specify the start point for data R/W
##
def SetCursor(self, x, y):
self.send_command(0x4E) # SET_RAM_X_ADDRESS_COUNTER
# x point must be the multiple of 8 or the last 3 bits will be ignored
self.send_data((x >> 3) & 0xFF)
self.send_command(0x4F) # SET_RAM_Y_ADDRESS_COUNTER
self.send_data(y & 0xFF)
self.send_data((y >> 8) & 0xFF)
self.ReadBusy()
def getbuffer(self, image):
if self.width%8 == 0:
linewidth = int(self.width/8)
else:
linewidth = int(self.width/8) + 1
buf = [0xFF] * (linewidth * self.height)
image_monocolor = image.convert('1')
imwidth, imheight = image_monocolor.size
pixels = image_monocolor.load()
if(imwidth == self.width and imheight == self.height):
logger.debug("Vertical")
for y in range(imheight):
for x in range(imwidth):
if pixels[x, y] == 0:
# x = imwidth - x
buf[int(x / 8) + y * linewidth] &= ~(0x80 >> (x % 8))
elif(imwidth == self.height and imheight == self.width):
logger.debug("Horizontal")
for y in range(imheight):
for x in range(imwidth):
newx = y
newy = self.height - x - 1
if pixels[x, y] == 0:
# newy = imwidth - newy - 1
buf[int(newx / 8) + newy*linewidth] &= ~(0x80 >> (y % 8))
return buf
def display(self, image):
if self.width%8 == 0:
linewidth = int(self.width/8)
else:
linewidth = int(self.width/8) + 1
self.SetWindows(0, 0, self.width, self.height);
for j in range(0, self.height):
self.SetCursor(0, j);
self.send_command(0x24);
for i in range(0, linewidth):
self.send_data(image[i + j * linewidth])
self.TurnOnDisplay()
def Clear(self, color):
if self.width%8 == 0:
linewidth = int(self.width/8)
else:
linewidth = int(self.width/8) + 1
self.SetWindows(0, 0, self.width, self.height);
for j in range(0, self.height):
self.SetCursor(0, j);
self.send_command(0x24);
for i in range(0, linewidth):
self.send_data(color)
self.TurnOnDisplay()
def sleep(self):
self.send_command(0x10) #enter deep sleep
self.send_data(0x01)
epdconfig.delay_ms(100)
epdconfig.delay_ms(2000)
epdconfig.module_exit()
### END OF FILE ###

View File

@ -0,0 +1,322 @@
# *****************************************************************************
# * | File : epd2in13_V2.py
# * | Author : Waveshare team
# * | Function : Electronic paper driver
# * | Info :
# *----------------
# * | This version: V4.0
# * | Date : 2019-06-20
# # | Info : python demo
# -----------------------------------------------------------------------------
# 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 logging
from . import epdconfig
# Display resolution
EPD_WIDTH = 122
EPD_HEIGHT = 250
logger = logging.getLogger(__name__)
class EPD:
def __init__(self):
self.reset_pin = epdconfig.RST_PIN
self.dc_pin = epdconfig.DC_PIN
self.busy_pin = epdconfig.BUSY_PIN
self.cs_pin = epdconfig.CS_PIN
self.width = EPD_WIDTH
self.height = EPD_HEIGHT
FULL_UPDATE = 0
PART_UPDATE = 1
lut_full_update= [
0x80,0x60,0x40,0x00,0x00,0x00,0x00, #LUT0: BB: VS 0 ~7
0x10,0x60,0x20,0x00,0x00,0x00,0x00, #LUT1: BW: VS 0 ~7
0x80,0x60,0x40,0x00,0x00,0x00,0x00, #LUT2: WB: VS 0 ~7
0x10,0x60,0x20,0x00,0x00,0x00,0x00, #LUT3: WW: VS 0 ~7
0x00,0x00,0x00,0x00,0x00,0x00,0x00, #LUT4: VCOM: VS 0 ~7
0x03,0x03,0x00,0x00,0x02, # TP0 A~D RP0
0x09,0x09,0x00,0x00,0x02, # TP1 A~D RP1
0x03,0x03,0x00,0x00,0x02, # TP2 A~D RP2
0x00,0x00,0x00,0x00,0x00, # TP3 A~D RP3
0x00,0x00,0x00,0x00,0x00, # TP4 A~D RP4
0x00,0x00,0x00,0x00,0x00, # TP5 A~D RP5
0x00,0x00,0x00,0x00,0x00, # TP6 A~D RP6
0x15,0x41,0xA8,0x32,0x30,0x0A,
]
lut_partial_update = [ #20 bytes
0x00,0x00,0x00,0x00,0x00,0x00,0x00, #LUT0: BB: VS 0 ~7
0x80,0x00,0x00,0x00,0x00,0x00,0x00, #LUT1: BW: VS 0 ~7
0x40,0x00,0x00,0x00,0x00,0x00,0x00, #LUT2: WB: VS 0 ~7
0x00,0x00,0x00,0x00,0x00,0x00,0x00, #LUT3: WW: VS 0 ~7
0x00,0x00,0x00,0x00,0x00,0x00,0x00, #LUT4: VCOM: VS 0 ~7
0x0A,0x00,0x00,0x00,0x00, # TP0 A~D RP0
0x00,0x00,0x00,0x00,0x00, # TP1 A~D RP1
0x00,0x00,0x00,0x00,0x00, # TP2 A~D RP2
0x00,0x00,0x00,0x00,0x00, # TP3 A~D RP3
0x00,0x00,0x00,0x00,0x00, # TP4 A~D RP4
0x00,0x00,0x00,0x00,0x00, # TP5 A~D RP5
0x00,0x00,0x00,0x00,0x00, # TP6 A~D RP6
0x15,0x41,0xA8,0x32,0x30,0x0A,
]
# Hardware reset
def reset(self):
epdconfig.digital_write(self.reset_pin, 1)
epdconfig.delay_ms(200)
epdconfig.digital_write(self.reset_pin, 0)
epdconfig.delay_ms(5)
epdconfig.digital_write(self.reset_pin, 1)
epdconfig.delay_ms(200)
def send_command(self, command):
epdconfig.digital_write(self.dc_pin, 0)
epdconfig.digital_write(self.cs_pin, 0)
epdconfig.spi_writebyte([command])
epdconfig.digital_write(self.cs_pin, 1)
def send_data(self, data):
epdconfig.digital_write(self.dc_pin, 1)
epdconfig.digital_write(self.cs_pin, 0)
epdconfig.spi_writebyte([data])
epdconfig.digital_write(self.cs_pin, 1)
def ReadBusy(self):
while(epdconfig.digital_read(self.busy_pin) == 1): # 0: idle, 1: busy
epdconfig.delay_ms(100)
def TurnOnDisplay(self):
self.send_command(0x22)
self.send_data(0xC7)
self.send_command(0x20)
self.ReadBusy()
def TurnOnDisplayPart(self):
self.send_command(0x22)
self.send_data(0x0c)
self.send_command(0x20)
self.ReadBusy()
def init(self, update):
if (epdconfig.module_init() != 0):
return -1
# EPD hardware init start
self.reset()
if(update == self.FULL_UPDATE):
self.ReadBusy()
self.send_command(0x12) # soft reset
self.ReadBusy()
self.send_command(0x74) #set analog block control
self.send_data(0x54)
self.send_command(0x7E) #set digital block control
self.send_data(0x3B)
self.send_command(0x01) #Driver output control
self.send_data(0xF9)
self.send_data(0x00)
self.send_data(0x00)
self.send_command(0x11) #data entry mode
self.send_data(0x01)
self.send_command(0x44) #set Ram-X address start/end position
self.send_data(0x00)
self.send_data(0x0F) #0x0C-->(15+1)*8=128
self.send_command(0x45) #set Ram-Y address start/end position
self.send_data(0xF9) #0xF9-->(249+1)=250
self.send_data(0x00)
self.send_data(0x00)
self.send_data(0x00)
self.send_command(0x3C) #BorderWavefrom
self.send_data(0x03)
self.send_command(0x2C) #VCOM Voltage
self.send_data(0x55) #
self.send_command(0x03)
self.send_data(self.lut_full_update[70])
self.send_command(0x04) #
self.send_data(self.lut_full_update[71])
self.send_data(self.lut_full_update[72])
self.send_data(self.lut_full_update[73])
self.send_command(0x3A) #Dummy Line
self.send_data(self.lut_full_update[74])
self.send_command(0x3B) #Gate time
self.send_data(self.lut_full_update[75])
self.send_command(0x32)
for count in range(70):
self.send_data(self.lut_full_update[count])
self.send_command(0x4E) # set RAM x address count to 0
self.send_data(0x00)
self.send_command(0x4F) # set RAM y address count to 0X127
self.send_data(0xF9)
self.send_data(0x00)
self.ReadBusy()
else:
self.send_command(0x2C) #VCOM Voltage
self.send_data(0x26)
self.ReadBusy()
self.send_command(0x32)
for count in range(70):
self.send_data(self.lut_partial_update[count])
self.send_command(0x37)
self.send_data(0x00)
self.send_data(0x00)
self.send_data(0x00)
self.send_data(0x00)
self.send_data(0x40)
self.send_data(0x00)
self.send_data(0x00)
self.send_command(0x22)
self.send_data(0xC0)
self.send_command(0x20)
self.ReadBusy()
self.send_command(0x3C) #BorderWavefrom
self.send_data(0x01)
return 0
def getbuffer(self, image):
if self.width%8 == 0:
linewidth = int(self.width/8)
else:
linewidth = int(self.width/8) + 1
buf = [0xFF] * (linewidth * self.height)
image_monocolor = image.convert('1')
imwidth, imheight = image_monocolor.size
pixels = image_monocolor.load()
if(imwidth == self.width and imheight == self.height):
logger.debug("Vertical")
for y in range(imheight):
for x in range(imwidth):
if pixels[x, y] == 0:
x = imwidth - x
buf[int(x / 8) + y * linewidth] &= ~(0x80 >> (x % 8))
elif(imwidth == self.height and imheight == self.width):
logger.debug("Horizontal")
for y in range(imheight):
for x in range(imwidth):
newx = y
newy = self.height - x - 1
if pixels[x, y] == 0:
newy = imwidth - newy - 1
buf[int(newx / 8) + newy*linewidth] &= ~(0x80 >> (y % 8))
return buf
def display(self, image):
if self.width%8 == 0:
linewidth = int(self.width/8)
else:
linewidth = int(self.width/8) + 1
self.send_command(0x24)
for j in range(0, self.height):
for i in range(0, linewidth):
self.send_data(image[i + j * linewidth])
self.TurnOnDisplay()
def displayPartial(self, image):
if self.width%8 == 0:
linewidth = int(self.width/8)
else:
linewidth = int(self.width/8) + 1
self.send_command(0x24)
for j in range(0, self.height):
for i in range(0, linewidth):
self.send_data(image[i + j * linewidth])
self.send_command(0x26)
for j in range(0, self.height):
for i in range(0, linewidth):
self.send_data(~image[i + j * linewidth])
self.TurnOnDisplayPart()
def displayPartBaseImage(self, image):
if self.width%8 == 0:
linewidth = int(self.width/8)
else:
linewidth = int(self.width/8) + 1
self.send_command(0x24)
for j in range(0, self.height):
for i in range(0, linewidth):
self.send_data(image[i + j * linewidth])
self.send_command(0x26)
for j in range(0, self.height):
for i in range(0, linewidth):
self.send_data(image[i + j * linewidth])
self.TurnOnDisplay()
def Clear(self, color):
if self.width%8 == 0:
linewidth = int(self.width/8)
else:
linewidth = int(self.width/8) + 1
# logger.debug(linewidth)
self.send_command(0x24)
for j in range(0, self.height):
for i in range(0, linewidth):
self.send_data(color)
# self.send_command(0x26)
# for j in range(0, self.height):
# for i in range(0, linewidth):
# self.send_data(color)
self.TurnOnDisplay()
def sleep(self):
# self.send_command(0x22) #POWER OFF
# self.send_data(0xC3)
# self.send_command(0x20)
self.send_command(0x10) #enter deep sleep
self.send_data(0x03)
epdconfig.delay_ms(2000)
epdconfig.module_exit()
### END OF FILE ###

View File

@ -0,0 +1,396 @@
# *****************************************************************************
# * | File : epd2in13_V3.py
# * | Author : Waveshare team
# * | Function : Electronic paper driver
# * | Info :
# *----------------
# * | This version: V1.1
# * | Date : 2021-10-30
# # | Info : python demo
# -----------------------------------------------------------------------------
# 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 logging
from . import epdconfig
# Display resolution
EPD_WIDTH = 122
EPD_HEIGHT = 250
logger = logging.getLogger(__name__)
class EPD:
def __init__(self):
self.reset_pin = epdconfig.RST_PIN
self.dc_pin = epdconfig.DC_PIN
self.busy_pin = epdconfig.BUSY_PIN
self.cs_pin = epdconfig.CS_PIN
self.width = EPD_WIDTH
self.height = EPD_HEIGHT
lut_partial_update= [
0x0,0x40,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
0x80,0x80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
0x40,0x40,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
0x0,0x80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
0x14,0x0,0x0,0x0,0x0,0x0,0x0,
0x1,0x0,0x0,0x0,0x0,0x0,0x0,
0x1,0x0,0x0,0x0,0x0,0x0,0x0,
0x0,0x0,0x0,0x0,0x0,0x0,0x0,
0x0,0x0,0x0,0x0,0x0,0x0,0x0,
0x0,0x0,0x0,0x0,0x0,0x0,0x0,
0x0,0x0,0x0,0x0,0x0,0x0,0x0,
0x0,0x0,0x0,0x0,0x0,0x0,0x0,
0x0,0x0,0x0,0x0,0x0,0x0,0x0,
0x0,0x0,0x0,0x0,0x0,0x0,0x0,
0x0,0x0,0x0,0x0,0x0,0x0,0x0,
0x0,0x0,0x0,0x0,0x0,0x0,0x0,
0x22,0x22,0x22,0x22,0x22,0x22,0x0,0x0,0x0,
0x22,0x17,0x41,0x00,0x32,0x36,
]
lut_full_update = [
0x80,0x4A,0x40,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
0x40,0x4A,0x80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
0x80,0x4A,0x40,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
0x40,0x4A,0x80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
0xF,0x0,0x0,0x0,0x0,0x0,0x0,
0xF,0x0,0x0,0xF,0x0,0x0,0x2,
0xF,0x0,0x0,0x0,0x0,0x0,0x0,
0x1,0x0,0x0,0x0,0x0,0x0,0x0,
0x0,0x0,0x0,0x0,0x0,0x0,0x0,
0x0,0x0,0x0,0x0,0x0,0x0,0x0,
0x0,0x0,0x0,0x0,0x0,0x0,0x0,
0x0,0x0,0x0,0x0,0x0,0x0,0x0,
0x0,0x0,0x0,0x0,0x0,0x0,0x0,
0x0,0x0,0x0,0x0,0x0,0x0,0x0,
0x0,0x0,0x0,0x0,0x0,0x0,0x0,
0x0,0x0,0x0,0x0,0x0,0x0,0x0,
0x22,0x22,0x22,0x22,0x22,0x22,0x0,0x0,0x0,
0x22,0x17,0x41,0x0,0x32,0x36,
]
'''
function :Hardware reset
parameter:
'''
def reset(self):
epdconfig.digital_write(self.reset_pin, 1)
epdconfig.delay_ms(20)
epdconfig.digital_write(self.reset_pin, 0)
epdconfig.delay_ms(2)
epdconfig.digital_write(self.reset_pin, 1)
epdconfig.delay_ms(20)
'''
function :send command
parameter:
command : Command register
'''
def send_command(self, command):
epdconfig.digital_write(self.dc_pin, 0)
epdconfig.digital_write(self.cs_pin, 0)
epdconfig.spi_writebyte([command])
epdconfig.digital_write(self.cs_pin, 1)
'''
function :send data
parameter:
data : Write data
'''
def send_data(self, data):
epdconfig.digital_write(self.dc_pin, 1)
epdconfig.digital_write(self.cs_pin, 0)
epdconfig.spi_writebyte([data])
epdconfig.digital_write(self.cs_pin, 1)
'''
function :Wait until the busy_pin goes LOW
parameter:
'''
def ReadBusy(self):
logger.debug("e-Paper busy")
while(epdconfig.digital_read(self.busy_pin) == 1): # 0: idle, 1: busy
epdconfig.delay_ms(10)
logger.debug("e-Paper busy release")
'''
function : Turn On Display
parameter:
'''
def TurnOnDisplay(self):
self.send_command(0x22) # Display Update Control
self.send_data(0xC7)
self.send_command(0x20) # Activate Display Update Sequence
self.ReadBusy()
'''
function : Turn On Display Part
parameter:
'''
def TurnOnDisplayPart(self):
self.send_command(0x22) # Display Update Control
self.send_data(0x0f) # fast:0x0c, quality:0x0f, 0xcf
self.send_command(0x20) # Activate Display Update Sequence
self.ReadBusy()
'''
function : Set lut
parameter:
lut : lut data
'''
def Lut(self, lut):
self.send_command(0x32)
for i in range(0, 153):
self.send_data(lut[i])
self.ReadBusy()
'''
function : Send lut data and configuration
parameter:
lut : lut data
'''
def SetLut(self, lut):
self.Lut(lut)
self.send_command(0x3f)
self.send_data(lut[153])
self.send_command(0x03) # gate voltage
self.send_data(lut[154])
self.send_command(0x04) # source voltage
self.send_data(lut[155]) # VSH
self.send_data(lut[156]) # VSH2
self.send_data(lut[157]) # VSL
self.send_command(0x2c) # VCOM
self.send_data(lut[158])
'''
function : Setting the display window
parameter:
xstart : X-axis starting position
ystart : Y-axis starting position
xend : End position of X-axis
yend : End position of Y-axis
'''
def SetWindow(self, x_start, y_start, x_end, y_end):
self.send_command(0x44) # SET_RAM_X_ADDRESS_START_END_POSITION
# x point must be the multiple of 8 or the last 3 bits will be ignored
self.send_data((x_start>>3) & 0xFF)
self.send_data((x_end>>3) & 0xFF)
self.send_command(0x45) # SET_RAM_Y_ADDRESS_START_END_POSITION
self.send_data(y_start & 0xFF)
self.send_data((y_start >> 8) & 0xFF)
self.send_data(y_end & 0xFF)
self.send_data((y_end >> 8) & 0xFF)
'''
function : Set Cursor
parameter:
x : X-axis starting position
y : Y-axis starting position
'''
def SetCursor(self, x, y):
self.send_command(0x4E) # SET_RAM_X_ADDRESS_COUNTER
# x point must be the multiple of 8 or the last 3 bits will be ignored
self.send_data(x & 0xFF)
self.send_command(0x4F) # SET_RAM_Y_ADDRESS_COUNTER
self.send_data(y & 0xFF)
self.send_data((y >> 8) & 0xFF)
'''
function : Initialize the e-Paper register
parameter:
'''
def init(self):
if (epdconfig.module_init() != 0):
return -1
# EPD hardware init start
self.reset()
self.ReadBusy()
self.send_command(0x12) #SWRESET
self.ReadBusy()
self.send_command(0x01) #Driver output control
self.send_data(0xf9)
self.send_data(0x00)
self.send_data(0x00)
self.send_command(0x11) #data entry mode
self.send_data(0x03)
self.SetWindow(0, 0, self.width-1, self.height-1)
self.SetCursor(0, 0)
self.send_command(0x3c)
self.send_data(0x05)
self.send_command(0x21) # Display update control
self.send_data(0x00)
self.send_data(0x80)
self.send_command(0x18)
self.send_data(0x80)
self.ReadBusy()
self.SetLut(self.lut_full_update)
return 0
'''
function : Display images
parameter:
image : Image data
'''
def getbuffer(self, image):
img = image
imwidth, imheight = img.size
if(imwidth == self.width and imheight == self.height):
img = img.convert('1')
elif(imwidth == self.height and imheight == self.width):
# image has correct dimensions, but needs to be rotated
img = img.rotate(90, expand=True).convert('1')
else:
logger.warning("Wrong image dimensions: must be " + str(self.width) + "x" + str(self.height))
# return a blank buffer
return [0x00] * (int(self.width/8) * self.height)
buf = bytearray(img.tobytes('raw'))
return buf
'''
function : Sends the image buffer in RAM to e-Paper and displays
parameter:
image : Image data
'''
def display(self, image):
if self.width%8 == 0:
linewidth = int(self.width/8)
else:
linewidth = int(self.width/8) + 1
self.send_command(0x24)
for j in range(0, self.height):
for i in range(0, linewidth):
self.send_data(image[i + j * linewidth])
self.TurnOnDisplay()
'''
function : Sends the image buffer in RAM to e-Paper and partial refresh
parameter:
image : Image data
'''
def displayPartial(self, image):
if self.width%8 == 0:
linewidth = int(self.width/8)
else:
linewidth = int(self.width/8) + 1
epdconfig.digital_write(self.reset_pin, 0)
epdconfig.delay_ms(1)
epdconfig.digital_write(self.reset_pin, 1)
self.SetLut(self.lut_partial_update)
self.send_command(0x37)
self.send_data(0x00)
self.send_data(0x00)
self.send_data(0x00)
self.send_data(0x00)
self.send_data(0x00)
self.send_data(0x40)
self.send_data(0x00)
self.send_data(0x00)
self.send_data(0x00)
self.send_data(0x00)
self.send_command(0x3C) #BorderWavefrom
self.send_data(0x80)
self.send_command(0x22)
self.send_data(0xC0)
self.send_command(0x20)
self.ReadBusy()
self.SetWindow(0, 0, self.width - 1, self.height - 1)
self.SetCursor(0, 0)
self.send_command(0x24) # WRITE_RAM
for j in range(0, self.height):
for i in range(0, linewidth):
self.send_data(image[i + j * linewidth])
self.TurnOnDisplayPart()
'''
function : Refresh a base image
parameter:
image : Image data
'''
def displayPartBaseImage(self, image):
if self.width%8 == 0:
linewidth = int(self.width/8)
else:
linewidth = int(self.width/8) + 1
self.send_command(0x24)
for j in range(0, self.height):
for i in range(0, linewidth):
self.send_data(image[i + j * linewidth])
self.send_command(0x26)
for j in range(0, self.height):
for i in range(0, linewidth):
self.send_data(image[i + j * linewidth])
self.TurnOnDisplay()
'''
function : Clear screen
parameter:
'''
def Clear(self, color):
if self.width%8 == 0:
linewidth = int(self.width/8)
else:
linewidth = int(self.width/8) + 1
# logger.debug(linewidth)
self.send_command(0x24)
for j in range(0, self.height):
for i in range(0, linewidth):
self.send_data(color)
self.TurnOnDisplay()
'''
function : Enter sleep mode
parameter:
'''
def sleep(self):
self.send_command(0x10) #enter deep sleep
self.send_data(0x01)
epdconfig.delay_ms(2000)
epdconfig.module_exit()
### END OF FILE ###

76
readme.md Normal file
View File

@ -0,0 +1,76 @@
# RaspberryPiZero 2.13in Display
This projects uses a single RaspberryPi Zero (v1) and a Waveshare 2.13" display, both connected via soldered GPIO-Hat. Languages used will be Python (C also possible).
! Disclaimer: The libraries used here are not made by me. Those are the original library files from Waveshare (see below for sources). Any modifications will be annoted.
## Next Steps and Roadmap
-[x] Text Examples: show single and multiple line texts
-[x] Image Examples: show pictures and modify pictures before show
-[x] Draw Examples: draw lines, circles and rectangles
-[x] Simple Card: a digital vCard you can always carry along and show off
-[x] Slideshow: Show multiple slides in a row repeatingly
-[ ] Partial Display Updates: only update partial display parts instead the whole screen
-[x] digital vCard with multiple pages, sliding and QR Codes
-[ ] start scripts with autostart while booting up
-[ ] get and show different RaspberryPi Stats
## Set up your RPi
For the 2.13" display the RaspberryPi Zero fits perfect as they match each others size quite well.
With a proper cover you can get a nice display case you can place nearly everywhere without risking your hardware to get harmed.
Install Raspbian or any other linux you like on your SD Card and set up your SSH connection. SSH will be the prefered way to connect up your RPi.
Working mainly on your home network, it can be handy to set up your pi with a local hostname like `raspberrypi.local` so you can reach it with `ssh username@raspberrypi.local` even if the RPis IP changes.
### Connect your display
If you got the display or display hat without pinheader you have to connect it by hand.
Pin connections can be viewed in `\py_lib\epdconfig.py` and here:
```
EPD => Jetson Nano/RPI(BCM)
VCC -> 3.3
GND -> GND
DIN -> 10(SPI0_MOSI)
CLK -> 11(SPI0_SCK)
CS -> 8(SPI0_CS0)
DC -> 25
RST -> 17
BUSY -> 24
```
## Use with python
### Install libraries
In order to access the display trough python you need some extra libraries:
```bash
sudo apt-get update
sudo apt-get install python3-pip
sudo apt-get install python3-pil
sudo pip3 install RPi.GPIO
```
### Basic and test use
The waveshare team already made some example code you can get from [Waveshare Github](https://github.com/waveshare/e-Paper) or look inside the `py_examples` folder (a small copy of the waveshare repo with changes).
To run a script simply type: `sudo python epd_2in9bc_test.py` and switch the file name to what you want to start.
 
## Use with C
You need to compile the program, this will generate the executable file. After that you can run the executable to start your programm
```bash
make
sudo ./epd
```
If you modify the program, you need to re-compile
```bash
make clear
make
```
## Library Structure
- \c_lib\Config\: hardware interface layer files
- \c_lib\GUI\: basic image processing functions
- \c_lib\Fonts\: for some commonly used ascii fonts
- \c_lib\E-paper\: the ink screen driver functions
## Sources
Display drivers and information from [Waveshare Wiki](https://www.waveshare.com/wiki/2.13inch_e-Paper_HAT)
RaspberryPi Zero info from [raspberrypi.org/](https://www.raspberrypi.org/)

13
setup.py Normal file
View File

@ -0,0 +1,13 @@
import sys, os
from setuptools import setup
dependencies = ['Pillow', 'RPi.GPIO', 'spidev']
setup(
name='waveshare-epd',
description='Waveshare e-Paper Display',
author='Waveshare',
package_dir={'': 'lib'},
packages=['waveshare_epd'],
install_requires=dependencies,
)