diff --git a/__pycache__/metar_display.cpython-39.pyc b/__pycache__/metar_display.cpython-39.pyc new file mode 100644 index 0000000..c8144af Binary files /dev/null and b/__pycache__/metar_display.cpython-39.pyc differ diff --git a/__pycache__/metar_layouts.cpython-39.pyc b/__pycache__/metar_layouts.cpython-39.pyc new file mode 100644 index 0000000..945dbd1 Binary files /dev/null and b/__pycache__/metar_layouts.cpython-39.pyc differ diff --git a/__pycache__/metar_remarks.cpython-39.pyc b/__pycache__/metar_remarks.cpython-39.pyc new file mode 100644 index 0000000..396eab8 Binary files /dev/null and b/__pycache__/metar_remarks.cpython-39.pyc differ diff --git a/__pycache__/metar_routines.cpython-39.pyc b/__pycache__/metar_routines.cpython-39.pyc new file mode 100644 index 0000000..0b2d2f8 Binary files /dev/null and b/__pycache__/metar_routines.cpython-39.pyc differ diff --git a/__pycache__/metar_settings.cpython-39.pyc b/__pycache__/metar_settings.cpython-39.pyc new file mode 100644 index 0000000..6b69342 Binary files /dev/null and b/__pycache__/metar_settings.cpython-39.pyc differ diff --git a/__pycache__/shutdown.cpython-39.pyc b/__pycache__/shutdown.cpython-39.pyc new file mode 100644 index 0000000..3370bd4 Binary files /dev/null and b/__pycache__/shutdown.cpython-39.pyc differ diff --git a/data.txt b/data.txt new file mode 100644 index 0000000..589c95c --- /dev/null +++ b/data.txt @@ -0,0 +1,4 @@ +kflg +-2 +3600 +0 diff --git a/icons/100_clouds.png b/icons/100_clouds.png new file mode 100644 index 0000000..8518030 Binary files /dev/null and b/icons/100_clouds.png differ diff --git a/icons/25_clouds.png b/icons/25_clouds.png new file mode 100644 index 0000000..01dbd58 Binary files /dev/null and b/icons/25_clouds.png differ diff --git a/icons/50_clouds.png b/icons/50_clouds.png new file mode 100644 index 0000000..50fbd67 Binary files /dev/null and b/icons/50_clouds.png differ diff --git a/icons/atm.png b/icons/atm.png new file mode 100644 index 0000000..b14572f Binary files /dev/null and b/icons/atm.png differ diff --git a/icons/baro0.png b/icons/baro0.png new file mode 100644 index 0000000..eb59149 Binary files /dev/null and b/icons/baro0.png differ diff --git a/icons/baro100.png b/icons/baro100.png new file mode 100644 index 0000000..a82fa5a Binary files /dev/null and b/icons/baro100.png differ diff --git a/icons/baro25.png b/icons/baro25.png new file mode 100644 index 0000000..15a6ac5 Binary files /dev/null and b/icons/baro25.png differ diff --git a/icons/baro50.png b/icons/baro50.png new file mode 100644 index 0000000..82575d8 Binary files /dev/null and b/icons/baro50.png differ diff --git a/icons/baro75.png b/icons/baro75.png new file mode 100644 index 0000000..51b5156 Binary files /dev/null and b/icons/baro75.png differ diff --git a/icons/cloud.png b/icons/cloud.png new file mode 100644 index 0000000..50fbd67 Binary files /dev/null and b/icons/cloud.png differ diff --git a/icons/cloudy night.png b/icons/cloudy night.png new file mode 100644 index 0000000..d40c2fd Binary files /dev/null and b/icons/cloudy night.png differ diff --git a/icons/cloudy.png b/icons/cloudy.png new file mode 100644 index 0000000..8518030 Binary files /dev/null and b/icons/cloudy.png differ diff --git a/icons/cold.png b/icons/cold.png new file mode 100644 index 0000000..c876403 Binary files /dev/null and b/icons/cold.png differ diff --git a/icons/compass.png b/icons/compass.png new file mode 100644 index 0000000..3a0e152 Binary files /dev/null and b/icons/compass.png differ diff --git a/icons/drizzle.png b/icons/drizzle.png new file mode 100644 index 0000000..1a07db1 Binary files /dev/null and b/icons/drizzle.png differ diff --git a/icons/east.png b/icons/east.png new file mode 100644 index 0000000..4b84b59 Binary files /dev/null and b/icons/east.png differ diff --git a/icons/eclipse.png b/icons/eclipse.png new file mode 100644 index 0000000..0bd4599 Binary files /dev/null and b/icons/eclipse.png differ diff --git a/icons/factory.png b/icons/factory.png new file mode 100644 index 0000000..e068d77 Binary files /dev/null and b/icons/factory.png differ diff --git a/icons/few_clouds.png b/icons/few_clouds.png new file mode 100644 index 0000000..dd240ad Binary files /dev/null and b/icons/few_clouds.png differ diff --git a/icons/hot.png b/icons/hot.png new file mode 100644 index 0000000..e13010d Binary files /dev/null and b/icons/hot.png differ diff --git a/icons/humidity0.png b/icons/humidity0.png new file mode 100644 index 0000000..048b146 Binary files /dev/null and b/icons/humidity0.png differ diff --git a/icons/humidity100.png b/icons/humidity100.png new file mode 100644 index 0000000..fccca45 Binary files /dev/null and b/icons/humidity100.png differ diff --git a/icons/humidity25.png b/icons/humidity25.png new file mode 100644 index 0000000..40d633a Binary files /dev/null and b/icons/humidity25.png differ diff --git a/icons/humidity50.png b/icons/humidity50.png new file mode 100644 index 0000000..e7e3331 Binary files /dev/null and b/icons/humidity50.png differ diff --git a/icons/humidity75.png b/icons/humidity75.png new file mode 100644 index 0000000..7e117fa Binary files /dev/null and b/icons/humidity75.png differ diff --git a/icons/mild.png b/icons/mild.png new file mode 100644 index 0000000..76bda30 Binary files /dev/null and b/icons/mild.png differ diff --git a/icons/mist.png b/icons/mist.png new file mode 100644 index 0000000..76003d3 Binary files /dev/null and b/icons/mist.png differ diff --git a/icons/night.png b/icons/night.png new file mode 100644 index 0000000..9f1d5a9 Binary files /dev/null and b/icons/night.png differ diff --git a/icons/north.png b/icons/north.png new file mode 100644 index 0000000..5d7cf6c Binary files /dev/null and b/icons/north.png differ diff --git a/icons/northeast.png b/icons/northeast.png new file mode 100644 index 0000000..68d4f84 Binary files /dev/null and b/icons/northeast.png differ diff --git a/icons/northwest.png b/icons/northwest.png new file mode 100644 index 0000000..81a4ea2 Binary files /dev/null and b/icons/northwest.png differ diff --git a/icons/rain.png b/icons/rain.png new file mode 100644 index 0000000..87c3f68 Binary files /dev/null and b/icons/rain.png differ diff --git a/icons/rainbow.png b/icons/rainbow.png new file mode 100644 index 0000000..06b6eba Binary files /dev/null and b/icons/rainbow.png differ diff --git a/icons/rainy.png b/icons/rainy.png new file mode 100644 index 0000000..87c3f68 Binary files /dev/null and b/icons/rainy.png differ diff --git a/icons/snow.png b/icons/snow.png new file mode 100644 index 0000000..0f08806 Binary files /dev/null and b/icons/snow.png differ diff --git a/icons/snowy.png b/icons/snowy.png new file mode 100644 index 0000000..363deb2 Binary files /dev/null and b/icons/snowy.png differ diff --git a/icons/south.png b/icons/south.png new file mode 100644 index 0000000..caa6f35 Binary files /dev/null and b/icons/south.png differ diff --git a/icons/southeast.png b/icons/southeast.png new file mode 100644 index 0000000..cc96522 Binary files /dev/null and b/icons/southeast.png differ diff --git a/icons/southwest.png b/icons/southwest.png new file mode 100644 index 0000000..26e0a7a Binary files /dev/null and b/icons/southwest.png differ diff --git a/icons/sun.png b/icons/sun.png new file mode 100644 index 0000000..20a6f92 Binary files /dev/null and b/icons/sun.png differ diff --git a/icons/sunrise.png b/icons/sunrise.png new file mode 100644 index 0000000..07402ba Binary files /dev/null and b/icons/sunrise.png differ diff --git a/icons/sunset.png b/icons/sunset.png new file mode 100644 index 0000000..22be9ab Binary files /dev/null and b/icons/sunset.png differ diff --git a/icons/testpattern3.png b/icons/testpattern3.png new file mode 100644 index 0000000..314cde1 Binary files /dev/null and b/icons/testpattern3.png differ diff --git a/icons/thunder.png b/icons/thunder.png new file mode 100644 index 0000000..f0817da Binary files /dev/null and b/icons/thunder.png differ diff --git a/icons/tornado.png b/icons/tornado.png new file mode 100644 index 0000000..8058249 Binary files /dev/null and b/icons/tornado.png differ diff --git a/icons/umbrella.png b/icons/umbrella.png new file mode 100644 index 0000000..1cb7073 Binary files /dev/null and b/icons/umbrella.png differ diff --git a/icons/vis.png b/icons/vis.png new file mode 100644 index 0000000..8b7a34d Binary files /dev/null and b/icons/vis.png differ diff --git a/icons/west.png b/icons/west.png new file mode 100644 index 0000000..ebf28ff Binary files /dev/null and b/icons/west.png differ diff --git a/icons/wind vane1.png b/icons/wind vane1.png new file mode 100644 index 0000000..e3d8cd9 Binary files /dev/null and b/icons/wind vane1.png differ diff --git a/icons/windvanehigh.png b/icons/windvanehigh.png new file mode 100644 index 0000000..6ccfc0d Binary files /dev/null and b/icons/windvanehigh.png differ diff --git a/icons/windvanelow.png b/icons/windvanelow.png new file mode 100644 index 0000000..3b95013 Binary files /dev/null and b/icons/windvanelow.png differ diff --git a/icons/windvanemed.png b/icons/windvanemed.png new file mode 100644 index 0000000..f26f0a2 Binary files /dev/null and b/icons/windvanemed.png differ diff --git a/icons/windy.png b/icons/windy.png new file mode 100644 index 0000000..fecb2be Binary files /dev/null and b/icons/windy.png differ diff --git a/icons/windy1.png b/icons/windy1.png new file mode 100644 index 0000000..2f183cc Binary files /dev/null and b/icons/windy1.png differ diff --git a/metar_display.py b/metar_display.py new file mode 100644 index 0000000..7f30301 --- /dev/null +++ b/metar_display.py @@ -0,0 +1,222 @@ +# metar_display.py +# Metar Display - Mark Harris +# Altered from https://github.com/aerodynamics-py/WEATHER_STATION_PI +# +# Added a number of bold fonts +# Added a number of drawing routines for rounded corners, etc. + +# Imports +from PIL import Image, ImageDraw, ImageFont, ImageOps +import requests +import urllib.request + +# Setup fonts that could be chosen. Default font_choice is #5 +# Look in '/usr/share/fonts/truetype/' to see what is installed on +# specific system and change as necessary. +font_choice = 5 +if font_choice == 1: + project_font = "/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf" +elif font_choice == 2: + project_font = "/usr/share/fonts/truetype/droid/DroidSansFallbackFull.ttf" +elif font_choice == 3: + project_font = "/usr/share/fonts/truetype/freefont/FreeMonoBoldOblique.ttf" +elif font_choice == 4: + project_font = "/usr/share/fonts/truetype/liberation2/LiberationMono-Bold.ttf" +elif font_choice == 5: + project_font = "/usr/share/fonts/truetype/noto/NotoMono-Regular.ttf" +elif font_choice == 6: + project_font = "/usr/share/fonts/truetype/piboto/Piboto-Bold.ttf" +elif font_choice == 7: + project_font = "/usr/share/fonts/truetype/quicksand/Quicksand-Bold.ttf" +else: + project_font = "font/Open_Sans/OpenSans-SemiBold.ttf" + +font8 = ImageFont.truetype(project_font, 8) +font12 = ImageFont.truetype(project_font, 12) +font14 = ImageFont.truetype(project_font, 14) +font16 = ImageFont.truetype(project_font, 16) +font20 = ImageFont.truetype(project_font, 20) +font24 = ImageFont.truetype(project_font, 24) +font36 = ImageFont.truetype(project_font, 36) +font48 = ImageFont.truetype(project_font, 48) +font96 = ImageFont.truetype(project_font, 96) +font196 = ImageFont.truetype(project_font, 196) +font296 = ImageFont.truetype(project_font, 296) + +project_fontbold = "/usr/share/fonts/truetype/liberation2/LiberationMono-Bold.ttf" +font8b = ImageFont.truetype(project_fontbold, 8) +font12b = ImageFont.truetype(project_fontbold, 12) +font14b = ImageFont.truetype(project_fontbold, 14) +font16b = ImageFont.truetype(project_fontbold, 16) +font20b = ImageFont.truetype(project_fontbold, 20) +font24b = ImageFont.truetype(project_fontbold, 24) +font36b = ImageFont.truetype(project_fontbold, 36) +font48b = ImageFont.truetype(project_fontbold, 48) +font96b = ImageFont.truetype(project_fontbold, 96) +font196b = ImageFont.truetype(project_fontbold, 196) +font296b = ImageFont.truetype(project_fontbold, 296) + + +class Metar: + def __init__(self, airport): + self.data = requests.get( + f"https://api.weather.gov/stations/"+airport+"/observations/latest", timeout=5).json() + self.data2 = requests.get( + f"https://api.weather.gov/stations/"+airport, timeout=5).json() + requests.session().close() + pass + + def update(self, airport): + self.data = requests.get( + f"https://api.weather.gov/stations/"+airport+"/observations/latest", timeout=5).json() + self.data2 = requests.get( + f"https://api.weather.gov/stations/"+airport, timeout=5).json() + requests.session().close() + return self.data, self.data2 + + +class Display: + def __init__(self): + self.im_black = Image.new('1', (800, 480), 255) + self.im_red = Image.new('1', (800, 480), 255) + self.draw_black = ImageDraw.Draw(self.im_black) + self.draw_red = ImageDraw.Draw(self.im_red) + + + def draw_text_centered(self, ypos, text, font): + w, h = self.draw_black.textsize(text) + #print(w,h) # debug + self.draw_black.text(((800-w-100)/2, ypos), text, fill=0, font=font) + + + def draw_circle(self, x, y, r, c): + if c == "b": + self.draw_black.ellipse((x - r, y - r, x + r, y + r), fill=0) + elif c == "wb": + self.draw_black.ellipse((x - r, y - r, x + r, y + r), fill=255) + elif c == "wr": + self.draw_red.ellipse((x - r, y - r, x + r, y + r), fill=255) + else: + self.draw_red.ellipse((x - r, y - r, x + r, y + r), fill=0) + + + def draw_circle_outline(self, x, y, r, w, c): + r2 = r - w +# print(r,r2) # debug + if c == "b": + self.draw_black.ellipse((x - r, y - r, x + r, y + r), fill=0) + self.draw_black.ellipse((x - r2, y - r2, x + r2, y + r2), fill=255) + else: + self.draw_red.ellipse((x - r, y - r, x + r, y + r), fill=0) + self.draw_red.ellipse((x - r2, y - r2, x + r2, y + r2), fill=255) + + + def draw_icon(self, x, y, c, l, h, icon): + im_icon = Image.open("/home/pi/metar/icons/" + icon + ".png") + im_icon = im_icon.convert("RGBA") #"LA" + im_icon = im_icon.resize((l, h)) + + if c == "b": + self.im_black.paste(im_icon, (x, y), im_icon) + elif c=="wb": # Invert black image if necessary + if im_icon.mode == 'RGBA': + r,g,b,a = im_icon.split() + rgb_image = Image.merge('RGB', (r,g,b)) + inverted_image = ImageOps.invert(rgb_image) + r2,g2,b2 = inverted_image.split() + final_transparent_image = Image.merge('RGBA', (r2,g2,b2,a)) + else: + inverted_image = ImageOps.invert(im_icon) + self.im_black.paste(inverted_image, (x, y), im_icon) + elif c=="wr":# Invert red image if necessary + if im_icon.mode == 'RGBA': + r,g,b,a = im_icon.split() + rgb_image = Image.merge('RGB', (r,g,b)) + inverted_image = ImageOps.invert(rgb_image) + r2,g2,b2 = inverted_image.split() + final_transparent_image = Image.merge('RGBA', (r2,g2,b2,a)) + else: + inverted_image = ImageOps.invert(im_icon) + self.im_red.paste(inverted_image, (x, y), im_icon) + else: + self.im_red.paste(im_icon, (x, y), im_icon) + + + def round_box(self, up_left_x, up_left_y, box_width, box_height, radius, box_color="b", box_fill=0, line_width=5): + up_right_x = up_left_x + box_width + up_right_y = up_left_y + low_left_x = up_left_x + low_left_y = up_left_y + box_height + low_right_x = up_right_x + low_right_y = low_left_y + + if box_color == "b": + # longest/shortest box + self.draw_black.rectangle((up_left_x-radius, up_left_y, low_right_x+radius, low_right_y), fill=box_fill, outline=0, width=line_width) + # skinniest/tallest box + self.draw_black.rectangle((up_left_x, up_left_y-radius, low_right_x, low_right_y+radius), fill=box_fill, outline=0, width=line_width) + if line_width == 0: + cir_color = "wb" + else: + cir_color = "b" + # Upper Left corner circle + self.draw_circle(up_left_x, up_left_y, radius, cir_color) + # Upper Right corner circle + self.draw_circle(up_right_x, up_right_y, radius, cir_color) + # Lower Left corner circle + self.draw_circle(low_left_x, low_left_y, radius, cir_color) + # Lower Right corner circle + self.draw_circle(low_right_x, low_right_y, radius, cir_color) + else: + # longest/shortest box + self.draw_red.rectangle((up_left_x-radius, up_left_y, low_right_x+radius, low_right_y), fill=box_fill, outline=0, width=line_width) + # skinniest/tallest box + self.draw_red.rectangle((up_left_x, up_left_y-radius, low_right_x, low_right_y+radius), fill=box_fill, outline=0, width=line_width) + if line_width == 0: + cir_color = "wr" + else: + cir_color = "r" + # Upper Left corner circle + self.draw_circle(up_left_x, up_left_y, radius, cir_color) + # Upper Right corner circle + self.draw_circle(up_right_x, up_right_y, radius, cir_color) + # Lower Left corner circle + self.draw_circle(low_left_x, low_left_y, radius, cir_color) + # Lower Right corner circle + self.draw_circle(low_right_x, low_right_y, radius, cir_color) + + + def round_line(self, up_left_x, up_left_y, box_width, box_height, radius, box_color="b", box_fill=0, line_width=5): # -SPACING, box_width-SPACING-(line_width*2) + self.round_box(up_left_x, up_left_y, box_width, box_height, radius, box_color, 0, line_width) + self.round_box(up_left_x+line_width, up_left_y+line_width, box_width-(line_width*2), box_height-(line_width*2), radius/2, box_color, 255, 0) + + + def show_pic(self, url, pos_x, pos_y, color="b"): + urllib.request.urlretrieve(url, "temp_pic.png") + + im_pic = Image.open("temp_pic.png") + + if color == "b": + self.im_black.paste(im_pic, (pos_x, pos_y)) + elif color == "wb": # Invert black image if necessary + if im_pic.mode == 'RGBA': + r,g,b,a = im_pic.split() + rgb_image = Image.merge('RGB', (r,g,b)) + inverted_image = ImageOps.invert(rgb_image) + r2,g2,b2 = inverted_image.split() + final_transparent_image = Image.merge('RGBA', (r2,g2,b2,a)) + else: + inverted_image = ImageOps.invert(im_pic) + self.im_black.paste(inverted_image, (pos_x, pos_y)) + elif color == "wr": # Invert red image if necessary + if im_pic.mode == 'RGBA': + r,g,b,a = im_pic.split() + rgb_image = Image.merge('RGB', (r,g,b)) + inverted_image = ImageOps.invert(rgb_image) + r2,g2,b2 = inverted_image.split() + final_transparent_image = Image.merge('RGBA', (r2,g2,b2,a)) + else: + inverted_image = ImageOps.invert(im_pic) + self.im_red.paste(inverted_image, (pos_x, pos_y)) + else: + self.im_red.paste(im_pic, (pos_x, pos_y)) diff --git a/metar_layouts.py b/metar_layouts.py new file mode 100644 index 0000000..c99b3f4 --- /dev/null +++ b/metar_layouts.py @@ -0,0 +1,1652 @@ +# metar_layouts.py +# Layouts for Metar Display - Mark Harris +# +# Each Layout offers a different look and amount of information. +# More can be created by starting at the bottom and pasting the following; +# ################ +# # Layout ? # +# ################ +# # My Own Created Layout +# def layout?(display, metar, remarks, print_table, use_remarks): +# # Get metar data along with flightcategory and related icon +# decoded_airport,decoded_time,decoded_wndir,decoded_wnspd,decoded_wngust,decoded_vis,\ +# decoded_alt,decoded_temp,decoded_dew,decoded_cloudlayers,decoded_weather,decoded_rvr \ +# = decode_rawmessage(metar.data["properties"]["rawMessage"]) # pass airport name +# flightcategory, icon = flight_category(metar) +# airport = decoded_airport +# +# Then using the other layouts as a guide create your own. +# You must add the name of your layout to 2 locations; +# metar_main.py to the variable "layout_list" +# epaper.html to the ' + + + + + +

+ +

+
+ +
+ https://www.world-airport-codes.com/ to lookup ICAO ID's +

+ +
+ +

+ +
+ +

+ +
+ +

+ + +

+ +

+ +


+ +
+ {% with messages = get_flashed_messages() %} + {% if messages %} +
+ {% for message in messages %} +
{{ message }} + {% endfor %} + + {% endif %} + {% endwith %} +
+
+ +
+

+

+ Basic Display with Large Flight Category Letters and METAR String +

+
+

+

+ METAR String with individual weather items with dynamic icons. +

+
+

+

+ Formatted Weather Data with dynamic icons. +

+
+

+

+ Basic Large Letter Flight Category. +

+
+

+

+ 3-Area Display with Large Flight Category Letters and weather data. +

+ + + + + + + + diff --git a/waveshare_epd/__init__.py b/waveshare_epd/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/waveshare_epd/__pycache__/__init__.cpython-39.pyc b/waveshare_epd/__pycache__/__init__.cpython-39.pyc new file mode 100644 index 0000000..39d81ef Binary files /dev/null and b/waveshare_epd/__pycache__/__init__.cpython-39.pyc differ diff --git a/waveshare_epd/__pycache__/epd7in5b_V2.cpython-39.pyc b/waveshare_epd/__pycache__/epd7in5b_V2.cpython-39.pyc new file mode 100644 index 0000000..561f76a Binary files /dev/null and b/waveshare_epd/__pycache__/epd7in5b_V2.cpython-39.pyc differ diff --git a/waveshare_epd/__pycache__/epdconfig.cpython-39.pyc b/waveshare_epd/__pycache__/epdconfig.cpython-39.pyc new file mode 100644 index 0000000..f34b15f Binary files /dev/null and b/waveshare_epd/__pycache__/epdconfig.cpython-39.pyc differ diff --git a/waveshare_epd/epd1in02.py b/waveshare_epd/epd1in02.py new file mode 100644 index 0000000..24f10a8 --- /dev/null +++ b/waveshare_epd/epd1in02.py @@ -0,0 +1,349 @@ +# ***************************************************************************** +# * | File : epd1in54.py +# * | Author : Waveshare team +# * | Function : Electronic paper driver +# * | Info : +# *---------------- +# * | This version: V1.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 = 80 +EPD_HEIGHT = 128 + +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 screen update LUT + + lut_w1 =[ + 0x60, 0x5A, 0x5A, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ] + + lut_b1 =[ + 0x90, 0x5A, 0x5A, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ] + + # partial screen update LUT + lut_w = [ + 0x60, 0x01, 0x01, 0x00, 0x00, 0x01, + 0x80, 0x1f, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ] + + lut_b = [ + 0x90, 0x01, 0x01, 0x00, 0x00, 0x01, + 0x40, 0x1f, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 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) # module reset + epdconfig.delay_ms(2) + 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): + logger.debug("e-Paper busy") + self.send_command(0x71) + busy = epdconfig.digital_read(self.busy_pin) + busy =not(busy & 0x01) + while(busy): + self.send_command(0x71) + busy = epdconfig.digital_read(self.busy_pin) + busy =not(busy & 0x01) + epdconfig.delay_ms(800) + logger.debug("e-Paper busy release") + + def TurnOnDisplay(self): + self.send_command(0x12) + epdconfig.delay_ms(10) + self.ReadBusy() + + def SetFulltReg(self): + self.send_command(0x23) + for count in range(0, 42): + self.send_data(self.lut_w1[count]) + + self.send_command(0x24) + for count in range(0, 42): + self.send_data(self.lut_b1[count]) + + def SetPartReg(self): + self.send_command(0x23) + for count in range(0, 42): + self.send_data(self.lut_w[count]) + + self.send_command(0x24) + for count in range(0, 42): + self.send_data(self.lut_b[count]) + + def Init(self): + if (epdconfig.module_init() != 0): + return -1 + # EPD hardware init start + self.reset() + + self.send_command(0xD2) + self.send_data(0x3F) + + self.send_command(0x00) + self.send_data (0x6F) #from outside + + self.send_command(0x01) #power setting + self.send_data (0x03) + self.send_data (0x00) + self.send_data (0x2b) + self.send_data (0x2b) + + self.send_command(0x06) #Configuring the charge pump + self.send_data(0x3f) + + self.send_command(0x2A) #Setting XON and the options of LUT + self.send_data(0x00) + self.send_data(0x00) + + self.send_command(0x30) #Set the clock frequency + self.send_data(0x17) #50Hz + + self.send_command(0x50) #Set VCOM and data output interval + self.send_data(0x57) + + self.send_command(0x60) #Set The non-overlapping period of Gate and Source. + self.send_data(0x22) + + self.send_command(0x61) #resolution setting + self.send_data (0x50) #source 128 + self.send_data (0x80) + + self.send_command(0x82) #sets VCOM_DC value + self.send_data(0x12) #-1v + + self.send_command(0xe3)#Set POWER SAVING + self.send_data(0x33) + self.SetFulltReg() + self.send_command(0x04) #power on + self.ReadBusy() + # EPD hardware init end + return 0 + + def Partial_Init(self): + self.reset() + + self.send_command(0xD2) + self.send_data(0x3F) + + self.send_command(0x00) + self.send_data (0x6F) #from outside + + self.send_command(0x01) #power setting + self.send_data (0x03) + self.send_data (0x00) + self.send_data (0x2b) + self.send_data (0x2b) + + self.send_command(0x06) #Configuring the charge pump + self.send_data(0x3f) + + self.send_command(0x2A) #Setting XON and the options of LUT + self.send_data(0x00) + self.send_data(0x00) + + self.send_command(0x30) #Set the clock frequency + self.send_data(0x17) + + self.send_command(0x50) #Set VCOM and data output interval + self.send_data(0xf2) + + self.send_command(0x60) #Set The non-overlapping period of Gate and Source. + self.send_data(0x22) + + self.send_command(0x82) #Set VCOM_DC value + self.send_data(0x12)#-1v + + self.send_command(0xe3)#Set POWER SAVING + self.send_data(0x33) + + self.SetPartReg() + + self.send_command(0x04)#Set POWER SAVING + self.ReadBusy() + # EPD hardware init end + return 0 + + def getbuffer(self, image): + buf = [0xFF] * (int(self.width / 8) * 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("Horizontal") + for y in range(imheight): + for x in range(imwidth): + # Set the bits for the column of pixels at the current position. + if pixels[x, y] == 0: + buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) + elif(imwidth == self.height and imheight == self.width): + logger.debug("Vertical") + for y in range(imheight): + for x in range(imwidth): + newx = y + newy = self.height - x - 1 + if pixels[x, y] == 0: + buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) + return buf + + def Display(self, image): + if (image == None): + return + # Width = (self.width % 8 == 0)? (self.width / 8 ): (self.width / 8 + 1) + if(self.width % 8 == 0): + Width = self.width / 8 + else: + Width = self.width / 8 + 1 + + self.send_command(0x10) + for j in range(0, self.height): + for i in range(0, int(Width)): + self.send_data(0xff) + + self.send_command(0x13) + for j in range(0, self.height): + for i in range(0, int(Width)): + self.send_data(image[i + j * int(Width)]) + self.TurnOnDisplay() + + def Clear(self): + # Width = (self.width % 8 == 0)? (self.width / 8 ): (self.width / 8 + 1) + if(self.width % 8 == 0): + Width = self.width / 8 + else: + Width = self.width / 8 + 1 + + Height = self.height + + self.send_command(0x10) + for j in range(0, Height): + for i in range(0, int(Width)): + self.send_data(0x00) + + self.send_command(0x13) + for j in range(0, Height): + for i in range(0, int(Width)): + self.send_data(0xff) + self.TurnOnDisplay() + + def DisplayPartial(self, old_Image, Image): + + # Set partial Windows */ + self.send_command(0x91) #This command makes the display enter partial mode + self.send_command(0x90) #resolution setting + self.send_data(0) #x-start + self.send_data(79) #x-end + + self.send_data(0) + self.send_data(127) #y-end + self.send_data(0x00) + + # Width = (self.width % 8 == 0)? (self.width / 8 ): (self.width / 8 + 1) + if(self.width % 8 == 0): + Width = self.width / 8 + else: + Width = self.width / 8 + 1 + + Height = self.height + # send data + self.send_command(0x10) + for j in range(0, Height): + for i in range(0, int(Width)): + self.send_data(old_Image[i + j * int(Width)]) + + self.send_command(0x13) + for j in range(0, Height): + for i in range(0, int(Width)): + self.send_data(Image[i + j * int(Width)]) + + # Set partial refresh + self.TurnOnDisplay() + + def Sleep(self): + self.send_command(0x50) + self.send_data(0xf7) + self.send_command(0x02) + self.ReadBusy() + self.send_command(0x07) + self.send_data(0xA5) + epdconfig.delay_ms(200) + + epdconfig.delay_ms(2000) + epdconfig.module_exit() + +### END OF FILE ### + diff --git a/waveshare_epd/epd1in54.py b/waveshare_epd/epd1in54.py new file mode 100644 index 0000000..4fdba04 --- /dev/null +++ b/waveshare_epd/epd1in54.py @@ -0,0 +1,260 @@ +# ***************************************************************************** +# * | File : epd1in54.py +# * | Author : Waveshare team +# * | Function : Electronic paper driver +# * | Info : +# *---------------- +# * | This version: V3.1 +# * | Date : 2019-06-20 +# # | Info : python demo +# ----------------------------------------------------------------------------- +# V3.1(2019-06-18): +# 2.remove commands define: +# #define PANEL_SETTING 0x00 +# #define POWER_SETTING 0x01 +# #define POWER_OFF 0x02 +# #define POWER_OFF_SEQUENCE_SETTING 0x03 +# #define POWER_ON 0x04 +# #define POWER_ON_MEASURE 0x05 +# #define BOOSTER_SOFT_START 0x06 +# #define DEEP_SLEEP 0x07 +# #define DATA_START_TRANSMISSION_1 0x10 +# #define DATA_STOP 0x11 +# #define DISPLAY_REFRESH 0x12 +# #define DATA_START_TRANSMISSION_2 0x13 +# #define PLL_CONTROL 0x30 +# #define TEMPERATURE_SENSOR_COMMAND 0x40 +# #define TEMPERATURE_SENSOR_CALIBRATION 0x41 +# #define TEMPERATURE_SENSOR_WRITE 0x42 +# #define TEMPERATURE_SENSOR_READ 0x43 +# #define VCOM_AND_DATA_INTERVAL_SETTING 0x50 +# #define LOW_POWER_DETECTION 0x51 +# #define TCON_SETTING 0x60 +# #define TCON_RESOLUTION 0x61 +# #define SOURCE_AND_GATE_START_SETTING 0x62 +# #define GET_STATUS 0x71 +# #define AUTO_MEASURE_VCOM 0x80 +# #define VCOM_VALUE 0x81 +# #define VCM_DC_SETTING_REGISTER 0x82 +# #define PROGRAM_MODE 0xA0 +# #define ACTIVE_PROGRAM 0xA1 +# #define READ_OTP_DATA 0xA2 +# ----------------------------------------------------------------------------- +# V3.0(2018-11-01): +# # 1.Remove: +# digital_write(self, pin, value) +# digital_read(self, pin) +# delay_ms(self, delaytime) +# set_lut(self, lut) +# self.lut = self.lut_full_update +# * 2.Change: +# display_frame -> TurnOnDisplay +# set_memory_area -> SetWindow +# set_memory_pointer -> SetCursor +# * 3.How to use +# epd = epd1in54.EPD() +# epd.init(epd.lut_full_update) +# image = Image.new('1', (epd1in54.EPD_WIDTH, epd1in54.EPD_HEIGHT), 255) +# ... +# drawing ...... +# ... +# epd.display(getbuffer(image)) +# ******************************************************************************/ +# 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 = 200 +EPD_HEIGHT = 200 + +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 = [ + 0x02, 0x02, 0x01, 0x11, 0x12, 0x12, 0x22, 0x22, + 0x66, 0x69, 0x69, 0x59, 0x58, 0x99, 0x99, 0x88, + 0x00, 0x00, 0x00, 0x00, 0xF8, 0xB4, 0x13, 0x51, + 0x35, 0x51, 0x51, 0x19, 0x01, 0x00 + ] + + lut_partial_update = [ + 0x10, 0x18, 0x18, 0x08, 0x18, 0x18, 0x08, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x13, 0x14, 0x44, 0x12, + 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) # module reset + 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): + logger.debug("e-Paper busy") + while(epdconfig.digital_read(self.busy_pin) == 1): # 0: idle, 1: busy + epdconfig.delay_ms(100) + logger.debug("e-Paper busy release") + + 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 + + self.ReadBusy() + + 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) + + 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 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(0x11) # DATA_ENTRY_MODE_SETTING + self.send_data(0x03) # X increment Y increment + + # set the look-up table register + self.send_command(0x32) + for i in range(0, len(lut)): + self.send_data(lut[i]) + # EPD hardware init end + return 0 + + def getbuffer(self, image): + buf = [0xFF] * (int(self.width / 8) * 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("Horizontal") + for y in range(imheight): + for x in range(imwidth): + # Set the bits for the column of pixels at the current position. + if pixels[x, y] == 0: + buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) + elif(imwidth == self.height and imheight == self.width): + logger.debug("Vertical") + for y in range(imheight): + for x in range(imwidth): + newx = y + newy = self.height - x - 1 + if pixels[x, y] == 0: + buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) + return buf + + def display(self, image): + if (image == None): + return + + self.SetWindow(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, int(self.width / 8)): + self.send_data(image[i + j * int(self.width / 8)]) + self.TurnOnDisplay() + + def Clear(self, color): + # self.SetWindow(0, 0, self.width - 1, self.height - 1) + # send the color data + self.SetWindow(0, 0, self.width, self.height) + # epdconfig.digital_write(self.dc_pin, 1) + # epdconfig.digital_write(self.cs_pin, 0) + for j in range(0, self.height): + self.SetCursor(0, j) + self.send_command(0x24) + for i in range(0, int(self.width / 8)): + self.send_data(color) + # epdconfig.digital_write(self.cs_pin, 1) + self.TurnOnDisplay() + + def sleep(self): + self.send_command(0x10) # DEEP_SLEEP_MODE + self.send_data(0x01) + + epdconfig.delay_ms(2000) + epdconfig.module_exit() +### END OF FILE ### + diff --git a/waveshare_epd/epd1in54_V2.py b/waveshare_epd/epd1in54_V2.py new file mode 100644 index 0000000..b489d9a --- /dev/null +++ b/waveshare_epd/epd1in54_V2.py @@ -0,0 +1,316 @@ +# ***************************************************************************** +# * | File : epd1in54_V2.py +# * | Author : Waveshare team +# * | Function : Electronic paper driver +# * | Info : +# *---------------- +# * | This version: V1 +# * | 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 = 200 +EPD_HEIGHT = 200 + +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 + + # waveform full refresh + WF_Full_1IN54 = [ + 0x80, 0x48, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x40, 0x48, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x80, 0x48, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x40, 0x48, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xA, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x8, 0x1, 0x0, 0x8, 0x1, 0x0, 0x2, + 0xA, 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, 0x0, 0x32, 0x20 + ] + + # waveform partial refresh(fast) + WF_PARTIAL_1IN54_0 = [ + 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, + 0xF,0x0,0x0,0x0,0x0,0x0,0x0, + 0x1,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,0x0,0x0,0x0,0x0,0x0,0x0, + 0x22,0x22,0x22,0x22,0x22,0x22,0x0,0x0,0x0, + 0x02,0x17,0x41,0xB0,0x32,0x28, + ] + + # 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): + logger.debug("e-Paper busy") + while(epdconfig.digital_read(self.busy_pin) == 1): + epdconfig.delay_ms(20) + logger.debug("e-Paper busy release") + + def TurnOnDisplay(self): + self.send_command(0x22) # DISPLAY_UPDATE_CONTROL_2 + self.send_data(0xc7) + self.send_command(0x20) # MASTER_ACTIVATION + self.ReadBusy() + + def TurnOnDisplayPart(self): + self.send_command(0x22) # DISPLAY_UPDATE_CONTROL_2 + self.send_data(0xcF) + self.send_command(0x20) # MASTER_ACTIVATION + self.ReadBusy() + + def lut(self, lut): + self.send_command(0x32) # WRITE_LUT_REGISTER + for i in range(0, len(lut)): + self.send_data(lut[i]) + + def set_lut(self, lut): + self.lut(lut) + + self.send_command(0x3f) + self.send_data(lut[153]) + + self.send_command(0x03) + self.send_data(lut[154]) + + self.send_command(0x04) + self.send_data(lut[155]) + self.send_data(lut[156]) + self.send_data(lut[157]) + + self.send_command(0x2c) + self.send_data(lut[158]) + + def SetWindows(self, Xstart, Ystart, Xend, Yend): + self.send_command(0x44); # SET_RAM_X_ADDRESS_START_END_POSITION + self.send_data((Xstart>>3) & 0xFF); + self.send_data((Xend>>3) & 0xFF); + + self.send_command(0x45); # SET_RAM_Y_ADDRESS_START_END_POSITION + self.send_data(Ystart & 0xFF); + self.send_data((Ystart >> 8) & 0xFF); + self.send_data(Yend & 0xFF); + self.send_data((Yend >> 8) & 0xFF); + + + def SetCursor(self, Xstart, Ystart): + self.send_command(0x4E); # SET_RAM_X_ADDRESS_COUNTER + self.send_data(Xstart & 0xFF); + + self.send_command(0x4F); # SET_RAM_Y_ADDRESS_COUNTER + self.send_data(Ystart & 0xFF); + self.send_data((Ystart >> 8) & 0xFF); + + def init(self, isPartial): + if (epdconfig.module_init() != 0): + return -1 + + if(isPartial): + logger.debug("partial refresh") + self.reset() + self.ReadBusy() + + self.set_lut(self.WF_PARTIAL_1IN54_0) + + 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() + + else: + logger.debug("full refresh") + # EPD hardware init start + self.reset() + + self.ReadBusy() + self.send_command(0x12) # SWRESET (software reset) + self.ReadBusy() + + self.send_command(0x01) # DRIVER_OUTPUT_CONTROL + self.send_data(0xC7) # (EPD_HEIGHT - 1) & 0xFF + self.send_data(0x00) # ((EPD_HEIGHT - 1) >> 8) & 0xFF + self.send_data(0x01) # GD = 0 SM = 0 TB = 0 + + self.send_command(0x11) # data entry mode + self.send_data(0x01) + + self.SetWindows(0, self.height-1, self.width-1, 0) # Set Windows + + self.send_command(0x3C) # BorderWavefrom + self.send_data(0x01) + + self.send_command(0x18) + self.send_data(0x80) + + self.send_command(0x22) # #Load Temperature and waveform setting. + self.send_data(0XB1) + self.send_command(0x20) + + self.SetCursor(0, self.height-1) # Set Cursor + + self.ReadBusy() + + self.set_lut(self.WF_Full_1IN54) # Set lut + + def Clear(self, color): + self.send_command(0x24) + for j in range(0, self.height): + for i in range(0, int(self.width / 8)): + self.send_data(color) + + self.TurnOnDisplay() + + def getbuffer(self, image): + buf = [0xFF] * (int(self.width/8) * 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("Horizontal") + for y in range(imheight): + for x in range(imwidth): + # Set the bits for the column of pixels at the current position. + if pixels[x, y] == 0: + buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) + elif(imwidth == self.height and imheight == self.width): + logger.debug("Vertical") + for y in range(imheight): + for x in range(imwidth): + newx = y + newy = self.height - x - 1 + if pixels[x, y] == 0: + buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) + return buf + + def display(self, image): + if (image == None): + return + + self.send_command(0x24) + for j in range(0, self.height): + for i in range(0, int(self.width / 8)): + self.send_data(image[i + j * int(self.width / 8)]) + self.TurnOnDisplay() + + def displayPartBaseImage(self, image): + if (image == None): + return + + self.send_command(0x24) + for j in range(0, self.height): + for i in range(0, int(self.width / 8)): + self.send_data(image[i + j * int(self.width / 8)]) + + self.send_command(0x26) + for j in range(0, self.height): + for i in range(0, int(self.width / 8)): + self.send_data(image[i + j * int(self.width / 8)]) + + self.TurnOnDisplay() + + def displayPart(self, image): + if (image == None): + return + + self.send_command(0x24) + for j in range(0, self.height): + for i in range(0, int(self.width / 8)): + self.send_data(image[i + j * int(self.width / 8)]) + + self.TurnOnDisplayPart() + + def sleep(self): + self.send_command(0x10) # DEEP_SLEEP_MODE + self.send_data(0x01) + + epdconfig.delay_ms(2000) + epdconfig.module_exit() + +### END OF FILE ### + diff --git a/waveshare_epd/epd1in54b.py b/waveshare_epd/epd1in54b.py new file mode 100644 index 0000000..fe8fa17 --- /dev/null +++ b/waveshare_epd/epd1in54b.py @@ -0,0 +1,222 @@ +# ***************************************************************************** +# * | File : epd1in54b.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 = 200 +EPD_HEIGHT = 200 + +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_vcom0 = [0x0E, 0x14, 0x01, 0x0A, 0x06, 0x04, 0x0A, 0x0A, 0x0F, 0x03, 0x03, 0x0C, 0x06, 0x0A, 0x00] + lut_w = [0x0E, 0x14, 0x01, 0x0A, 0x46, 0x04, 0x8A, 0x4A, 0x0F, 0x83, 0x43, 0x0C, 0x86, 0x0A, 0x04] + lut_b = [0x0E, 0x14, 0x01, 0x8A, 0x06, 0x04, 0x8A, 0x4A, 0x0F, 0x83, 0x43, 0x0C, 0x06, 0x4A, 0x04] + lut_g1 = [0x8E, 0x94, 0x01, 0x8A, 0x06, 0x04, 0x8A, 0x4A, 0x0F, 0x83, 0x43, 0x0C, 0x06, 0x0A, 0x04] + lut_g2 = [0x8E, 0x94, 0x01, 0x8A, 0x06, 0x04, 0x8A, 0x4A, 0x0F, 0x83, 0x43, 0x0C, 0x06, 0x0A, 0x04] + lut_vcom1 = [0x03, 0x1D, 0x01, 0x01, 0x08, 0x23, 0x37, 0x37, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] + lut_red0 = [0x83, 0x5D, 0x01, 0x81, 0x48, 0x23, 0x77, 0x77, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] + lut_red1 = [0x03, 0x1D, 0x01, 0x01, 0x08, 0x23, 0x37, 0x37, 0x01, 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) # module reset + 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): + logger.debug("e-Paper busy") + while(epdconfig.digital_read(self.busy_pin) == 0): + epdconfig.delay_ms(100) + logger.debug("e-Paper busy release") + + def set_lut_bw(self): + self.send_command(0x20) # vcom + for count in range(0, 15): + self.send_data(self.lut_vcom0[count]) + self.send_command(0x21) # ww -- + for count in range(0, 15): + self.send_data(self.lut_w[count]) + self.send_command(0x22) # bw r + for count in range(0, 15): + self.send_data(self.lut_b[count]) + self.send_command(0x23) # wb w + for count in range(0, 15): + self.send_data(self.lut_g1[count]) + self.send_command(0x24) # bb b + for count in range(0, 15): + self.send_data(self.lut_g2[count]) + + def set_lut_red(self): + self.send_command(0x25) + for count in range(0, 15): + self.send_data(self.lut_vcom1[count]) + self.send_command(0x26) + for count in range(0, 15): + self.send_data(self.lut_red0[count]) + self.send_command(0x27) + for count in range(0, 15): + self.send_data(self.lut_red1[count]) + + def init(self): + if (epdconfig.module_init() != 0): + return -1 + # EPD hardware init start + self.reset() + + self.send_command(0x01) # POWER_SETTING + self.send_data(0x07) + self.send_data(0x00) + self.send_data(0x08) + self.send_data(0x00) + self.send_command(0x06) # BOOSTER_SOFT_START + self.send_data(0x07) + self.send_data(0x07) + self.send_data(0x07) + self.send_command(0x04) # POWER_ON + + self.ReadBusy() + + self.send_command(0X00) # PANEL_SETTING + self.send_data(0xCF) + self.send_command(0X50) # VCOM_AND_DATA_INTERVAL_SETTING + self.send_data(0x17) + self.send_command(0x30) # PLL_CONTROL + self.send_data(0x39) + self.send_command(0x61) # TCON_RESOLUTION set x and y + self.send_data(0xC8) + self.send_data(0x00) + self.send_data(0xC8) + self.send_command(0x82) # VCM_DC_SETTING_REGISTER + self.send_data(0x0E) + + self.set_lut_bw() + self.set_lut_red() + return 0 + + def getbuffer(self, image): + buf = [0xFF] * int(self.width * self.height / 8) + # Set buffer to value of Python Imaging Library image. + # Image must be in mode 1. + image_monocolor = image.convert('1') + imwidth, imheight = image_monocolor.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)) + + pixels = image_monocolor.load() + for y in range(self.height): + for x in range(self.width): + # Set the bits for the column of pixels at the current position. + if pixels[x, y] == 0: + buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) + return buf + + def display(self, blackimage, redimage): + # send black data + if (blackimage != None): + self.send_command(0x10) # DATA_START_TRANSMISSION_1 + for i in range(0, int(self.width * self.height / 8)): + temp = 0x00 + for bit in range(0, 4): + if (blackimage[i] & (0x80 >> bit) != 0): + temp |= 0xC0 >> (bit * 2) + self.send_data(temp) + temp = 0x00 + for bit in range(4, 8): + if (blackimage[i] & (0x80 >> bit) != 0): + temp |= 0xC0 >> ((bit - 4) * 2) + self.send_data(temp) + + # send red data + if (redimage != None): + self.send_command(0x13) # DATA_START_TRANSMISSION_2 + for i in range(0, int(self.width * self.height / 8)): + self.send_data(redimage[i]) + + self.send_command(0x12) # DISPLAY_REFRESH + self.ReadBusy() + + def Clear(self): + self.send_command(0x10) # DATA_START_TRANSMISSION_1 + for i in range(0, int(self.width * self.height / 8)): + self.send_data(0xFF) + self.send_data(0xFF) + + self.send_command(0x13) # DATA_START_TRANSMISSION_2 + for i in range(0, int(self.width * self.height / 8)): + self.send_data(0xFF) + + self.send_command(0x12) # DISPLAY_REFRESH + self.ReadBusy() + + def sleep(self): + self.send_command(0x50) # VCOM_AND_DATA_INTERVAL_SETTING + self.send_data(0x17) + self.send_command(0x82) # to solve Vcom drop + self.send_data(0x00) + self.send_command(0x01) # power setting + self.send_data(0x02) # gate switch to external + self.send_data(0x00) + self.send_data(0x00) + self.send_data(0x00) + self.ReadBusy() + + self.send_command(0x02) # power off + + epdconfig.delay_ms(2000) + epdconfig.module_exit() + +### END OF FILE ### + diff --git a/waveshare_epd/epd1in54b_V2.py b/waveshare_epd/epd1in54b_V2.py new file mode 100644 index 0000000..1a9a52b --- /dev/null +++ b/waveshare_epd/epd1in54b_V2.py @@ -0,0 +1,177 @@ +# ***************************************************************************** +# * | File : epd1in54b.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 = 200 +EPD_HEIGHT = 200 + +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 + + + # Hardware reset + def reset(self): + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(200) + epdconfig.digital_write(self.reset_pin, 0) # module reset + 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): + logger.debug("e-Paper busy") + while(epdconfig.digital_read(self.busy_pin) == 1): + epdconfig.delay_ms(100) + logger.debug("e-Paper busy release") + + 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(0xC7) + self.send_data(0x00) + self.send_data(0x01) + + 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(0x18) #0x18-->(24+1)*8=200 + + self.send_command(0x45) #set Ram-Y address start/end position + self.send_data(0xC7) #0xC7-->(199+1)=200 + self.send_data(0x00) + self.send_data(0x00) + self.send_data(0x00) + + self.send_command(0x3C) #BorderWavefrom + self.send_data(0x05) + + self.send_command(0x18) #Read built-in temperature sensor + self.send_data(0x80) + + 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 0X199 + self.send_data(0xC7) + self.send_data(0x00) + self.ReadBusy() + return 0 + + def getbuffer(self, image): + buf = [0xFF] * int(self.width * self.height / 8) + # Set buffer to value of Python Imaging Library image. + # Image must be in mode 1. + image_monocolor = image.convert('1') + imwidth, imheight = image_monocolor.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)) + + pixels = image_monocolor.load() + for y in range(self.height): + for x in range(self.width): + # Set the bits for the column of pixels at the current position. + if pixels[x, y] == 0: + buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) + return buf + + def display(self, blackimage, redimage): + # send black data + if (blackimage != None): + self.send_command(0x24) # DATA_START_TRANSMISSION_1 + for i in range(0, int(self.width * self.height / 8)): + self.send_data(blackimage[i]) + + # send red data + if (redimage != None): + self.send_command(0x26) # DATA_START_TRANSMISSION_2 + for i in range(0, int(self.width * self.height / 8)): + self.send_data(~redimage[i]) + + self.send_command(0x22) # DISPLAY_REFRESH + self.send_data(0xF7) + self.send_command(0x20) # DISPLAY_REFRESH + self.ReadBusy() + + def Clear(self): + self.send_command(0x24) # DATA_START_TRANSMISSION_1 + for i in range(0, int(self.width * self.height / 8)): + self.send_data(0xFF) + + self.send_command(0x26) # DATA_START_TRANSMISSION_2 + for i in range(0, int(self.width * self.height / 8)): + self.send_data(0x00) + + self.send_command(0x22) # DISPLAY_REFRESH + self.send_data(0xF7) + self.send_command(0x20) # DISPLAY_REFRESH + self.ReadBusy() + + + def sleep(self): + self.send_command(0x10) #enter deep sleep + self.send_data(0x01) + + epdconfig.delay_ms(2000) + epdconfig.module_exit() + +### END OF FILE ### + diff --git a/waveshare_epd/epd1in54c.py b/waveshare_epd/epd1in54c.py new file mode 100644 index 0000000..9b2bbb6 --- /dev/null +++ b/waveshare_epd/epd1in54c.py @@ -0,0 +1,156 @@ +# ***************************************************************************** +# * | File : epd1in54c.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 = 152 +EPD_HEIGHT = 152 + +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 + + # Hardware reset + def reset(self): + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(10) + epdconfig.digital_write(self.reset_pin, 0) + epdconfig.delay_ms(1) + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(10) + + 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): + logger.debug("e-Paper busy") + while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy + epdconfig.delay_ms(200) + logger.debug("e-Paper busy release") + + def init(self): + if (epdconfig.module_init() != 0): + return -1 + # EPD hardware init start + self.reset() + + self.send_command(0x06) # boost soft start + self.send_data(0x17) + self.send_data(0x17) + self.send_data(0x17) + self.send_command(0x04) # power on + + self.ReadBusy() + + self.send_command(0x00) # panel setting + self.send_data(0x0f) # LUT from OTP,160x296 + self.send_data(0x0d) # VCOM to 0V fast + + self.send_command(0x61) # resolution setting + self.send_data(0x98) + self.send_data(0x00) + self.send_data(0x98) + + self.send_command(0x50) + self.send_data(0x77) + + def getbuffer(self, image): + buf = [0xFF] * (int(self.width/8) * 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("Horizontal") + for y in range(imheight): + for x in range(imwidth): + # Set the bits for the column of pixels at the current position. + if pixels[x, y] == 0: + buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) + elif(imwidth == self.height and imheight == self.width): + logger.debug("Vertical") + for y in range(imheight): + for x in range(imwidth): + newx = y + newy = self.height - x - 1 + if pixels[x, y] == 0: + buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) + return buf + + def display(self, blackimage, yellowimage): + self.send_command(0x10) + logger.debug("blackimage") + for i in range(0, int(self.width * self.height / 8)): + self.send_data(blackimage[i]) + self.send_command(0x13) + logger.debug("yellowimage") + for i in range(0, int(self.width * self.height / 8)): + self.send_data(yellowimage[i]) + + self.send_command(0x12) + self.ReadBusy() + + def Clear(self): + self.send_command(0x10) + for i in range(0, int(self.width * self.height / 8)): + self.send_data(0xFF) + self.send_command(0x13) + for i in range(0, int(self.width * self.height / 8)): + self.send_data(0xFF) + + self.send_command(0x12) + self.ReadBusy() + + # after this, call epd.init() to awaken the module + def sleep(self): + self.send_command(0X02) # power off + self.ReadBusy() + self.send_command(0X07) # deep sleep + self.send_data(0xA5) + + epdconfig.delay_ms(2000) + epdconfig.module_exit() +### END OF FILE ### + diff --git a/waveshare_epd/epd2in13.py b/waveshare_epd/epd2in13.py new file mode 100644 index 0000000..59afdc8 --- /dev/null +++ b/waveshare_epd/epd2in13.py @@ -0,0 +1,228 @@ +# ***************************************************************************** +# * | 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 +import numpy as np + +# 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 ### + diff --git a/waveshare_epd/epd2in13_V2.py b/waveshare_epd/epd2in13_V2.py new file mode 100644 index 0000000..6670428 --- /dev/null +++ b/waveshare_epd/epd2in13_V2.py @@ -0,0 +1,323 @@ +# ***************************************************************************** +# * | 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 +import numpy as np + +# 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 ### + diff --git a/waveshare_epd/epd2in13_V3.py b/waveshare_epd/epd2in13_V3.py new file mode 100644 index 0000000..3812190 --- /dev/null +++ b/waveshare_epd/epd2in13_V3.py @@ -0,0 +1,397 @@ +# ***************************************************************************** +# * | 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 +import numpy as np + +# 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 ### + diff --git a/waveshare_epd/epd2in13b_V3.py b/waveshare_epd/epd2in13b_V3.py new file mode 100644 index 0000000..fa8e3e1 --- /dev/null +++ b/waveshare_epd/epd2in13b_V3.py @@ -0,0 +1,161 @@ +# ***************************************************************************** +# * | File : epd2in13bc.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 = 104 +EPD_HEIGHT = 212 + +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 + + # 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(2) + 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): + logger.debug("e-Paper busy") + self.send_command(0x71); + while(epdconfig.digital_read(self.busy_pin) == 0): + self.send_command(0x71); + epdconfig.delay_ms(100) + logger.debug("e-Paper busy release") + + def init(self): + if (epdconfig.module_init() != 0): + return -1 + + self.reset() + self.send_command(0x04); + self.ReadBusy();#waiting for the electronic paper IC to release the idle signal + + self.send_command(0x00); #panel setting + self.send_data(0x0f); #LUT from OTP,128x296 + self.send_data(0x89); #Temperature sensor, boost and other related timing settings + + self.send_command(0x61); #resolution setting + self.send_data (0x68); + self.send_data (0x00); + self.send_data (0xD4); + + self.send_command(0X50); #VCOM AND DATA INTERVAL SETTING + self.send_data(0x77); #WBmode:VBDF 17|D7 VBDW 97 VBDB 57 + # WBRmode:VBDF F7 VBDW 77 VBDB 37 VBDR B7 + + return 0 + + def getbuffer(self, image): + # logger.debug("bufsiz = ",int(self.width/8) * self.height) + buf = [0xFF] * (int(self.width/8) * self.height) + image_monocolor = image.convert('1') + imwidth, imheight = image_monocolor.size + pixels = image_monocolor.load() + # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) + if(imwidth == self.width and imheight == self.height): + logger.debug("Vertical") + for y in range(imheight): + for x in range(imwidth): + # Set the bits for the column of pixels at the current position. + if pixels[x, y] == 0: + buf[int((x + y * self.width) / 8)] &= ~(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: + buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) + return buf + + def display(self, imageblack, imagered): + self.send_command(0x10) + for i in range(0, int(self.width * self.height / 8)): + self.send_data(imageblack[i]) + + self.send_command(0x13) + for i in range(0, int(self.width * self.height / 8)): + self.send_data(imagered[i]) + + self.send_command(0x12) # REFRESH + epdconfig.delay_ms(100) + self.ReadBusy() + + def Clear(self): + self.send_command(0x10) + for i in range(0, int(self.width * self.height / 8)): + self.send_data(0xFF) + + self.send_command(0x13) + for i in range(0, int(self.width * self.height / 8)): + self.send_data(0xFF) + + self.send_command(0x12) # REFRESH + epdconfig.delay_ms(100) + self.ReadBusy() + + def sleep(self): + self.send_command(0X50) + self.send_data(0xf7) + self.send_command(0X02) + self.ReadBusy() + self.send_command(0x07) # DEEP_SLEEP + self.send_data(0xA5) # check code + + epdconfig.delay_ms(2000) + epdconfig.module_exit() +### END OF FILE ### + diff --git a/waveshare_epd/epd2in13bc.py b/waveshare_epd/epd2in13bc.py new file mode 100644 index 0000000..601ebc6 --- /dev/null +++ b/waveshare_epd/epd2in13bc.py @@ -0,0 +1,162 @@ +# ***************************************************************************** +# * | File : epd2in13bc.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 = 104 +EPD_HEIGHT = 212 + +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 + + # 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): + logger.debug("e-Paper busy") + while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy + epdconfig.delay_ms(100) + logger.debug("e-Paper busy release") + + def init(self): + if (epdconfig.module_init() != 0): + return -1 + + self.reset() + + self.send_command(0x06) # BOOSTER_SOFT_START + self.send_data(0x17) + self.send_data(0x17) + self.send_data(0x17) + + self.send_command(0x04) # POWER_ON + self.ReadBusy() + + self.send_command(0x00) # PANEL_SETTING + self.send_data(0x8F) + + self.send_command(0x50) # VCOM_AND_DATA_INTERVAL_SETTING + self.send_data(0xF0) + + self.send_command(0x61) # RESOLUTION_SETTING + self.send_data(self.width & 0xff) + self.send_data(self.height >> 8) + self.send_data(self.height & 0xff) + return 0 + + def getbuffer(self, image): + # logger.debug("bufsiz = ",int(self.width/8) * self.height) + buf = [0xFF] * (int(self.width/8) * self.height) + image_monocolor = image.convert('1') + imwidth, imheight = image_monocolor.size + pixels = image_monocolor.load() + # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) + if(imwidth == self.width and imheight == self.height): + logger.debug("Vertical") + for y in range(imheight): + for x in range(imwidth): + # Set the bits for the column of pixels at the current position. + if pixels[x, y] == 0: + buf[int((x + y * self.width) / 8)] &= ~(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: + buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) + return buf + + def display(self, imageblack, imagered): + self.send_command(0x10) + for i in range(0, int(self.width * self.height / 8)): + self.send_data(imageblack[i]) + # self.send_command(0x92) + + self.send_command(0x13) + for i in range(0, int(self.width * self.height / 8)): + self.send_data(imagered[i]) + # self.send_command(0x92) + + self.send_command(0x12) # REFRESH + self.ReadBusy() + + def Clear(self): + self.send_command(0x10) + for i in range(0, int(self.width * self.height / 8)): + self.send_data(0xFF) + self.send_command(0x92) + + self.send_command(0x13) + for i in range(0, int(self.width * self.height / 8)): + self.send_data(0xFF) + self.send_command(0x92) + + self.send_command(0x12) # REFRESH + self.ReadBusy() + + def sleep(self): + self.send_command(0x02) # POWER_OFF + self.ReadBusy() + self.send_command(0x07) # DEEP_SLEEP + self.send_data(0xA5) # check code + + epdconfig.delay_ms(2000) + epdconfig.module_exit() +### END OF FILE ### + diff --git a/waveshare_epd/epd2in13d.py b/waveshare_epd/epd2in13d.py new file mode 100644 index 0000000..2430261 --- /dev/null +++ b/waveshare_epd/epd2in13d.py @@ -0,0 +1,361 @@ +# ***************************************************************************** +# * | File : epd2in13d.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 +from PIL import Image +import RPi.GPIO as GPIO + +# Display resolution +EPD_WIDTH = 104 +EPD_HEIGHT = 212 + +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_vcomDC = [ + 0x00, 0x08, 0x00, 0x00, 0x00, 0x02, + 0x60, 0x28, 0x28, 0x00, 0x00, 0x01, + 0x00, 0x14, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x12, 0x12, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, + ] + + lut_ww = [ + 0x40, 0x08, 0x00, 0x00, 0x00, 0x02, + 0x90, 0x28, 0x28, 0x00, 0x00, 0x01, + 0x40, 0x14, 0x00, 0x00, 0x00, 0x01, + 0xA0, 0x12, 0x12, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ] + + lut_bw = [ + 0x40, 0x17, 0x00, 0x00, 0x00, 0x02, + 0x90, 0x0F, 0x0F, 0x00, 0x00, 0x03, + 0x40, 0x0A, 0x01, 0x00, 0x00, 0x01, + 0xA0, 0x0E, 0x0E, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ] + + lut_wb = [ + 0x80, 0x08, 0x00, 0x00, 0x00, 0x02, + 0x90, 0x28, 0x28, 0x00, 0x00, 0x01, + 0x80, 0x14, 0x00, 0x00, 0x00, 0x01, + 0x50, 0x12, 0x12, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ] + + lut_bb = [ + 0x80, 0x08, 0x00, 0x00, 0x00, 0x02, + 0x90, 0x28, 0x28, 0x00, 0x00, 0x01, + 0x80, 0x14, 0x00, 0x00, 0x00, 0x01, + 0x50, 0x12, 0x12, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ] + + lut_vcom1 = [ + 0x00, 0x19, 0x01, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, + ] + + lut_ww1 = [ + 0x00, 0x19, 0x01, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ] + + lut_bw1 = [ + 0x80, 0x19, 0x01, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ] + + lut_wb1 = [ + 0x40, 0x19, 0x01, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ] + + lut_bb1 = [ + 0x00, 0x19, 0x01, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 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): + logger.debug("e-Paper busy") + while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy + self.send_command(0x71) + epdconfig.delay_ms(100) + logger.debug("e-Paper busy release") + + def TurnOnDisplay(self): + self.send_command(0x12) + epdconfig.delay_ms(100) + self.ReadBusy() + + def init(self): + if (epdconfig.module_init() != 0): + return -1 + # EPD hardware init start + self.reset() + + self.send_command(0x01) # POWER SETTING + self.send_data(0x03) + self.send_data(0x00) + self.send_data(0x2b) + self.send_data(0x2b) + self.send_data(0x03) + + self.send_command(0x06) # boost soft start + self.send_data(0x17) # A + self.send_data(0x17) # B + self.send_data(0x17) # C + + self.send_command(0x04) + self.ReadBusy() + + self.send_command(0x00) # panel setting + self.send_data(0xbf) # LUT from OTP,128x296 + self.send_data(0x0d) # VCOM to 0V fast + + self.send_command(0x30) # PLL setting + self.send_data(0x3a) # 3a 100HZ 29 150Hz 39 200HZ 31 171HZ + + self.send_command(0x61) # resolution setting + self.send_data(self.width) + self.send_data((self.height >> 8) & 0xff) + self.send_data(self.height& 0xff) + + self.send_command(0x82) # vcom_DC setting + self.send_data(0x28) + return 0 + + def SetFullReg(self): + self.send_command(0x82) + self.send_data(0x00) + self.send_command(0X50) + self.send_data(0x97) + + self.send_command(0x20) # vcom + for count in range(0, 44): + self.send_data(self.lut_vcomDC[count]) + self.send_command(0x21) # ww -- + for count in range(0, 42): + self.send_data(self.lut_ww[count]) + self.send_command(0x22) # bw r + for count in range(0, 42): + self.send_data(self.lut_bw[count]) + self.send_command(0x23) # wb w + for count in range(0, 42): + self.send_data(self.lut_wb[count]) + self.send_command(0x24) # bb b + for count in range(0, 42): + self.send_data(self.lut_bb[count]) + + def SetPartReg(self): + self.send_command(0x82) + self.send_data(0x03) + self.send_command(0X50) + self.send_data(0x47) + + self.send_command(0x20) # vcom + for count in range(0, 44): + self.send_data(self.lut_vcom1[count]) + self.send_command(0x21) # ww -- + for count in range(0, 42): + self.send_data(self.lut_ww1[count]) + self.send_command(0x22) # bw r + for count in range(0, 42): + self.send_data(self.lut_bw1[count]) + self.send_command(0x23) # wb w + for count in range(0, 42): + self.send_data(self.lut_wb1[count]) + self.send_command(0x24) # bb b + for count in range(0, 42): + self.send_data(self.lut_bb1[count]) + + def getbuffer(self, image): + # logger.debug("bufsiz = ",int(self.width/8) * self.height) + buf = [0xFF] * (int(self.width/8) * self.height) + image_monocolor = image.convert('1') + imwidth, imheight = image_monocolor.size + pixels = image_monocolor.load() + # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) + if(imwidth == self.width and imheight == self.height): + logger.debug("Vertical") + for y in range(imheight): + for x in range(imwidth): + # Set the bits for the column of pixels at the current position. + if pixels[x, y] == 0: + buf[int((x + y * self.width) / 8)] &= ~(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: + buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) + return buf + + def display(self, image): + if (Image == None): + return + + self.send_command(0x10) + for i in range(0, int(self.width * self.height / 8)): + self.send_data(0x00) + epdconfig.delay_ms(10) + + self.send_command(0x13) + for i in range(0, int(self.width * self.height / 8)): + self.send_data(image[i]) + epdconfig.delay_ms(10) + + self.SetFullReg() + self.TurnOnDisplay() + + def DisplayPartial(self, image): + if (Image == None): + return + + self.send_command(0x91) + self.send_command(0x90) + self.send_data(0) + self.send_data(self.width - 1) + + self.send_data(0) + self.send_data(0) + self.send_data(int(self.height / 256)) + self.send_data(self.height % 256 - 1) + self.send_data(0x28) + + self.send_command(0x10) + for i in range(0, int(self.width * self.height / 8)): + self.send_data(image[i]) + epdconfig.delay_ms(10) + + self.send_command(0x13) + for i in range(0, int(self.width * self.height / 8)): + self.send_data(~image[i]) + epdconfig.delay_ms(10) + + self.SetPartReg() + self.TurnOnDisplay() + + def Clear(self, color): + self.send_command(0x10) + for i in range(0, int(self.width * self.height / 8)): + self.send_data(0x00) + epdconfig.delay_ms(10) + + self.send_command(0x13) + for i in range(0, int(self.width * self.height / 8)): + self.send_data(0xFF) + epdconfig.delay_ms(10) + + self.SetFullReg() + self.TurnOnDisplay() + + def sleep(self): + self.send_command(0X50) + self.send_data(0xf7) + self.send_command(0X02) # power off + self.send_command(0X07) # deep sleep + self.send_data(0xA5) + + epdconfig.delay_ms(2000) + epdconfig.module_exit() + +### END OF FILE ### + diff --git a/waveshare_epd/epd2in66.py b/waveshare_epd/epd2in66.py new file mode 100644 index 0000000..d8b4384 --- /dev/null +++ b/waveshare_epd/epd2in66.py @@ -0,0 +1,234 @@ +# ***************************************************************************** +# * | File : epd2in66.py +# * | Author : Waveshare team +# * | Function : Electronic paper driver +# * | Info : +# *---------------- +# * | This version: V1.0 +# * | Date : 2020-07-22 +# # | 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 = 152 +EPD_HEIGHT = 296 + +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 + + WF_PARTIAL = [ + 0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x40,0x40,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x0A,0x00,0x00,0x00,0x00,0x00,0x02,0x01,0x00,0x00, + 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x22,0x22,0x22,0x22,0x22,0x22, + 0x00,0x00,0x00,0x22,0x17,0x41,0xB0,0x32,0x36, + ] + + + # 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): + logger.debug("e-Paper busy") + while(epdconfig.digital_read(self.busy_pin) == 1): # 0: idle, 1: busy + epdconfig.delay_ms(200) + logger.debug("e-Paper busy release") + + + def init(self, mode): + if (epdconfig.module_init() != 0): + return -1 + # EPD hardware init start + self.reset() + + self.send_command(0x12) + epdconfig.delay_ms(300) + self.ReadBusy() + + self.send_command(0x11) # setting gaet number + self.send_data(0x03) + self.send_command(0x44) # set gate voltage + self.send_data(0x01) + self.send_data(0x13) + self.send_command(0x45) # set source voltage + self.send_data(0x0) + self.send_data(0x0) + self.send_data(0x28) + self.send_data(0x01) + + if(mode == 0): #full + self.send_command(0x3C) + self.send_data(0x01) + + elif(mode == 1): #partial + self.load_lut(self.WF_PARTIAL) + self.send_command(0x37) # set display option, these setting turn on previous function + 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) + self.send_data(0x80) + + self.send_command(0x22) + self.send_data(0xcf) + + self.send_command(0x20) + self.ReadBusy() + + else: + logger.debug("There is no such mode") + + return 0 + + + def load_lut(self, lut): + self.send_command(0x32) + for i in range(0, 153): + self.send_data(lut[i]) + + + def turnon_display(self): + self.send_command(0x20) + self.ReadBusy() + + def getbuffer(self, image): + # logger.debug("bufsiz = ",int(self.width/8) * self.height) + buf = [0xFF] * (int(self.width/8) * self.height) + image_monocolor = image.convert('1') + imwidth, imheight = image_monocolor.size + pixels = image_monocolor.load() + # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) + if(imwidth == self.width and imheight == self.height): + logger.debug("Vertical") + for y in range(imheight): + for x in range(imwidth): + # Set the bits for the column of pixels at the current position. + if pixels[x, y] == 0: + buf[int((x + y * self.width) / 8)] &= ~(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: + buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) + return buf + + + def display(self, image): + if (image == None): + return + + self.send_command(0x4E) + self.send_data(0x01) + self.send_command(0x4F) + self.send_data(0x27) + self.send_data(0x01) + + self.send_command(0x24) + for j in range(0, self.height): + for i in range(0, int(self.width / 8)): + self.send_data(image[i + j * int(self.width / 8)]) + + self.turnon_display() + + + def Clear(self): + self.send_command(0x4E) + self.send_data(0x01) + self.send_command(0x4F) + self.send_data(0x27) + self.send_data(0x01) + + self.send_command(0x24) + for j in range(0, self.height): + for i in range(0, int(self.width / 8)): + self.send_data(0xff) + + self.send_command(0x26) + for j in range(0, self.height): + for i in range(0, int(self.width / 8)): + self.send_data(0xff) + + self.turnon_display() + + + def sleep(self): + self.send_command(0X10) # DEEP_SLEEP_MODE + self.send_data(0x01) + + epdconfig.delay_ms(2000) + epdconfig.module_exit() + +### END OF FILE ### + diff --git a/waveshare_epd/epd2in66b.py b/waveshare_epd/epd2in66b.py new file mode 100644 index 0000000..a52e6f8 --- /dev/null +++ b/waveshare_epd/epd2in66b.py @@ -0,0 +1,188 @@ +# ***************************************************************************** +# * | File : epd2in66b.py +# * | Author : Waveshare team +# * | Function : Electronic paper driver +# * | Info : +# *---------------- +# * | This version: V1.0 +# * | Date : 2020-12-01 +# # | 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 = 152 +EPD_HEIGHT = 296 + +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 + + # 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): + logger.debug("e-Paper busy") + while(epdconfig.digital_read(self.busy_pin) == 1): # 0: idle, 1: busy + epdconfig.delay_ms(20) + logger.debug("e-Paper busy release") + + + def init(self): + if (epdconfig.module_init() != 0): + return -1 + # EPD hardware init start + self.reset() + + self.send_command(0x12) + epdconfig.delay_ms(30) + self.ReadBusy() + + self.send_command(0x11) # setting gaet number + self.send_data(0x03) + + self.setWindows(0, 0, self.width-1, self.height-1) + + self.send_command(0x21) + self.send_data(0x00) + self.send_data(0x80) + + self.setCursor(0, 0) + self.ReadBusy() + + return 0 + + def setWindows(self, Xstart, Ystart, Xend, Yend): + self.send_command(0x44) # SET_RAM_X_ADDRESS_START_END_POSITION + self.send_data((Xstart>>3) & 0x1F) + self.send_data((Xend>>3) & 0x1F) + + self.send_command(0x45) # SET_RAM_Y_ADDRESS_START_END_POSITION + self.send_data(Ystart & 0xFF) + self.send_data((Ystart >> 8) & 0x01) + self.send_data(Yend & 0xFF) + self.send_data((Yend >> 8) & 0x01) + + def setCursor(self, Xstart, Ystart): + self.send_command(0x4E) # SET_RAM_X_ADDRESS_COUNTER + self.send_data(Xstart & 0x1F) + + self.send_command(0x4F) # SET_RAM_Y_ADDRESS_COUNTER + self.send_data(Ystart & 0xFF) + self.send_data((Ystart >> 8) & 0x01) + + def turnon_display(self): + self.send_command(0x20) + self.ReadBusy() + + def getbuffer(self, image): + # logger.debug("bufsiz = ",int(self.width/8) * self.height) + buf = [0xFF] * (int(self.width/8) * self.height) + image_monocolor = image.convert('1') + imwidth, imheight = image_monocolor.size + pixels = image_monocolor.load() + # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) + if(imwidth == self.width and imheight == self.height): + logger.debug("Vertical") + for y in range(imheight): + for x in range(imwidth): + # Set the bits for the column of pixels at the current position. + if pixels[x, y] == 0: + buf[int((x + y * self.width) / 8)] &= ~(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: + buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) + return buf + + def display(self, Blackimage, Redimage): + if (Blackimage == None or Redimage == None): + return + self.send_command(0x24) + for j in range(0, self.height): + for i in range(0, int(self.width / 8)): + self.send_data(Blackimage[i + j * int(self.width / 8)]) + + self.send_command(0x26) + for j in range(0, self.height): + for i in range(0, int(self.width / 8)): + self.send_data(~Redimage[i + j * int(self.width / 8)]) + + self.turnon_display() + + + def Clear(self): + self.send_command(0x24) + for j in range(0, self.height): + for i in range(0, int(self.width / 8)): + self.send_data(0xff) + + self.send_command(0x26) + for j in range(0, self.height): + for i in range(0, int(self.width / 8)): + self.send_data(0x00) + + self.turnon_display() + + + def sleep(self): + self.send_command(0X10) # DEEP_SLEEP_MODE + self.send_data(0x01) + + epdconfig.delay_ms(2000) + epdconfig.module_exit() + +### END OF FILE ### + diff --git a/waveshare_epd/epd2in7.py b/waveshare_epd/epd2in7.py new file mode 100644 index 0000000..831492b --- /dev/null +++ b/waveshare_epd/epd2in7.py @@ -0,0 +1,527 @@ +# ***************************************************************************** +# * | File : epd2in7.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 = 176 +EPD_HEIGHT = 264 + +GRAY1 = 0xff #white +GRAY2 = 0xC0 +GRAY3 = 0x80 #gray +GRAY4 = 0x00 #Blackest + +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 + self.GRAY1 = GRAY1 #white + self.GRAY2 = GRAY2 + self.GRAY3 = GRAY3 #gray + self.GRAY4 = GRAY4 #Blackest + + lut_vcom_dc = [0x00, 0x00, + 0x00, 0x08, 0x00, 0x00, 0x00, 0x02, + 0x60, 0x28, 0x28, 0x00, 0x00, 0x01, + 0x00, 0x14, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x12, 0x12, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + ] + lut_ww = [ + 0x40, 0x08, 0x00, 0x00, 0x00, 0x02, + 0x90, 0x28, 0x28, 0x00, 0x00, 0x01, + 0x40, 0x14, 0x00, 0x00, 0x00, 0x01, + 0xA0, 0x12, 0x12, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ] + lut_bw = [ + 0x40, 0x08, 0x00, 0x00, 0x00, 0x02, + 0x90, 0x28, 0x28, 0x00, 0x00, 0x01, + 0x40, 0x14, 0x00, 0x00, 0x00, 0x01, + 0xA0, 0x12, 0x12, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ] + lut_bb = [ + 0x80, 0x08, 0x00, 0x00, 0x00, 0x02, + 0x90, 0x28, 0x28, 0x00, 0x00, 0x01, + 0x80, 0x14, 0x00, 0x00, 0x00, 0x01, + 0x50, 0x12, 0x12, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ] + lut_wb = [ + 0x80, 0x08, 0x00, 0x00, 0x00, 0x02, + 0x90, 0x28, 0x28, 0x00, 0x00, 0x01, + 0x80, 0x14, 0x00, 0x00, 0x00, 0x01, + 0x50, 0x12, 0x12, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ] + ###################full screen update LUT###################### + #0~3 gray + gray_lut_vcom = [ + 0x00, 0x00, + 0x00, 0x0A, 0x00, 0x00, 0x00, 0x01, + 0x60, 0x14, 0x14, 0x00, 0x00, 0x01, + 0x00, 0x14, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x13, 0x0A, 0x01, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ] + #R21 + gray_lut_ww =[ + 0x40, 0x0A, 0x00, 0x00, 0x00, 0x01, + 0x90, 0x14, 0x14, 0x00, 0x00, 0x01, + 0x10, 0x14, 0x0A, 0x00, 0x00, 0x01, + 0xA0, 0x13, 0x01, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ] + #R22H r + gray_lut_bw =[ + 0x40, 0x0A, 0x00, 0x00, 0x00, 0x01, + 0x90, 0x14, 0x14, 0x00, 0x00, 0x01, + 0x00, 0x14, 0x0A, 0x00, 0x00, 0x01, + 0x99, 0x0C, 0x01, 0x03, 0x04, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ] + #R23H w + gray_lut_wb =[ + 0x40, 0x0A, 0x00, 0x00, 0x00, 0x01, + 0x90, 0x14, 0x14, 0x00, 0x00, 0x01, + 0x00, 0x14, 0x0A, 0x00, 0x00, 0x01, + 0x99, 0x0B, 0x04, 0x04, 0x01, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ] + #R24H b + gray_lut_bb =[ + 0x80, 0x0A, 0x00, 0x00, 0x00, 0x01, + 0x90, 0x14, 0x14, 0x00, 0x00, 0x01, + 0x20, 0x14, 0x0A, 0x00, 0x00, 0x01, + 0x50, 0x13, 0x01, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 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): + logger.debug("e-Paper busy") + while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy + epdconfig.delay_ms(200) + logger.debug("e-Paper busy release") + + def set_lut(self): + self.send_command(0x20) # vcom + for count in range(0, 44): + self.send_data(self.lut_vcom_dc[count]) + self.send_command(0x21) # ww -- + for count in range(0, 42): + self.send_data(self.lut_ww[count]) + self.send_command(0x22) # bw r + for count in range(0, 42): + self.send_data(self.lut_bw[count]) + self.send_command(0x23) # wb w + for count in range(0, 42): + self.send_data(self.lut_bb[count]) + self.send_command(0x24) # bb b + for count in range(0, 42): + self.send_data(self.lut_wb[count]) + + def gray_SetLut(self): + self.send_command(0x20) + for count in range(0, 44): #vcom + self.send_data(self.gray_lut_vcom[count]) + + self.send_command(0x21) #red not use + for count in range(0, 42): + self.send_data(self.gray_lut_ww[count]) + + self.send_command(0x22) #bw r + for count in range(0, 42): + self.send_data(self.gray_lut_bw[count]) + + self.send_command(0x23) #wb w + for count in range(0, 42): + self.send_data(self.gray_lut_wb[count]) + + self.send_command(0x24) #bb b + for count in range(0, 42): + self.send_data(self.gray_lut_bb[count]) + + self.send_command(0x25) #vcom + for count in range(0, 42): + self.send_data(self.gray_lut_ww[count]) + + def init(self): + if (epdconfig.module_init() != 0): + return -1 + + # EPD hardware init start + self.reset() + + self.send_command(0x01) # POWER_SETTING + self.send_data(0x03) # VDS_EN, VDG_EN + self.send_data(0x00) # VCOM_HV, VGHL_LV[1], VGHL_LV[0] + self.send_data(0x2b) # VDH + self.send_data(0x2b) # VDL + self.send_data(0x09) # VDHR + + self.send_command(0x06) # BOOSTER_SOFT_START + self.send_data(0x07) + self.send_data(0x07) + self.send_data(0x17) + + # Power optimization + self.send_command(0xF8) + self.send_data(0x60) + self.send_data(0xA5) + + # Power optimization + self.send_command(0xF8) + self.send_data(0x89) + self.send_data(0xA5) + + # Power optimization + self.send_command(0xF8) + self.send_data(0x90) + self.send_data(0x00) + + # Power optimization + self.send_command(0xF8) + self.send_data(0x93) + self.send_data(0x2A) + + # Power optimization + self.send_command(0xF8) + self.send_data(0xA0) + self.send_data(0xA5) + + # Power optimization + self.send_command(0xF8) + self.send_data(0xA1) + self.send_data(0x00) + + # Power optimization + self.send_command(0xF8) + self.send_data(0x73) + self.send_data(0x41) + + self.send_command(0x16) # PARTIAL_DISPLAY_REFRESH + self.send_data(0x00) + self.send_command(0x04) # POWER_ON + self.ReadBusy() + + self.send_command(0x00) # PANEL_SETTING + self.send_data(0xAF) # KW-BF KWR-AF BWROTP 0f + + self.send_command(0x30) # PLL_CONTROL + self.send_data(0x3A) # 3A 100HZ 29 150Hz 39 200HZ 31 171HZ + + self.send_command(0X50) #VCOM AND DATA INTERVAL SETTING + self.send_data(0x57) + + self.send_command(0x82) # VCM_DC_SETTING_REGISTER + self.send_data(0x12) + self.set_lut() + return 0 + + def Init_4Gray(self): + if (epdconfig.module_init() != 0): + return -1 + self.reset() + + self.send_command(0x01) #POWER SETTING + self.send_data (0x03) + self.send_data (0x00) + self.send_data (0x2b) + self.send_data (0x2b) + + + self.send_command(0x06) #booster soft start + self.send_data (0x07) #A + self.send_data (0x07) #B + self.send_data (0x17) #C + + self.send_command(0xF8) #boost?? + self.send_data (0x60) + self.send_data (0xA5) + + self.send_command(0xF8) #boost?? + self.send_data (0x89) + self.send_data (0xA5) + + self.send_command(0xF8) #boost?? + self.send_data (0x90) + self.send_data (0x00) + + self.send_command(0xF8) #boost?? + self.send_data (0x93) + self.send_data (0x2A) + + self.send_command(0xF8) #boost?? + self.send_data (0xa0) + self.send_data (0xa5) + + self.send_command(0xF8) #boost?? + self.send_data (0xa1) + self.send_data (0x00) + + self.send_command(0xF8) #boost?? + self.send_data (0x73) + self.send_data (0x41) + + self.send_command(0x16) + self.send_data(0x00) + + self.send_command(0x04) + self.ReadBusy() + + self.send_command(0x00) #panel setting + self.send_data(0xbf) #KW-BF KWR-AF BWROTP 0f + + self.send_command(0x30) #PLL setting + self.send_data (0x90) #100hz + + self.send_command(0x61) #resolution setting + self.send_data (0x00) #176 + self.send_data (0xb0) + self.send_data (0x01) #264 + self.send_data (0x08) + + self.send_command(0x82) #vcom_DC setting + self.send_data (0x12) + + self.send_command(0X50) #VCOM AND DATA INTERVAL SETTING + self.send_data(0x57) + + def getbuffer(self, image): + # logger.debug("bufsiz = ",int(self.width/8) * self.height) + buf = [0xFF] * (int(self.width/8) * self.height) + image_monocolor = image.convert('1') + imwidth, imheight = image_monocolor.size + pixels = image_monocolor.load() + # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) + if(imwidth == self.width and imheight == self.height): + logger.debug("Vertical") + for y in range(imheight): + for x in range(imwidth): + # Set the bits for the column of pixels at the current position. + if pixels[x, y] == 0: + buf[int((x + y * self.width) / 8)] &= ~(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: + buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) + return buf + + def getbuffer_4Gray(self, image): + # logger.debug("bufsiz = ",int(self.width/8) * self.height) + buf = [0xFF] * (int(self.width / 4) * self.height) + image_monocolor = image.convert('L') + imwidth, imheight = image_monocolor.size + pixels = image_monocolor.load() + i=0 + # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) + if(imwidth == self.width and imheight == self.height): + logger.debug("Vertical") + for y in range(imheight): + for x in range(imwidth): + # Set the bits for the column of pixels at the current position. + if(pixels[x, y] == 0xC0): + pixels[x, y] = 0x80 + elif (pixels[x, y] == 0x80): + pixels[x, y] = 0x40 + i= i+1 + if(i%4 == 0): + buf[int((x + (y * self.width))/4)] = ((pixels[x-3, y]&0xc0) | (pixels[x-2, y]&0xc0)>>2 | (pixels[x-1, y]&0xc0)>>4 | (pixels[x, y]&0xc0)>>6) + + elif(imwidth == self.height and imheight == self.width): + logger.debug("Horizontal") + for x in range(imwidth): + for y in range(imheight): + newx = y + newy = self.height - x - 1 + if(pixels[x, y] == 0xC0): + pixels[x, y] = 0x80 + elif (pixels[x, y] == 0x80): + pixels[x, y] = 0x40 + i= i+1 + if(i%4 == 0): + buf[int((newx + (newy * self.width))/4)] = ((pixels[x, y-3]&0xc0) | (pixels[x, y-2]&0xc0)>>2 | (pixels[x, y-1]&0xc0)>>4 | (pixels[x, y]&0xc0)>>6) + return buf + + def display(self, image): + self.send_command(0x10) + for i in range(0, int(self.width * self.height / 8)): + self.send_data(0xFF) + self.send_command(0x13) + for i in range(0, int(self.width * self.height / 8)): + self.send_data(image[i]) + self.send_command(0x12) + self.ReadBusy() + + def display_4Gray(self, image): + self.send_command(0x10) + for i in range(0, 5808): #5808*4 46464 + temp3=0 + for j in range(0, 2): + temp1 = image[i*2+j] + for k in range(0, 2): + temp2 = temp1&0xC0 + if(temp2 == 0xC0): + temp3 |= 0x01#white + elif(temp2 == 0x00): + temp3 |= 0x00 #black + elif(temp2 == 0x80): + temp3 |= 0x01 #gray1 + else: #0x40 + temp3 |= 0x00 #gray2 + temp3 <<= 1 + + temp1 <<= 2 + temp2 = temp1&0xC0 + if(temp2 == 0xC0): #white + temp3 |= 0x01 + elif(temp2 == 0x00): #black + temp3 |= 0x00 + elif(temp2 == 0x80): + temp3 |= 0x01 #gray1 + else : #0x40 + temp3 |= 0x00 #gray2 + if(j!=1 or k!=1): + temp3 <<= 1 + temp1 <<= 2 + self.send_data(temp3) + + self.send_command(0x13) + for i in range(0, 5808): #5808*4 46464 + temp3=0 + for j in range(0, 2): + temp1 = image[i*2+j] + for k in range(0, 2): + temp2 = temp1&0xC0 + if(temp2 == 0xC0): + temp3 |= 0x01#white + elif(temp2 == 0x00): + temp3 |= 0x00 #black + elif(temp2 == 0x80): + temp3 |= 0x00 #gray1 + else: #0x40 + temp3 |= 0x01 #gray2 + temp3 <<= 1 + + temp1 <<= 2 + temp2 = temp1&0xC0 + if(temp2 == 0xC0): #white + temp3 |= 0x01 + elif(temp2 == 0x00): #black + temp3 |= 0x00 + elif(temp2 == 0x80): + temp3 |= 0x00 #gray1 + else: #0x40 + temp3 |= 0x01 #gray2 + if(j!=1 or k!=1): + temp3 <<= 1 + temp1 <<= 2 + self.send_data(temp3) + + self.gray_SetLut() + self.send_command(0x12) + epdconfig.delay_ms(200) + self.ReadBusy() + # pass + + def Clear(self, color=0xFF): + self.send_command(0x10) + for i in range(0, int(self.width * self.height / 8)): + self.send_data(color) + self.send_command(0x13) + for i in range(0, int(self.width * self.height / 8)): + self.send_data(color) + self.send_command(0x12) + self.ReadBusy() + + def sleep(self): + self.send_command(0X50) + self.send_data(0xf7) + self.send_command(0X02) + self.send_command(0X07) + self.send_data(0xA5) + + epdconfig.delay_ms(2000) + epdconfig.module_exit() +### END OF FILE ### + diff --git a/waveshare_epd/epd2in7b.py b/waveshare_epd/epd2in7b.py new file mode 100644 index 0000000..314c828 --- /dev/null +++ b/waveshare_epd/epd2in7b.py @@ -0,0 +1,272 @@ +# ***************************************************************************** +# * | File : epd2in7b.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 = 176 +EPD_HEIGHT = 264 + +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_vcom_dc = [ + 0x00, 0x00, + 0x00, 0x1A, 0x1A, 0x00, 0x00, 0x01, + 0x00, 0x0A, 0x0A, 0x00, 0x00, 0x08, + 0x00, 0x0E, 0x01, 0x0E, 0x01, 0x10, + 0x00, 0x0A, 0x0A, 0x00, 0x00, 0x08, + 0x00, 0x04, 0x10, 0x00, 0x00, 0x05, + 0x00, 0x03, 0x0E, 0x00, 0x00, 0x0A, + 0x00, 0x23, 0x00, 0x00, 0x00, 0x01 + ] + + lut_ww = [ + 0x90, 0x1A, 0x1A, 0x00, 0x00, 0x01, + 0x40, 0x0A, 0x0A, 0x00, 0x00, 0x08, + 0x84, 0x0E, 0x01, 0x0E, 0x01, 0x10, + 0x80, 0x0A, 0x0A, 0x00, 0x00, 0x08, + 0x00, 0x04, 0x10, 0x00, 0x00, 0x05, + 0x00, 0x03, 0x0E, 0x00, 0x00, 0x0A, + 0x00, 0x23, 0x00, 0x00, 0x00, 0x01 + ] + + # R22H r + lut_bw = [ + 0xA0, 0x1A, 0x1A, 0x00, 0x00, 0x01, + 0x00, 0x0A, 0x0A, 0x00, 0x00, 0x08, + 0x84, 0x0E, 0x01, 0x0E, 0x01, 0x10, + 0x90, 0x0A, 0x0A, 0x00, 0x00, 0x08, + 0xB0, 0x04, 0x10, 0x00, 0x00, 0x05, + 0xB0, 0x03, 0x0E, 0x00, 0x00, 0x0A, + 0xC0, 0x23, 0x00, 0x00, 0x00, 0x01 + ] + + # R23H w + lut_bb = [ + 0x90, 0x1A, 0x1A, 0x00, 0x00, 0x01, + 0x40, 0x0A, 0x0A, 0x00, 0x00, 0x08, + 0x84, 0x0E, 0x01, 0x0E, 0x01, 0x10, + 0x80, 0x0A, 0x0A, 0x00, 0x00, 0x08, + 0x00, 0x04, 0x10, 0x00, 0x00, 0x05, + 0x00, 0x03, 0x0E, 0x00, 0x00, 0x0A, + 0x00, 0x23, 0x00, 0x00, 0x00, 0x01 + ] + # R24H b + lut_wb = [ + 0x90, 0x1A, 0x1A, 0x00, 0x00, 0x01, + 0x20, 0x0A, 0x0A, 0x00, 0x00, 0x08, + 0x84, 0x0E, 0x01, 0x0E, 0x01, 0x10, + 0x10, 0x0A, 0x0A, 0x00, 0x00, 0x08, + 0x00, 0x04, 0x10, 0x00, 0x00, 0x05, + 0x00, 0x03, 0x0E, 0x00, 0x00, 0x0A, + 0x00, 0x23, 0x00, 0x00, 0x00, 0x01 + ] + + # 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(2) + 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): + logger.debug("e-Paper busy") + while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy + epdconfig.delay_ms(100) + logger.debug("e-Paper busy release") + + def set_lut(self): + self.send_command(0x20) # vcom + for count in range(0, 44): + self.send_data(self.lut_vcom_dc[count]) + self.send_command(0x21) # ww -- + for count in range(0, 42): + self.send_data(self.lut_ww[count]) + self.send_command(0x22) # bw r + for count in range(0, 42): + self.send_data(self.lut_bw[count]) + self.send_command(0x23) # wb w + for count in range(0, 42): + self.send_data(self.lut_bb[count]) + self.send_command(0x24) # bb b + for count in range(0, 42): + self.send_data(self.lut_wb[count]) + + def init(self): + if (epdconfig.module_init() != 0): + return -1 + + self.reset() + + self.send_command(0x04) # POWER_ON + self.ReadBusy() + + self.send_command(0x00) # PANEL_SETTING + self.send_data(0xaf) #KW-BF KWR-AF BWROTP 0f + + self.send_command(0x30) # PLL_CONTROL + self.send_data(0x3a) #3A 100HZ 29 150Hz 39 200HZ 31 171HZ + + self.send_command(0x01) # POWER_SETTING + self.send_data(0x03) # VDS_EN, VDG_EN + self.send_data(0x00) # VCOM_HV, VGHL_LV[1], VGHL_LV[0] + self.send_data(0x2b) # VDH + self.send_data(0x2b) # VDL + self.send_data(0x09) # VDHR + + self.send_command(0x06) # BOOSTER_SOFT_START + self.send_data(0x07) + self.send_data(0x07) + self.send_data(0x17) + + # Power optimization + self.send_command(0xF8) + self.send_data(0x60) + self.send_data(0xA5) + + # Power optimization + self.send_command(0xF8) + self.send_data(0x89) + self.send_data(0xA5) + + # Power optimization + self.send_command(0xF8) + self.send_data(0x90) + self.send_data(0x00) + + # Power optimization + self.send_command(0xF8) + self.send_data(0x93) + self.send_data(0x2A) + + # Power optimization + self.send_command(0xF8) + self.send_data(0x73) + self.send_data(0x41) + + self.send_command(0x82) # VCM_DC_SETTING_REGISTER + self.send_data(0x12) + self.send_command(0x50) # VCOM_AND_DATA_INTERVAL_SETTING + self.send_data(0x87) # define by OTP + + self.set_lut() + + self.send_command(0x16) # PARTIAL_DISPLAY_REFRESH + self.send_data(0x00) + + return 0 + + def getbuffer(self, image): + # logger.debug("bufsiz = ",int(self.width/8) * self.height) + buf = [0xFF] * (int(self.width/8) * self.height) + image_monocolor = image.convert('1') + imwidth, imheight = image_monocolor.size + pixels = image_monocolor.load() + # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) + if(imwidth == self.width and imheight == self.height): + logger.debug("Vertical") + for y in range(imheight): + for x in range(imwidth): + # Set the bits for the column of pixels at the current position. + if pixels[x, y] == 0: + buf[int((x + y * self.width) / 8)] &= ~(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: + buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) + return buf + + def display(self, imageblack, imagered): + self.send_command(0x10) + for i in range(0, int(self.width * self.height / 8)): + self.send_data(~imageblack[i]) + self.send_command(0x11) + + self.send_command(0x13) + for i in range(0, int(self.width * self.height / 8)): + self.send_data(~imagered[i]) + self.send_command(0x11) + + self.send_command(0x12) + self.ReadBusy() + + def Clear(self, color=0x00): + self.send_command(0x10) + for i in range(0, int(self.width * self.height / 8)): + self.send_data(color) + self.send_command(0x11) + + self.send_command(0x13) + for i in range(0, int(self.width * self.height / 8)): + self.send_data(color) + self.send_command(0x11) + + self.send_command(0x12) + self.ReadBusy() + + def sleep(self): + self.send_command(0X50) + self.send_data(0xf7) + self.send_command(0X02) + self.send_command(0X07) + self.send_data(0xA5) + + epdconfig.delay_ms(2000) + epdconfig.module_exit() +### END OF FILE ### + diff --git a/waveshare_epd/epd2in7b_V2.py b/waveshare_epd/epd2in7b_V2.py new file mode 100644 index 0000000..3c1b25e --- /dev/null +++ b/waveshare_epd/epd2in7b_V2.py @@ -0,0 +1,186 @@ +# ***************************************************************************** +# * | File : epd2in7b_V2.py +# * | Author : Waveshare team +# * | Function : Electronic paper driver +# * | Info : +# *---------------- +# * | This version: V1.0 +# * | Date : 2020-10-22 +# # | 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 = 176 +EPD_HEIGHT = 264 + +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 + + # 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(2) + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(200) + + # Send Command + 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) + + # Send 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) + + # Read Busy + 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") + + # Setting the display window + def SetWindows(self, Xstart, Ystart, Xend, Yend): + self.send_command(0x44) + self.send_data((Xstart >> 3) & 0xff) + self.send_data((Xend >> 3) & 0xff) + + self.send_command(0x45) + self.send_data(Ystart & 0xff) + self.send_data((Ystart >> 8) & 0xff) + self.send_data(Yend & 0xff) + self.send_data((Yend >> 8) & 0xff) + + # Set Cursor + def SetCursor(self, Xstart, Ystart): + self.send_command(0x4E) + self.send_data(Xstart & 0xff) + self.send_command(0x4F) + self.send_data(Ystart & 0xff) + self.send_data((Ystart >> 8) & 0xff) + + # Initialize the e-Paper register + def init(self): + if (epdconfig.module_init() != 0): + return -1 + + self.reset() + + self.ReadBusy() + self.send_command(0x12) + self.ReadBusy() + + self.send_command(0x00) + self.send_data(0x27) + self.send_data(0x01) + self.send_data(0x00) + + self.send_command(0x11) + self.send_data(0x03) + + self.SetWindows(0, 0, self.width-1, self.height-1) + self.SetCursor(0, 0) + return 0 + + def getbuffer(self, image): + # logger.debug("bufsiz = ",int(self.width/8) * self.height) + buf = [0xFF] * (int(self.width/8) * self.height) + image_monocolor = image.convert('1') + imwidth, imheight = image_monocolor.size + pixels = image_monocolor.load() + # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) + if(imwidth == self.width and imheight == self.height): + logger.debug("Vertical") + for y in range(imheight): + for x in range(imwidth): + # Set the bits for the column of pixels at the current position. + if pixels[x, y] == 0: + buf[int((x + y * self.width) / 8)] &= ~(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: + buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) + return buf + + # Sends the image buffer in RAM to e-Paper and displays + def display(self, imageblack, imagered): + Width = self.width / 8 + Height = self.height + + self.send_command(0x24) + for i in range(0, int(Width * Height)): + self.send_data(imageblack[i]) + + self.send_command(0x26) + for i in range(0, int(Width * Height)): + self.send_data(~imagered[i]) + + self.TurnOnDisplay() + + # Clear the screen + def Clear(self): + self.send_command(0x24) + for i in range(0, int(self.width * self.height / 8)): + self.send_data(0xff) + + self.send_command(0x26) + for i in range(0, int(self.width * self.height / 8)): + self.send_data(0x00) + + self.TurnOnDisplay() + + # Turn on display + def TurnOnDisplay(self): + self.send_command(0x20) + self.ReadBusy() + + # Enter sleep mode + def sleep(self): + self.send_command(0x10) + self.send_data(0x01) + + epdconfig.delay_ms(2000) + epdconfig.module_exit() +### END OF FILE ### + diff --git a/waveshare_epd/epd2in9.py b/waveshare_epd/epd2in9.py new file mode 100644 index 0000000..22246a0 --- /dev/null +++ b/waveshare_epd/epd2in9.py @@ -0,0 +1,204 @@ +# ***************************************************************************** +# * | File : epd2in9.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 = 128 +EPD_HEIGHT = 296 + +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 = [ + 0x50, 0xAA, 0x55, 0xAA, 0x11, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xFF, 0xFF, 0x1F, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + ] + + lut_partial_update = [ + 0x10, 0x18, 0x18, 0x08, 0x18, 0x18, + 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x13, 0x14, 0x44, 0x12, + 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(200) + + 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 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) + + 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 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(0x11) # DATA_ENTRY_MODE_SETTING + self.send_data(0x03) # X increment Y increment + + self.send_command(0x32) # WRITE_LUT_REGISTER + for i in range(0, len(lut)): + self.send_data(lut[i]) + # EPD hardware init end + return 0 + + def getbuffer(self, image): + # logger.debug("bufsiz = ",int(self.width/8) * self.height) + buf = [0xFF] * (int(self.width/8) * self.height) + image_monocolor = image.convert('1') + imwidth, imheight = image_monocolor.size + pixels = image_monocolor.load() + # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) + if(imwidth == self.width and imheight == self.height): + logger.debug("Vertical") + for y in range(imheight): + for x in range(imwidth): + # Set the bits for the column of pixels at the current position. + if pixels[x, y] == 0: + buf[int((x + y * self.width) / 8)] &= ~(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: + buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) + return buf + + def display(self, image): + if (image == None): + return + self.SetWindow(0, 0, self.width - 1, self.height - 1) + for j in range(0, self.height): + self.SetCursor(0, j) + self.send_command(0x24) # WRITE_RAM + for i in range(0, int(self.width / 8)): + self.send_data(image[i + j * int(self.width / 8)]) + self.TurnOnDisplay() + + def Clear(self, color): + self.SetWindow(0, 0, self.width - 1, self.height - 1) + for j in range(0, self.height): + self.SetCursor(0, j) + self.send_command(0x24) # WRITE_RAM + for i in range(0, int(self.width / 8)): + self.send_data(color) + self.TurnOnDisplay() + + def sleep(self): + self.send_command(0x10) # DEEP_SLEEP_MODE + self.send_data(0x01) + + epdconfig.delay_ms(2000) + epdconfig.module_exit() +### END OF FILE ### + diff --git a/waveshare_epd/epd2in9_V2.py b/waveshare_epd/epd2in9_V2.py new file mode 100644 index 0000000..76d630e --- /dev/null +++ b/waveshare_epd/epd2in9_V2.py @@ -0,0 +1,303 @@ +# ***************************************************************************** +# * | File : epd2in9_V2.py +# * | Author : Waveshare team +# * | Function : Electronic paper driver +# * | Info : +# *---------------- +# * | This version: V1.0 +# * | Date : 2020-10-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 = 128 +EPD_HEIGHT = 296 + +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 + + WF_PARTIAL_2IN9 = [ + 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, + 0x0A,0x0,0x0,0x0,0x0,0x0,0x1, + 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,0xB0,0x32,0x36, + ] + + WS_20_30 = [ + 0x80, 0x66, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x0, 0x0, 0x0, + 0x10, 0x66, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, + 0x80, 0x66, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x0, 0x0, 0x0, + 0x10, 0x66, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x14, 0x8, 0x0, 0x0, 0x0, 0x0, 0x2, + 0xA, 0xA, 0x0, 0xA, 0xA, 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, + 0x14, 0x8, 0x0, 0x1, 0x0, 0x0, 0x1, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x0, 0x0, 0x0, + 0x22, 0x17, 0x41, 0x0, 0x32, 0x36 + ] + + # Hardware reset + def reset(self): + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(50) + epdconfig.digital_write(self.reset_pin, 0) + epdconfig.delay_ms(2) + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(50) + + 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): + 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") + + def TurnOnDisplay(self): + self.send_command(0x22) # DISPLAY_UPDATE_CONTROL_2 + self.send_data(0xc7) + self.send_command(0x20) # MASTER_ACTIVATION + self.ReadBusy() + + def TurnOnDisplay_Partial(self): + self.send_command(0x22) # DISPLAY_UPDATE_CONTROL_2 + self.send_data(0x0F) + self.send_command(0x20) # MASTER_ACTIVATION + self.ReadBusy() + + def lut(self, lut): + self.send_command(0x32) + for i in range(0, 153): + self.send_data(lut[i]) + self.ReadBusy() + + 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]) + + 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) + + 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) + + 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(0x27) + self.send_data(0x01) + 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.send_command(0x21) # Display update control + self.send_data(0x00) + self.send_data(0x80) + + self.SetCursor(0, 0) + self.ReadBusy() + + self.SetLut(self.WS_20_30) + # EPD hardware init end + return 0 + + def getbuffer(self, image): + # logger.debug("bufsiz = ",int(self.width/8) * self.height) + buf = [0xFF] * (int(self.width/8) * self.height) + image_monocolor = image.convert('1') + imwidth, imheight = image_monocolor.size + pixels = image_monocolor.load() + # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) + if(imwidth == self.width and imheight == self.height): + logger.debug("Vertical") + for y in range(imheight): + for x in range(imwidth): + # Set the bits for the column of pixels at the current position. + if pixels[x, y] == 0: + buf[int((x + y * self.width) / 8)] &= ~(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: + buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) + return buf + + def display(self, image): + if (image == None): + return + self.send_command(0x24) # WRITE_RAM + for j in range(0, self.height): + for i in range(0, int(self.width / 8)): + self.send_data(image[i + j * int(self.width / 8)]) + self.TurnOnDisplay() + + def display_Base(self, image): + if (image == None): + return + + self.send_command(0x24) # WRITE_RAM + for j in range(0, self.height): + for i in range(0, int(self.width / 8)): + self.send_data(image[i + j * int(self.width / 8)]) + + self.send_command(0x26) # WRITE_RAM + for j in range(0, self.height): + for i in range(0, int(self.width / 8)): + self.send_data(image[i + j * int(self.width / 8)]) + + self.TurnOnDisplay() + + def display_Partial(self, image): + if (image == None): + return + + epdconfig.digital_write(self.reset_pin, 0) + epdconfig.delay_ms(2) + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(2) + + self.SetLut(self.WF_PARTIAL_2IN9) + 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, int(self.width / 8)): + self.send_data(image[i + j * int(self.width / 8)]) + self.TurnOnDisplay_Partial() + + def Clear(self, color): + self.send_command(0x24) # WRITE_RAM + for j in range(0, self.height): + for i in range(0, int(self.width / 8)): + self.send_data(color) + self.TurnOnDisplay() + + def sleep(self): + self.send_command(0x10) # DEEP_SLEEP_MODE + self.send_data(0x01) + + epdconfig.delay_ms(2000) + epdconfig.module_exit() +### END OF FILE ### + diff --git a/waveshare_epd/epd2in9b_V3.py b/waveshare_epd/epd2in9b_V3.py new file mode 100644 index 0000000..7749155 --- /dev/null +++ b/waveshare_epd/epd2in9b_V3.py @@ -0,0 +1,161 @@ +# ***************************************************************************** +# * | File : epd2in9b_V3.py +# * | Author : Waveshare team +# * | Function : Electronic paper driver +# * | Info : +# *---------------- +# * | This version: V1.1 +# * | Date : 2020-12-03 +# # | 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 = 128 +EPD_HEIGHT = 296 + +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 + + # 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(2) + 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): + logger.debug("e-Paper busy") + self.send_command(0X71) + while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy + self.send_command(0X71) + epdconfig.delay_ms(200) + logger.debug("e-Paper busy release") + + def init(self): + if (epdconfig.module_init() != 0): + return -1 + # EPD hardware init start + self.reset() + + self.send_command(0x04) + self.ReadBusy()#waiting for the electronic paper IC to release the idle signal + + self.send_command(0x00) #panel setting + self.send_data(0x0f) #LUT from OTP,128x296 + self.send_data(0x89) #Temperature sensor, boost and other related timing settings + + self.send_command(0x61) #resolution setting + self.send_data (0x80) + self.send_data (0x01) + self.send_data (0x28) + + self.send_command(0X50) #VCOM AND DATA INTERVAL SETTING + self.send_data(0x77) #WBmode:VBDF 17|D7 VBDW 97 VBDB 57 + # WBRmode:VBDF F7 VBDW 77 VBDB 37 VBDR B7 + + return 0 + + def getbuffer(self, image): + # logger.debug("bufsiz = ",int(self.width/8) * self.height) + buf = [0xFF] * (int(self.width/8) * self.height) + image_monocolor = image.convert('1') + imwidth, imheight = image_monocolor.size + pixels = image_monocolor.load() + # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) + if(imwidth == self.width and imheight == self.height): + logger.debug("Vertical") + for y in range(imheight): + for x in range(imwidth): + # Set the bits for the column of pixels at the current position. + if pixels[x, y] == 0: + buf[int((x + y * self.width) / 8)] &= ~(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: + buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) + return buf + + def display(self, blackimage, ryimage): # ryimage: red or yellow image + if (blackimage != None): + self.send_command(0X10) + for i in range(0, int(self.width * self.height / 8)): + self.send_data(blackimage[i]) + if (ryimage != None): + self.send_command(0X13) + for i in range(0, int(self.width * self.height / 8)): + self.send_data(ryimage[i]) + + self.send_command(0x12) + epdconfig.delay_ms(200) + self.ReadBusy() + + def Clear(self): + self.send_command(0X10) + for i in range(0, int(self.width * self.height / 8)): + self.send_data(0xff) + self.send_command(0X13) + for i in range(0, int(self.width * self.height / 8)): + self.send_data(0xff) + + self.send_command(0x12) + epdconfig.delay_ms(200) + self.ReadBusy() + + def sleep(self): + self.send_command(0X02) # power off + self.ReadBusy() + self.send_command(0X07) # deep sleep + self.send_data(0xA5) + + epdconfig.delay_ms(2000) + epdconfig.module_exit() +### END OF FILE ### + diff --git a/waveshare_epd/epd2in9bc.py b/waveshare_epd/epd2in9bc.py new file mode 100644 index 0000000..51ea5b5 --- /dev/null +++ b/waveshare_epd/epd2in9bc.py @@ -0,0 +1,158 @@ +# ***************************************************************************** +# * | File : epd2in9bc.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 = 128 +EPD_HEIGHT = 296 + +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 + + # 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): + logger.debug("e-Paper busy") + while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy + epdconfig.delay_ms(200) + logger.debug("e-Paper busy release") + + def init(self): + if (epdconfig.module_init() != 0): + return -1 + # EPD hardware init start + self.reset() + + self.send_command(0x06) # boost + self.send_data (0x17) + self.send_data (0x17) + self.send_data (0x17) + self.send_command(0x04) # POWER_ON + self.ReadBusy() + self.send_command(0X00) # PANEL_SETTING + self.send_data(0x8F) + self.send_command(0X50) # VCOM_AND_DATA_INTERVAL_SETTING + self.send_data(0x77) + self.send_command(0x61) # TCON_RESOLUTION + self.send_data (0x80) + self.send_data (0x01) + self.send_data (0x28) + # self.send_command(VCM_DC_SETTING_REGISTER) + # self.send_data (0x0A) + + return 0 + + def getbuffer(self, image): + # logger.debug("bufsiz = ",int(self.width/8) * self.height) + buf = [0xFF] * (int(self.width/8) * self.height) + image_monocolor = image.convert('1') + imwidth, imheight = image_monocolor.size + pixels = image_monocolor.load() + # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) + if(imwidth == self.width and imheight == self.height): + logger.debug("Vertical") + for y in range(imheight): + for x in range(imwidth): + # Set the bits for the column of pixels at the current position. + if pixels[x, y] == 0: + buf[int((x + y * self.width) / 8)] &= ~(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: + buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) + return buf + + def display(self, blackimage, ryimage): # ryimage: red or yellow image + if (blackimage != None): + self.send_command(0X10) + for i in range(0, int(self.width * self.height / 8)): + self.send_data(blackimage[i]) + if (ryimage != None): + self.send_command(0X13) + for i in range(0, int(self.width * self.height / 8)): + self.send_data(ryimage[i]) + + self.send_command(0x12) + self.ReadBusy() + + def Clear(self): + self.send_command(0X10) + for i in range(0, int(self.width * self.height / 8)): + self.send_data(0xff) + self.send_command(0X13) + for i in range(0, int(self.width * self.height / 8)): + self.send_data(0xff) + + self.send_command(0x12) + self.ReadBusy() + + def sleep(self): + self.send_command(0X02) # power off + self.ReadBusy() + self.send_command(0X07) # deep sleep + self.send_data(0xA5) + + epdconfig.delay_ms(2000) + epdconfig.module_exit() +### END OF FILE ### + diff --git a/waveshare_epd/epd2in9d.py b/waveshare_epd/epd2in9d.py new file mode 100644 index 0000000..b48d7d8 --- /dev/null +++ b/waveshare_epd/epd2in9d.py @@ -0,0 +1,303 @@ +#!/usr/bin/python +# -*- coding:utf-8 -*- + +# ***************************************************************************** +# * | File : epd2in9d.py +# * | Author : Waveshare team +# * | Function : Electronic paper driver +# * | Info : +# *---------------- +# * | This version: V2.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 +from PIL import Image +import RPi.GPIO as GPIO + +# Display resolution +EPD_WIDTH = 128 +EPD_HEIGHT = 296 + +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_vcom1 = [ + 0x00, 0x19, 0x01, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, + ] + + lut_ww1 = [ + 0x00, 0x19, 0x01, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ] + + lut_bw1 = [ + 0x80, 0x19, 0x01, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ] + + lut_wb1 = [ + 0x40, 0x19, 0x01, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ] + + lut_bb1 = [ + 0x00, 0x19, 0x01, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 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(20) + epdconfig.digital_write(self.reset_pin, 0) + epdconfig.delay_ms(5) + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(20) + epdconfig.digital_write(self.reset_pin, 0) + epdconfig.delay_ms(5) + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(20) + epdconfig.digital_write(self.reset_pin, 0) + epdconfig.delay_ms(5) + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(20) + + 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): + logger.debug("e-Paper busy") + while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy + self.send_command(0x71) + epdconfig.delay_ms(10) + logger.debug("e-Paper busy release") + + def TurnOnDisplay(self): + self.send_command(0x12) + epdconfig.delay_ms(10) + self.ReadBusy() + + def init(self): + if (epdconfig.module_init() != 0): + return -1 + # EPD hardware init start + self.reset() + + self.send_command(0x04) + self.ReadBusy() #waiting for the electronic paper IC to release the idle signal + + self.send_command(0x00) #panel setting + self.send_data(0x1f) # LUT from OTP,KW-BF KWR-AF BWROTP 0f BWOTP 1f + + self.send_command(0x61) #resolution setting + self.send_data (0x80) + self.send_data (0x01) + self.send_data (0x28) + + self.send_command(0X50) #VCOM AND DATA INTERVAL SETTING + self.send_data(0x97) #WBmode:VBDF 17|D7 VBDW 97 VBDB 57 WBRmode:VBDF F7 VBDW 77 VBDB 37 VBDR B7 + + return 0 + + def SetPartReg(self): + + self.send_command(0x01) #POWER SETTING + self.send_data(0x03) + self.send_data(0x00) + self.send_data(0x2b) + self.send_data(0x2b) + self.send_data(0x03) + + self.send_command(0x06) #boost soft start + self.send_data(0x17) #A + self.send_data(0x17) #B + self.send_data(0x17) #C + + self.send_command(0x04) + self.ReadBusy() + + self.send_command(0x00) #panel setting + self.send_data(0xbf) #LUT from OTP,128x296 + + self.send_command(0x30) #PLL setting + self.send_data(0x3a) # 3a 100HZ 29 150Hz 39 200HZ 31 171HZ + + self.send_command(0x61) #resolution setting + self.send_data(self.width) + self.send_data((self.height >> 8) & 0xff) + self.send_data(self.height & 0xff) + + self.send_command(0x82) #vcom_DC setting + self.send_data(0x12) + + self.send_command(0X50) + self.send_data(0x97) + + self.send_command(0x20) # vcom + for count in range(0, 44): + self.send_data(self.lut_vcom1[count]) + self.send_command(0x21) # ww -- + for count in range(0, 42): + self.send_data(self.lut_ww1[count]) + self.send_command(0x22) # bw r + for count in range(0, 42): + self.send_data(self.lut_bw1[count]) + self.send_command(0x23) # wb w + for count in range(0, 42): + self.send_data(self.lut_wb1[count]) + self.send_command(0x24) # bb b + for count in range(0, 42): + self.send_data(self.lut_bb1[count]) + + def getbuffer(self, image): + # logger.debug("bufsiz = ",int(self.width/8) * self.height) + buf = [0xFF] * (int(self.width/8) * self.height) + image_monocolor = image.convert('1') + imwidth, imheight = image_monocolor.size + pixels = image_monocolor.load() + # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) + if(imwidth == self.width and imheight == self.height): + logger.debug("Vertical") + for y in range(imheight): + for x in range(imwidth): + # Set the bits for the column of pixels at the current position. + if pixels[x, y] == 0: + buf[int((x + y * self.width) / 8)] &= ~(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: + buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) + return buf + + def display(self, image): + self.send_command(0x10) + for i in range(0, int(self.width * self.height / 8)): + self.send_data(0x00) + epdconfig.delay_ms(10) + + self.send_command(0x13) + for i in range(0, int(self.width * self.height / 8)): + self.send_data(image[i]) + epdconfig.delay_ms(10) + + self.TurnOnDisplay() + + def DisplayPartial(self, image): + self.SetPartReg() + self.send_command(0x91) + self.send_command(0x90) + self.send_data(0) + self.send_data(self.width - 1) + + self.send_data(0) + self.send_data(0) + self.send_data(int(self.height / 256)) + self.send_data(self.height % 256 - 1) + self.send_data(0x28) + + self.send_command(0x10) + for i in range(0, int(self.width * self.height / 8)): + self.send_data(image[i]) + epdconfig.delay_ms(10) + + self.send_command(0x13) + for i in range(0, int(self.width * self.height / 8)): + self.send_data(~image[i]) + epdconfig.delay_ms(10) + + self.TurnOnDisplay() + + def Clear(self, color): + self.send_command(0x10) + for i in range(0, int(self.width * self.height / 8)): + self.send_data(0x00) + epdconfig.delay_ms(10) + + self.send_command(0x13) + for i in range(0, int(self.width * self.height / 8)): + self.send_data(0xFF) + epdconfig.delay_ms(10) + + self.TurnOnDisplay() + + def sleep(self): + self.send_command(0X50) + self.send_data(0xf7) + self.send_command(0X02) #power off + self.send_command(0X07) #deep sleep + self.send_data(0xA5) + + epdconfig.delay_ms(2000) + epdconfig.module_exit() + +### END OF FILE ### + diff --git a/waveshare_epd/epd3in7.py b/waveshare_epd/epd3in7.py new file mode 100644 index 0000000..fe4dd26 --- /dev/null +++ b/waveshare_epd/epd3in7.py @@ -0,0 +1,453 @@ +# ***************************************************************************** +# * | File : epd3in7.py +# * | Author : Waveshare team +# * | Function : Electronic paper driver +# * | Info : +# *---------------- +# * | This version: V1.0 +# * | Date : 2020-07-16 +# # | 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 = 280 +EPD_HEIGHT = 480 + +GRAY1 = 0xff #white +GRAY2 = 0xC0 #Close to white +GRAY3 = 0x80 #Close to black +GRAY4 = 0x00 #black + +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 + self.GRAY1 = GRAY1 #white + self.GRAY2 = GRAY2 + self.GRAY3 = GRAY3 #gray + self.GRAY4 = GRAY4 #Blackest + + lut_4Gray_GC = [ + 0x2A,0x06,0x15,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x28,0x06,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x20,0x06,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x14,0x06,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x02,0x02,0x0A,0x00,0x00,0x00,0x08,0x08,0x02, + 0x00,0x02,0x02,0x0A,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x22,0x22,0x22,0x22,0x22 + ] + + lut_1Gray_GC = [ + 0x2A,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x05,0x2A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x2A,0x15,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x05,0x0A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x02,0x03,0x0A,0x00,0x02,0x06,0x0A,0x05,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x22,0x22,0x22,0x22,0x22 + ] + + lut_1Gray_DU = [ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x2A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x0A,0x55,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x05,0x05,0x00,0x05,0x03,0x05,0x05,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x22,0x22,0x22,0x22,0x22 + ] + + lut_1Gray_A2 = [ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x0A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x03,0x05,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x22,0x22,0x22,0x22,0x22 + ] + + # 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): + 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") + + + def init(self, mode): + if (epdconfig.module_init() != 0): + return -1 + # EPD hardware init start + self.reset() + + self.send_command(0x12) + epdconfig.delay_ms(300) + + self.send_command(0x46) + self.send_data(0xF7) + self.ReadBusy() + self.send_command(0x47) + self.send_data(0xF7) + self.ReadBusy() + + self.send_command(0x01) # setting gaet number + self.send_data(0xDF) + self.send_data(0x01) + self.send_data(0x00) + + self.send_command(0x03) # set gate voltage + self.send_data(0x00) + + self.send_command(0x04) # set source voltage + self.send_data(0x41) + self.send_data(0xA8) + self.send_data(0x32) + + self.send_command(0x11) # set data entry sequence + self.send_data(0x03) + + self.send_command(0x3C) # set border + self.send_data(0x03) + + self.send_command(0x0C) # set booster strength + self.send_data(0xAE) + self.send_data(0xC7) + self.send_data(0xC3) + self.send_data(0xC0) + self.send_data(0xC0) + + self.send_command(0x18) # set internal sensor on + self.send_data(0x80) + + self.send_command(0x2C) # set vcom value + self.send_data(0x44) + + if(mode == 0): #4Gray + self.send_command(0x37) # set display option, these setting turn on previous function + self.send_data(0x00) + self.send_data(0x00) + self.send_data(0x00) + self.send_data(0x00) + self.send_data(0x00) + self.send_data(0x00) + self.send_data(0x00) + self.send_data(0x00) + self.send_data(0x00) + self.send_data(0x00) + elif(mode == 1): #1Gray + self.send_command(0x37) # set display option, these setting turn on previous function + self.send_data(0x00) #can switch 1 gray or 4 gray + self.send_data(0xFF) + self.send_data(0xFF) + self.send_data(0xFF) + self.send_data(0xFF) + self.send_data(0x4F) + self.send_data(0xFF) + self.send_data(0xFF) + self.send_data(0xFF) + self.send_data(0xFF) + else: + logger.debug("There is no such mode") + + self.send_command(0x44) # setting X direction start/end position of RAM + self.send_data(0x00) + self.send_data(0x00) + self.send_data(0x17) + self.send_data(0x01) + + self.send_command(0x45) # setting Y direction start/end position of RAM + self.send_data(0x00) + self.send_data(0x00) + self.send_data(0xDF) + self.send_data(0x01) + + self.send_command(0x22) # Display Update Control 2 + self.send_data(0xCF) + return 0 + + + def load_lut(self, lut): + self.send_command(0x32) + for i in range(0, 105): + self.send_data(lut[i]) + + + def getbuffer(self, image): + # logger.debug("bufsiz = ",int(self.width/8) * self.height) + buf = [0xFF] * (int(self.width/8) * self.height) + image_monocolor = image.convert('1') + imwidth, imheight = image_monocolor.size + pixels = image_monocolor.load() + # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) + if(imwidth == self.width and imheight == self.height): + logger.debug("Vertical") + for y in range(imheight): + for x in range(imwidth): + # Set the bits for the column of pixels at the current position. + if pixels[x, y] == 0: + buf[int((x + y * self.width) / 8)] &= ~(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: + buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) + return buf + + + def getbuffer_4Gray(self, image): + # logger.debug("bufsiz = ",int(self.width/8) * self.height) + buf = [0xFF] * (int(self.width / 4) * self.height) + image_monocolor = image.convert('L') + imwidth, imheight = image_monocolor.size + pixels = image_monocolor.load() + i=0 + # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) + if(imwidth == self.width and imheight == self.height): + logger.debug("Vertical") + for y in range(imheight): + for x in range(imwidth): + # Set the bits for the column of pixels at the current position. + if(pixels[x, y] == 0xC0): + pixels[x, y] = 0x80 + elif (pixels[x, y] == 0x80): + pixels[x, y] = 0x40 + i = i + 1 + if(i%4 == 0): + buf[int((x + (y * self.width))/4)] = ((pixels[x-3, y]&0xc0) | (pixels[x-2, y]&0xc0)>>2 | (pixels[x-1, y]&0xc0)>>4 | (pixels[x, y]&0xc0)>>6) + + elif(imwidth == self.height and imheight == self.width): + logger.debug("Horizontal") + for x in range(imwidth): + for y in range(imheight): + newx = y + newy = imwidth - x - 1 + if(pixels[x, y] == 0xC0): + pixels[x, y] = 0x80 + elif (pixels[x, y] == 0x80): + pixels[x, y] = 0x40 + i = i + 1 + if(i%4 == 0): + buf[int((newx + (newy * self.width))/4)] = ((pixels[x, y-3]&0xc0) | (pixels[x, y-2]&0xc0)>>2 | (pixels[x, y-1]&0xc0)>>4 | (pixels[x, y]&0xc0)>>6) + return buf + + + def display_4Gray(self, image): + if (image == None): + return + + self.send_command(0x4E) + self.send_data(0x00) + self.send_data(0x00) + self.send_command(0x4F) + self.send_data(0x00) + self.send_data(0x00) + + self.send_command(0x24) + for i in range(0, (int)(self.height*(self.width/8))): + temp3=0 + for j in range(0, 2): + temp1 = image[i*2+j] + for k in range(0, 2): + temp2 = temp1&0xC0 + if(temp2 == 0xC0): + temp3 |= 0x01 #white + elif(temp2 == 0x00): + temp3 |= 0x00 #black + elif(temp2 == 0x80): + temp3 |= 0x00 #gray1 + else: #0x40 + temp3 |= 0x01 #gray2 + temp3 <<= 1 + temp1 <<= 2 + temp2 = temp1&0xC0 + if(temp2 == 0xC0): #white + temp3 |= 0x01 + elif(temp2 == 0x00): #black + temp3 |= 0x00 + elif(temp2 == 0x80): + temp3 |= 0x00 #gray1 + else: #0x40 + temp3 |= 0x01 #gray2 + if(j!=1 or k!=1): + temp3 <<= 1 + temp1 <<= 2 + self.send_data(temp3) + + self.send_command(0x4E) + self.send_data(0x00) + self.send_data(0x00) + self.send_command(0x4F) + self.send_data(0x00) + self.send_data(0x00) + + self.send_command(0x26) + for i in range(0, (int)(self.height*(self.width/8))): + temp3=0 + for j in range(0, 2): + temp1 = image[i*2+j] + for k in range(0, 2): + temp2 = temp1&0xC0 + if(temp2 == 0xC0): + temp3 |= 0x01 #white + elif(temp2 == 0x00): + temp3 |= 0x00 #black + elif(temp2 == 0x80): + temp3 |= 0x01 #gray1 + else: #0x40 + temp3 |= 0x00 #gray2 + temp3 <<= 1 + temp1 <<= 2 + temp2 = temp1&0xC0 + if(temp2 == 0xC0): #white + temp3 |= 0x01 + elif(temp2 == 0x00): #black + temp3 |= 0x00 + elif(temp2 == 0x80): + temp3 |= 0x01 #gray1 + else: #0x40 + temp3 |= 0x00 #gray2 + if(j!=1 or k!=1): + temp3 <<= 1 + temp1 <<= 2 + self.send_data(temp3) + + self.load_lut(self.lut_4Gray_GC) + self.send_command(0x22) + self.send_data(0xC7) + self.send_command(0x20) + self.ReadBusy() + + + def display_1Gray(self, image): + if (image == None): + return + + self.send_command(0x4E) + self.send_data(0x00) + self.send_data(0x00) + self.send_command(0x4F) + self.send_data(0x00) + self.send_data(0x00) + + self.send_command(0x24) + for j in range(0, self.height): + for i in range(0, int(self.width / 8)): + self.send_data(image[i + j * int(self.width / 8)]) + + self.load_lut(self.lut_1Gray_A2) + self.send_command(0x20) + self.ReadBusy() + + + def Clear(self, color, mode): + self.send_command(0x4E) + self.send_data(0x00) + self.send_data(0x00) + self.send_command(0x4F) + self.send_data(0x00) + self.send_data(0x00) + + self.send_command(0x24) + for j in range(0, self.height): + for i in range(0, int(self.width / 8)): + self.send_data(0xff) + + if(mode == 0): #4Gray + self.send_command(0x26) + for j in range(0, self.height): + for i in range(0, int(self.width / 8)): + self.send_data(0xff) + self.load_lut(self.lut_4Gray_GC) + self.send_command(0x22) + self.send_data(0xC7) + elif(mode == 1): #1Gray + self.load_lut(self.lut_1Gray_DU) + else: + logger.debug("There is no such mode") + + self.send_command(0x20) + self.ReadBusy() + + + def sleep(self): + self.send_command(0X50) # DEEP_SLEEP_MODE + self.send_data(0xf7) + self.send_command(0X02) #power off + self.send_command(0X07) #deep sleep + self.send_data(0xA5) + + epdconfig.delay_ms(2000) + epdconfig.module_exit() + +### END OF FILE ### + diff --git a/waveshare_epd/epd4in01f.py b/waveshare_epd/epd4in01f.py new file mode 100644 index 0000000..ae423fb --- /dev/null +++ b/waveshare_epd/epd4in01f.py @@ -0,0 +1,236 @@ +#!/usr/bin/python +# -*- coding:utf-8 -*- +# ***************************************************************************** +# * | File : epd4in01f.py +# * | Author : Waveshare team +# * | Function : Electronic paper driver +# * | Info : +# *---------------- +# * | This version: V1.0 +# * | Date : 2020-11-06 +# # | 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 = 640 +EPD_HEIGHT = 400 + +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 + self.BLACK = 0x000000 # 0000 BGR + self.WHITE = 0xffffff # 0001 + self.GREEN = 0x00ff00 # 0010 + self.BLUE = 0xff0000 # 0011 + self.RED = 0x0000ff # 0100 + self.YELLOW = 0x00ffff # 0101 + self.ORANGE = 0x0080ff # 0110 + + + # 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(1) + 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 ReadBusyHigh(self): + logger.debug("e-Paper busy") + while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy + epdconfig.delay_ms(10) + logger.debug("e-Paper busy release") + + def ReadBusyLow(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") + + def init(self): + if (epdconfig.module_init() != 0): + return -1 + # EPD hardware init start + self.reset() + + self.ReadBusyHigh() + self.send_command(0x00); + self.send_data(0x2f); + self.send_data(0x00); + self.send_command(0x01); + self.send_data(0x37); + self.send_data(0x00); + self.send_data(0x05); + self.send_data(0x05); + self.send_command(0x03); + self.send_data(0x00); + self.send_command(0x06); + self.send_data(0xC7); + self.send_data(0xC7); + self.send_data(0x1D); + self.send_command(0x41); + self.send_data(0x00); + self.send_command(0x50); + self.send_data(0x37); + self.send_command(0x60); + self.send_data(0x22); + self.send_command(0x61); + self.send_data(0x02); + self.send_data(0x80); + self.send_data(0x01); + self.send_data(0x90); + self.send_command(0xE3); + self.send_data(0xAA); + + # EPD hardware init end + return 0 + + def getbuffer(self, image): + buf = [0x00] * int(self.width * self.height / 2) + image_monocolor = image.convert('RGB')#Picture mode conversion + imwidth, imheight = image_monocolor.size + pixels = image_monocolor.load() + logger.debug('imwidth = %d imheight = %d ',imwidth, imheight) + if(imwidth == self.width and imheight == self.height): + for y in range(imheight): + for x in range(imwidth): + # Set the bits for the column of pixels at the current position. + Add = int((x + y * self.width) / 2) + Color = 0; + if (pixels[x, y][0] == 0 and pixels[x, y][1] == 0 and pixels[x, y][2] == 0): + Color = 0 + elif (pixels[x, y][0] == 255 and pixels[x, y][1] == 255 and pixels[x, y][2] == 255): + Color = 1 + elif (pixels[x, y][0] == 0 and pixels[x, y][1] == 255 and pixels[x, y][2] == 0): + Color = 2 + elif (pixels[x, y][0] == 0 and pixels[x, y][1] == 0 and pixels[x, y][2] == 255): + Color = 3 + elif (pixels[x, y][0] == 255 and pixels[x, y][1] == 0 and pixels[x, y][2] == 0): + Color = 4 + elif (pixels[x, y][0] == 255 and pixels[x, y][1] == 255 and pixels[x, y][2] == 0): + Color = 5 + elif (pixels[x, y][0] == 255 and pixels[x, y][1] == 128 and pixels[x, y][2] == 0): + Color = 6 + + data_t = buf[Add]&(~(0xF0 >> ((x % 2)*4))) + buf[Add] = data_t | ((Color << 4) >> ((x % 2)*4)); + + elif(imwidth == self.height and imheight == self.width): + for y in range(imheight): + for x in range(imwidth): + newx = y + newy = self.height - x - 1 + Add = int((newx + newy*self.width) / 2) + Color = 0; + if (pixels[x, y][0] == 0 and pixels[x, y][1] == 0 and pixels[x, y][2] == 0): + Color = 0 + elif (pixels[x, y][0] == 255 and pixels[x, y][1] == 255 and pixels[x, y][2] == 255): + Color = 1 + elif (pixels[x, y][0] == 0 and pixels[x, y][1] == 255 and pixels[x, y][2] == 0): + Color = 2 + elif (pixels[x, y][0] == 0 and pixels[x, y][1] == 0 and pixels[x, y][2] == 255): + Color = 3 + elif (pixels[x, y][0] == 255 and pixels[x, y][1] == 0 and pixels[x, y][2] == 0): + Color = 4 + elif (pixels[x, y][0] == 255 and pixels[x, y][1] == 255 and pixels[x, y][2] == 0): + Color = 5 + elif (pixels[x, y][0] == 255 and pixels[x, y][1] == 128 and pixels[x, y][2] == 0): + Color = 6 + + data_t = buf[Add]&(~(0xF0 >> ((newx % 2)*4))) + buf[Add] = data_t | ((Color << 4) >> ((newx % 2)*4)); + return buf + + def display(self,image): + self.send_command(0x61)#Set Resolution setting + self.send_data(0x02) + self.send_data(0x80) + self.send_data(0x01) + self.send_data(0x90) + self.send_command(0x10) + for i in range(0, int(EPD_HEIGHT)): + for j in range(0, int(EPD_WIDTH/2)): + self.send_data((image[j+(int(EPD_WIDTH/2)*i)])) + self.send_command(0x04)#0x04 + self.ReadBusyHigh() + self.send_command(0x12)#0x12 + self.ReadBusyHigh() + self.send_command(0x02) #0x02 + self.ReadBusyLow() + # epdconfig.delay_ms(500) + + def Clear(self): + self.send_command(0x61)#Set Resolution setting + self.send_data(0x02) + self.send_data(0x80) + self.send_data(0x01) + self.send_data(0x90) + self.send_command(0x10) + for i in range(0, int(EPD_HEIGHT)): + for j in range(0, int(EPD_WIDTH/2)): + self.send_data(0x11) + #BLACK 0x00 /// 0000 + #WHITE 0x11 /// 0001 + #GREEN 0x22 /// 0010 + #BLUE 0x33 /// 0011 + #RED 0x44 /// 0100 + #YELLOW 0x55 /// 0101 + #ORANGE 0x66 /// 0110 + #CLEAN 0x77 /// 0111 unavailable Afterimage + self.send_command(0x04)#0x04 + self.ReadBusyHigh() + self.send_command(0x12)#0x12 + self.ReadBusyHigh() + self.send_command(0x02) #0x02 + self.ReadBusyLow() + # epdconfig.delay_ms(500) + + def sleep(self): + # epdconfig.delay_ms(500) + self.send_command(0x07) # DEEP_SLEEP + self.send_data(0XA5) + + epdconfig.delay_ms(2000) + epdconfig.module_exit() + \ No newline at end of file diff --git a/waveshare_epd/epd4in2.py b/waveshare_epd/epd4in2.py new file mode 100644 index 0000000..08ce91f --- /dev/null +++ b/waveshare_epd/epd4in2.py @@ -0,0 +1,663 @@ +# ***************************************************************************** +# * | File : epd4in2.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 +from PIL import Image +import RPi.GPIO as GPIO + +# Display resolution +EPD_WIDTH = 400 +EPD_HEIGHT = 300 + +GRAY1 = 0xff #white +GRAY2 = 0xC0 +GRAY3 = 0x80 #gray +GRAY4 = 0x00 #Blackest + +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 + self.GRAY1 = GRAY1 #white + self.GRAY2 = GRAY2 + self.GRAY3 = GRAY3 #gray + self.GRAY4 = GRAY4 #Blackest + self.DATA = [0x00] * 15000 + + lut_vcom0 = [ + 0x00, 0x08, 0x08, 0x00, 0x00, 0x02, + 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x01, + 0x00, 0x08, 0x08, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, + ] + lut_ww = [ + 0x50, 0x08, 0x08, 0x00, 0x00, 0x02, + 0x90, 0x0F, 0x0F, 0x00, 0x00, 0x01, + 0xA0, 0x08, 0x08, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ] + lut_bw = [ + 0x50, 0x08, 0x08, 0x00, 0x00, 0x02, + 0x90, 0x0F, 0x0F, 0x00, 0x00, 0x01, + 0xA0, 0x08, 0x08, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ] + lut_wb = [ + 0xA0, 0x08, 0x08, 0x00, 0x00, 0x02, + 0x90, 0x0F, 0x0F, 0x00, 0x00, 0x01, + 0x50, 0x08, 0x08, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ] + lut_bb = [ + 0x20, 0x08, 0x08, 0x00, 0x00, 0x02, + 0x90, 0x0F, 0x0F, 0x00, 0x00, 0x01, + 0x10, 0x08, 0x08, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ] + #******************************partial screen update LUT*********************************/ + EPD_4IN2_Partial_lut_vcom1 =[ + 0x00, 0x01, 0x20, 0x01, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ] + + EPD_4IN2_Partial_lut_ww1 =[ + 0x00, 0x01, 0x20, 0x01, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ] + + EPD_4IN2_Partial_lut_bw1 =[ + 0x20, 0x01, 0x20, 0x01, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ] + + EPD_4IN2_Partial_lut_wb1 =[ + 0x10, 0x01, 0x20, 0x01, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ] + + EPD_4IN2_Partial_lut_bb1 =[ + 0x00, 0x01,0x20, 0x01, 0x00, 0x01, + 0x00, 0x00,0x00, 0x00, 0x00, 0x00, + 0x00, 0x00,0x00, 0x00, 0x00, 0x00, + 0x00, 0x00,0x00, 0x00, 0x00, 0x00, + 0x00, 0x00,0x00, 0x00, 0x00, 0x00, + 0x00, 0x00,0x00, 0x00, 0x00, 0x00, + 0x00, 0x00,0x00, 0x00, 0x00, 0x00, + ] + + #******************************gray*********************************/ + #0~3 gray + EPD_4IN2_4Gray_lut_vcom =[ + 0x00 ,0x0A ,0x00 ,0x00 ,0x00 ,0x01, + 0x60 ,0x14 ,0x14 ,0x00 ,0x00 ,0x01, + 0x00 ,0x14 ,0x00 ,0x00 ,0x00 ,0x01, + 0x00 ,0x13 ,0x0A ,0x01 ,0x00 ,0x01, + 0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00, + 0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00, + 0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 + ] + #R21 + EPD_4IN2_4Gray_lut_ww =[ + 0x40 ,0x0A ,0x00 ,0x00 ,0x00 ,0x01, + 0x90 ,0x14 ,0x14 ,0x00 ,0x00 ,0x01, + 0x10 ,0x14 ,0x0A ,0x00 ,0x00 ,0x01, + 0xA0 ,0x13 ,0x01 ,0x00 ,0x00 ,0x01, + 0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00, + 0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00, + 0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00, + ] + #R22H r + EPD_4IN2_4Gray_lut_bw =[ + 0x40 ,0x0A ,0x00 ,0x00 ,0x00 ,0x01, + 0x90 ,0x14 ,0x14 ,0x00 ,0x00 ,0x01, + 0x00 ,0x14 ,0x0A ,0x00 ,0x00 ,0x01, + 0x99 ,0x0C ,0x01 ,0x03 ,0x04 ,0x01, + 0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00, + 0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00, + 0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00, + ] + #R23H w + EPD_4IN2_4Gray_lut_wb =[ + 0x40 ,0x0A ,0x00 ,0x00 ,0x00 ,0x01, + 0x90 ,0x14 ,0x14 ,0x00 ,0x00 ,0x01, + 0x00 ,0x14 ,0x0A ,0x00 ,0x00 ,0x01, + 0x99 ,0x0B ,0x04 ,0x04 ,0x01 ,0x01, + 0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00, + 0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00, + 0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00, + ] + #R24H b + EPD_4IN2_4Gray_lut_bb =[ + 0x80 ,0x0A ,0x00 ,0x00 ,0x00 ,0x01, + 0x90 ,0x14 ,0x14 ,0x00 ,0x00 ,0x01, + 0x20 ,0x14 ,0x0A ,0x00 ,0x00 ,0x01, + 0x50 ,0x13 ,0x01 ,0x00 ,0x00 ,0x01, + 0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00, + 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(10) + epdconfig.digital_write(self.reset_pin, 0) + epdconfig.delay_ms(10) + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(10) + epdconfig.digital_write(self.reset_pin, 0) + epdconfig.delay_ms(10) + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(10) + epdconfig.digital_write(self.reset_pin, 0) + epdconfig.delay_ms(10) + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(10) + + 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): + self.send_command(0x71) + while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy + self.send_command(0x71) + epdconfig.delay_ms(100) + + def set_lut(self): + self.send_command(0x20) # vcom + for count in range(0, 36): + self.send_data(self.lut_vcom0[count]) + + self.send_command(0x21) # ww -- + for count in range(0, 36): + self.send_data(self.lut_ww[count]) + + self.send_command(0x22) # bw r + for count in range(0, 36): + self.send_data(self.lut_bw[count]) + + self.send_command(0x23) # wb w + for count in range(0, 36): + self.send_data(self.lut_bb[count]) + + self.send_command(0x24) # bb b + for count in range(0, 36): + self.send_data(self.lut_wb[count]) + + + def Partial_SetLut(self): + self.send_command(0x20); + for count in range(0, 44): + self.send_data(self.EPD_4IN2_Partial_lut_vcom1[count]) + + self.send_command(0x21); + for count in range(0, 42): + self.send_data(self.EPD_4IN2_Partial_lut_ww1[count]) + + self.send_command(0x22); + for count in range(0, 42): + self.send_data(self.EPD_4IN2_Partial_lut_bw1[count]) + + self.send_command(0x23); + for count in range(0, 42): + self.send_data(self.EPD_4IN2_Partial_lut_wb1[count]) + + self.send_command(0x24); + for count in range(0, 42): + self.send_data(self.EPD_4IN2_Partial_lut_bb1[count]) + + + + def Gray_SetLut(self): + self.send_command(0x20) #vcom + for count in range(0, 42): + self.send_data(self.EPD_4IN2_4Gray_lut_vcom[count]) + + self.send_command(0x21) #red not use + for count in range(0, 42): + self.send_data(self.EPD_4IN2_4Gray_lut_ww[count]) + + self.send_command(0x22) #bw r + for count in range(0, 42): + self.send_data(self.EPD_4IN2_4Gray_lut_bw[count]) + + self.send_command(0x23) #wb w + for count in range(0, 42): + self.send_data(self.EPD_4IN2_4Gray_lut_wb[count]) + + self.send_command(0x24) #bb b + for count in range(0, 42): + self.send_data(self.EPD_4IN2_4Gray_lut_bb[count]) + + self.send_command(0x25) #vcom + for count in range(0, 42): + self.send_data(self.EPD_4IN2_4Gray_lut_ww[count]) + + + def init(self): + if (epdconfig.module_init() != 0): + return -1 + # EPD hardware init start + self.reset() + + self.send_command(0x01) # POWER SETTING + self.send_data(0x03) # VDS_EN, VDG_EN + self.send_data(0x00) # VCOM_HV, VGHL_LV[1], VGHL_LV[0] + self.send_data(0x2b) # VDH + self.send_data(0x2b) # VDL + + self.send_command(0x06) # boost soft start + self.send_data(0x17) + self.send_data(0x17) + self.send_data(0x17) + + self.send_command(0x04) # POWER_ON + self.ReadBusy() + + self.send_command(0x00) # panel setting + self.send_data(0xbf) # KW-BF KWR-AF BWROTP 0f + + self.send_command(0x30) # PLL setting + self.send_data(0x3c) # 3A 100HZ 29 150Hz 39 200HZ 31 171HZ + + self.send_command(0x61) # resolution setting + self.send_data(0x01) + self.send_data(0x90) # 128 + self.send_data(0x01) + self.send_data(0x2c) + + self.send_command(0x82) # vcom_DC setting + self.send_data(0x12) + + self.send_command(0X50) # VCOM AND DATA INTERVAL SETTING + self.send_data(0x97) # 97white border 77black border VBDF 17|D7 VBDW 97 VBDB 57 VBDF F7 VBDW 77 VBDB 37 VBDR B7 + + self.set_lut() + # EPD hardware init end + return 0 + + def init_Partial(self): + if (epdconfig.module_init() != 0): + return -1 + # EPD hardware init start + self.reset() + + self.send_command(0x01) # POWER SETTING + self.send_data(0x03) # VDS_EN, VDG_EN + self.send_data(0x00) # VCOM_HV, VGHL_LV[1], VGHL_LV[0] + self.send_data(0x2b) # VDH + self.send_data(0x2b) # VDL + + self.send_command(0x06) # boost soft start + self.send_data(0x17) + self.send_data(0x17) + self.send_data(0x17) + + self.send_command(0x04) # POWER_ON + self.ReadBusy() + + self.send_command(0x00) # panel setting + self.send_data(0xbf) # KW-BF KWR-AF BWROTP 0f + + self.send_command(0x30) # PLL setting + self.send_data(0x3c) # 3A 100HZ 29 150Hz 39 200HZ 31 171HZ + + self.send_command(0x61) # resolution setting + self.send_data(0x01) + self.send_data(0x90) # 128 + self.send_data(0x01) + self.send_data(0x2c) + + self.send_command(0x82) # vcom_DC setting + self.send_data(0x12) + + self.send_command(0X50) # VCOM AND DATA INTERVAL SETTING + self.send_data(0x07) # 97white border 77black border VBDF 17|D7 VBDW 97 VBDB 57 VBDF F7 VBDW 77 VBDB 37 VBDR B7 + + self.Partial_SetLut(); + # EPD hardware init end + return 0 + + def Init_4Gray(self): + if (epdconfig.module_init() != 0): + return -1 + # EPD hardware init start + self.reset() + + self.send_command(0x01) #POWER SETTING + self.send_data (0x03) + self.send_data (0x00) #VGH=20V,VGL=-20V + self.send_data (0x2b) #VDH=15V + self.send_data (0x2b) #VDL=-15V + self.send_data (0x13) + + self.send_command(0x06) #booster soft start + self.send_data (0x17) #A + self.send_data (0x17) #B + self.send_data (0x17) #C + + self.send_command(0x04) + self.ReadBusy() + + self.send_command(0x00) #panel setting + self.send_data(0x3f) #KW-3f KWR-2F BWROTP 0f BWOTP 1f + + self.send_command(0x30) #PLL setting + self.send_data (0x3c) #100hz + + self.send_command(0x61) #resolution setting + self.send_data (0x01) #400 + self.send_data (0x90) + self.send_data (0x01) #300 + self.send_data (0x2c) + + self.send_command(0x82) #vcom_DC setting + self.send_data (0x12) + + self.send_command(0X50) #VCOM AND DATA INTERVAL SETTING + self.send_data(0x97) + + def getbuffer(self, image): + # logger.debug("bufsiz = ",int(self.width/8) * self.height) + buf = [0xFF] * (int(self.width/8) * self.height) + image_monocolor = image.convert('1') + imwidth, imheight = image_monocolor.size + pixels = image_monocolor.load() + # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) + if(imwidth == self.width and imheight == self.height): + logger.debug("Horizontal") + for y in range(imheight): + for x in range(imwidth): + # Set the bits for the column of pixels at the current position. + if pixels[x, y] == 0: + buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) + elif(imwidth == self.height and imheight == self.width): + logger.debug("Vertical") + for y in range(imheight): + for x in range(imwidth): + newx = y + newy = self.height - x - 1 + if pixels[x, y] == 0: + buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) + return buf + + def getbuffer_4Gray(self, image): + # logger.debug("bufsiz = ",int(self.width/8) * self.height) + buf = [0xFF] * (int(self.width / 4) * self.height) + image_monocolor = image.convert('L') + imwidth, imheight = image_monocolor.size + pixels = image_monocolor.load() + i=0 + # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) + if(imwidth == self.width and imheight == self.height): + logger.debug("Vertical") + for y in range(imheight): + for x in range(imwidth): + # Set the bits for the column of pixels at the current position. + if(pixels[x, y] == 0xC0): + pixels[x, y] = 0x80 + elif (pixels[x, y] == 0x80): + pixels[x, y] = 0x40 + i= i+1 + if(i%4 == 0): + buf[int((x + (y * self.width))/4)] = ((pixels[x-3, y]&0xc0) | (pixels[x-2, y]&0xc0)>>2 | (pixels[x-1, y]&0xc0)>>4 | (pixels[x, y]&0xc0)>>6) + + elif(imwidth == self.height and imheight == self.width): + logger.debug("Horizontal") + for x in range(imwidth): + for y in range(imheight): + newx = y + newy = x + if(pixels[x, y] == 0xC0): + pixels[x, y] = 0x80 + elif (pixels[x, y] == 0x80): + pixels[x, y] = 0x40 + i= i+1 + if(i%4 == 0): + buf[int((newx + (newy * self.width))/4)] = ((pixels[x, y-3]&0xc0) | (pixels[x, y-2]&0xc0)>>2 | (pixels[x, y-1]&0xc0)>>4 | (pixels[x, y]&0xc0)>>6) + + return buf + + def display(self, image): + self.send_command(0x92); + self.set_lut(); + self.send_command(0x10) + for i in range(0, int(self.width * self.height / 8)): + self.send_data(0xFF) + + self.send_command(0x13) + for i in range(0, int(self.width * self.height / 8)): + self.send_data(image[i]) + + self.send_command(0x12) + self.ReadBusy() + + def EPD_4IN2_PartialDisplay(self, X_start, Y_start, X_end, Y_end, Image): + # EPD_WIDTH = 400 + # EPD_HEIGHT = 300 + if(EPD_WIDTH % 8 != 0): + Width = int(EPD_WIDTH / 8) + 1; + else: + Width = int(EPD_WIDTH / 8); + Height = EPD_HEIGHT; + + if(X_start % 8 != 0): + X_start = int(X_start/8)*8+8 + if(X_end % 8 != 0): + X_end = int(X_end/8)*8+8 + + + self.send_command(0x91); #This command makes the display enter partial mode + self.send_command(0x90); #resolution setting + self.send_data (int(X_start/256)); + self.send_data (int(X_start%256)); #x-start + + self.send_data (int(X_end /256)); + self.send_data (int(X_end %256)-1); #x-end + + self.send_data (int(Y_start/256)); + self.send_data (int(Y_start%256)); #y-start + + + self.send_data (int(Y_end/256)); + self.send_data (int(Y_end%256)-1); #y-end + self.send_data (0x28); + + self.send_command(0x10); #writes Old data to SRAM for programming + for j in range(0, int(Y_end - Y_start)): + for i in range(0, int(X_end/8) - int(X_start/8)): + self.send_data(self.DATA[(Y_start + j)*Width + int(X_start/8) + i]); + + self.send_command(0x13); #writes New data to SRAM. + for j in range(0, int(Y_end - Y_start)): + for i in range(0, int(X_end/8) - int(X_start/8)): + self.send_data(~Image[(Y_start + j)*Width + int(X_start/8) + i]); + self.DATA[(Y_start + j)*Width + int(X_start/8) + i] = ~Image[(Y_start + j)*Width + int(X_start/8) + i] + + self.send_command(0x12); #DISPLAY REFRESH + epdconfig.delay_ms(200) #The delay here is necessary, 200uS at least!!! + self.ReadBusy() + + + def display_4Gray(self, image): + self.send_command(0x92); + self.set_lut(); + self.send_command(0x10) + for i in range(0, int(EPD_WIDTH * EPD_HEIGHT / 8)): # EPD_WIDTH * EPD_HEIGHT / 4 + temp3=0 + for j in range(0, 2): + temp1 = image[i*2+j] + for k in range(0, 2): + temp2 = temp1&0xC0 + if(temp2 == 0xC0): + temp3 |= 0x01#white + elif(temp2 == 0x00): + temp3 |= 0x00 #black + elif(temp2 == 0x80): + temp3 |= 0x01 #gray1 + else: #0x40 + temp3 |= 0x00 #gray2 + temp3 <<= 1 + + temp1 <<= 2 + temp2 = temp1&0xC0 + if(temp2 == 0xC0): #white + temp3 |= 0x01 + elif(temp2 == 0x00): #black + temp3 |= 0x00 + elif(temp2 == 0x80): + temp3 |= 0x01 #gray1 + else : #0x40 + temp3 |= 0x00 #gray2 + if(j!=1 or k!=1): + temp3 <<= 1 + temp1 <<= 2 + self.send_data(temp3) + + self.send_command(0x13) + + for i in range(0, int(EPD_WIDTH * EPD_HEIGHT / 8)): #5808*4 46464 + temp3=0 + for j in range(0, 2): + temp1 = image[i*2+j] + for k in range(0, 2): + temp2 = temp1&0xC0 + if(temp2 == 0xC0): + temp3 |= 0x01#white + elif(temp2 == 0x00): + temp3 |= 0x00 #black + elif(temp2 == 0x80): + temp3 |= 0x00 #gray1 + else: #0x40 + temp3 |= 0x01 #gray2 + temp3 <<= 1 + + temp1 <<= 2 + temp2 = temp1&0xC0 + if(temp2 == 0xC0): #white + temp3 |= 0x01 + elif(temp2 == 0x00): #black + temp3 |= 0x00 + elif(temp2 == 0x80): + temp3 |= 0x00 #gray1 + else: #0x40 + temp3 |= 0x01 #gray2 + if(j!=1 or k!=1): + temp3 <<= 1 + temp1 <<= 2 + self.send_data(temp3) + + self.Gray_SetLut() + self.send_command(0x12) + epdconfig.delay_ms(200) + self.ReadBusy() + # pass + + def Clear(self): + self.send_command(0x10) + for i in range(0, int(self.width * self.height / 8)): + self.send_data(0xFF) + + self.send_command(0x13) + for i in range(0, int(self.width * self.height / 8)): + self.send_data(0xFF) + + self.send_command(0x12) + self.ReadBusy() + + def sleep(self): + self.send_command(0x02) # POWER_OFF + self.ReadBusy() + self.send_command(0x07) # DEEP_SLEEP + self.send_data(0XA5) + + epdconfig.delay_ms(2000) + epdconfig.module_exit() + +### END OF FILE ### + diff --git a/waveshare_epd/epd4in2b_V2.py b/waveshare_epd/epd4in2b_V2.py new file mode 100644 index 0000000..db080a5 --- /dev/null +++ b/waveshare_epd/epd4in2b_V2.py @@ -0,0 +1,153 @@ +# ***************************************************************************** +# * | File : epd4in2bc.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 = 400 +EPD_HEIGHT = 300 + +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 + + # 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): + logger.debug("e-Paper busy") + self.send_command(0x71); + while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy + self.send_command(0x71); + epdconfig.delay_ms(20) + logger.debug("e-Paper busy release") + + def init(self): + if (epdconfig.module_init() != 0): + return -1 + + self.reset() + + self.send_command(0x04); + self.ReadBusy(); + + self.send_command(0x00); + self.send_data(0x0f); + + return 0 + + def getbuffer(self, image): + # logger.debug("bufsiz = ",int(self.width/8) * self.height) + buf = [0xFF] * (int(self.width/8) * self.height) + image_monocolor = image.convert('1') + imwidth, imheight = image_monocolor.size + pixels = image_monocolor.load() + # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) + if(imwidth == self.width and imheight == self.height): + logger.debug("Horizontal") + for y in range(imheight): + for x in range(imwidth): + # Set the bits for the column of pixels at the current position. + if pixels[x, y] == 0: + buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) + elif(imwidth == self.height and imheight == self.width): + logger.debug("Vertical") + for y in range(imheight): + for x in range(imwidth): + newx = y + newy = self.height - x - 1 + if pixels[x, y] == 0: + buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) + return buf + + def display(self, imageblack, imagered): + self.send_command(0x10) + for i in range(0, int(self.width * self.height / 8)): + self.send_data(imageblack[i]) + + self.send_command(0x13) + for i in range(0, int(self.width * self.height / 8)): + self.send_data(imagered[i]) + + self.send_command(0x12) + epdconfig.delay_ms(20) + self.ReadBusy() + + def Clear(self): + self.send_command(0x10) + for i in range(0, int(self.width * self.height / 8)): + self.send_data(0xFF) + + self.send_command(0x13) + for i in range(0, int(self.width * self.height / 8)): + self.send_data(0xFF) + + self.send_command(0x12) + epdconfig.delay_ms(20) + self.ReadBusy() + + def sleep(self): + self.send_command(0X50); + self.send_data(0xf7); #border floating + + self.send_command(0X02); #power off + self.ReadBusy(); #waiting for the electronic paper IC to release the idle signal + self.send_command(0X07); #deep sleep + self.send_data(0xA5); + + epdconfig.delay_ms(2000) + epdconfig.module_exit() +### END OF FILE ### + diff --git a/waveshare_epd/epd4in2bc.py b/waveshare_epd/epd4in2bc.py new file mode 100644 index 0000000..c948f2f --- /dev/null +++ b/waveshare_epd/epd4in2bc.py @@ -0,0 +1,151 @@ +# ***************************************************************************** +# * | File : epd4in2bc.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 = 400 +EPD_HEIGHT = 300 + +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 + + # 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): + logger.debug("e-Paper busy") + while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy + epdconfig.delay_ms(100) + logger.debug("e-Paper busy release") + + def init(self): + if (epdconfig.module_init() != 0): + return -1 + + self.reset() + + self.send_command(0x06) # BOOSTER_SOFT_START + self.send_data (0x17) + self.send_data (0x17) + self.send_data (0x17) # 07 0f 17 1f 27 2F 37 2f + + self.send_command(0x04) # POWER_ON + self.ReadBusy() + + self.send_command(0x00) # PANEL_SETTING + self.send_data(0x0F) # LUT from OTP + + return 0 + + def getbuffer(self, image): + # logger.debug("bufsiz = ",int(self.width/8) * self.height) + buf = [0xFF] * (int(self.width/8) * self.height) + image_monocolor = image.convert('1') + imwidth, imheight = image_monocolor.size + pixels = image_monocolor.load() + # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) + if(imwidth == self.width and imheight == self.height): + logger.debug("Horizontal") + for y in range(imheight): + for x in range(imwidth): + # Set the bits for the column of pixels at the current position. + if pixels[x, y] == 0: + buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) + elif(imwidth == self.height and imheight == self.width): + logger.debug("Vertical") + for y in range(imheight): + for x in range(imwidth): + newx = y + newy = self.height - x - 1 + if pixels[x, y] == 0: + buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) + return buf + + def display(self, imageblack, imagered): + self.send_command(0x10) + for i in range(0, int(self.width * self.height / 8)): + self.send_data(imageblack[i]) + + self.send_command(0x13) + for i in range(0, int(self.width * self.height / 8)): + self.send_data(imagered[i]) + + self.send_command(0x12) + self.ReadBusy() + + def Clear(self): + self.send_command(0x10) + for i in range(0, int(self.width * self.height / 8)): + self.send_data(0xFF) + + self.send_command(0x13) + for i in range(0, int(self.width * self.height / 8)): + self.send_data(0xFF) + + self.send_command(0x12) + self.ReadBusy() + + def sleep(self): + self.send_command(0x02) # POWER_OFF + self.ReadBusy() + self.send_command(0x07) # DEEP_SLEEP + self.send_data(0xA5) # check code + + epdconfig.delay_ms(2000) + epdconfig.module_exit() +### END OF FILE ### + diff --git a/waveshare_epd/epd5in65f.py b/waveshare_epd/epd5in65f.py new file mode 100644 index 0000000..fc71d79 --- /dev/null +++ b/waveshare_epd/epd5in65f.py @@ -0,0 +1,216 @@ +#!/usr/bin/python +# -*- coding:utf-8 -*- +# ***************************************************************************** +# * | File : epd5in65f.py +# * | Author : Waveshare team +# * | Function : Electronic paper driver +# * | Info : +# *---------------- +# * | This version: V1.0 +# * | Date : 2020-03-02 +# # | 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 + +import PIL +from PIL import Image +import io + +# Display resolution +EPD_WIDTH = 600 +EPD_HEIGHT = 448 + +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 + self.BLACK = 0x000000 # 0000 BGR + self.WHITE = 0xffffff # 0001 + self.GREEN = 0x00ff00 # 0010 + self.BLUE = 0xff0000 # 0011 + self.RED = 0x0000ff # 0100 + self.YELLOW = 0x00ffff # 0101 + self.ORANGE = 0x0080ff # 0110 + + + # Hardware reset + def reset(self): + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(600) + epdconfig.digital_write(self.reset_pin, 0) + epdconfig.delay_ms(2) + 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 send_data_bulk(self, data): + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte2(data) + epdconfig.digital_write(self.cs_pin, 1) + + def ReadBusyHigh(self): + logger.debug("e-Paper busy") + while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy + epdconfig.delay_ms(100) + logger.debug("e-Paper busy release") + + def ReadBusyLow(self): + logger.debug("e-Paper busy") + while(epdconfig.digital_read(self.busy_pin) == 1): # 0: idle, 1: busy + epdconfig.delay_ms(100) + logger.debug("e-Paper busy release") + + def init(self): + if (epdconfig.module_init() != 0): + return -1 + # EPD hardware init start + self.reset() + + self.ReadBusyHigh() + self.send_command(0x00) + self.send_data(0xEF) + self.send_data(0x08) + self.send_command(0x01) + self.send_data(0x37) + self.send_data(0x00) + self.send_data(0x23) + self.send_data(0x23) + self.send_command(0x03) + self.send_data(0x00) + self.send_command(0x06) + self.send_data(0xC7) + self.send_data(0xC7) + self.send_data(0x1D) + self.send_command(0x30) + self.send_data(0x3c) + self.send_command(0x41) + self.send_data(0x00) + self.send_command(0x50) + self.send_data(0x37) + self.send_command(0x60) + self.send_data(0x22) + self.send_command(0x61) + self.send_data(0x02) + self.send_data(0x58) + self.send_data(0x01) + self.send_data(0xC0) + self.send_command(0xE3) + self.send_data(0xAA) + + epdconfig.delay_ms(100) + self.send_command(0x50) + self.send_data(0x37) + # EPD hardware init end + return 0 + + def getbuffer(self, image): + # Create a pallette with the 7 colors supported by the panel + pal_image = Image.new("P", (1,1)) + pal_image.putpalette( (0,0,0, 255,255,255, 0,255,0, 0,0,255, 255,0,0, 255,255,0, 255,128,0) + (0,0,0)*249) + + # Check if we need to rotate the image + imwidth, imheight = image.size + if(imwidth == self.width and imheight == self.height): + image_temp = image + elif(imwidth == self.height and imheight == self.width): + image_temp = image.rotate(90, expand=True) + else: + logger.warning("Invalid image dimensions: %d x %d, expected %d x %d" % (imwidth, imheight, self.width, self.height)) + + # Convert the soruce image to the 7 colors, dithering if needed + image_7color = image_temp.convert("RGB").quantize(palette=pal_image) + buf_7color = bytearray(image_7color.tobytes('raw')) + + # PIL does not support 4 bit color, so pack the 4 bits of color + # into a single byte to transfer to the panel + buf = [0x00] * int(self.width * self.height / 2) + idx = 0 + for i in range(0, len(buf_7color), 2): + buf[idx] = (buf_7color[i] << 4) + buf_7color[i+1] + idx += 1 + + return buf + + def display(self,image): + self.send_command(0x61) #Set Resolution setting + self.send_data(0x02) + self.send_data(0x58) + self.send_data(0x01) + self.send_data(0xC0) + self.send_command(0x10) + + self.send_data_bulk(image) + self.send_command(0x04) #0x04 + self.ReadBusyHigh() + self.send_command(0x12) #0x12 + self.ReadBusyHigh() + self.send_command(0x02) #0x02 + self.ReadBusyLow() + epdconfig.delay_ms(500) + + def Clear(self): + self.send_command(0x61) #Set Resolution setting + self.send_data(0x02) + self.send_data(0x58) + self.send_data(0x01) + self.send_data(0xC0) + self.send_command(0x10) + + # Set all pixels to white + buf = [0x11] * int(self.width * self.height / 2) + self.send_data_bulk(buf) + + self.send_command(0x04) #0x04 + self.ReadBusyHigh() + self.send_command(0x12) #0x12 + self.ReadBusyHigh() + self.send_command(0x02) #0x02 + self.ReadBusyLow() + epdconfig.delay_ms(500) + + def sleep(self): + epdconfig.delay_ms(500) + self.send_command(0x07) # DEEP_SLEEP + self.send_data(0XA5) + epdconfig.digital_write(self.reset_pin, 0) + + epdconfig.delay_ms(2000) + epdconfig.module_exit() diff --git a/waveshare_epd/epd5in83.py b/waveshare_epd/epd5in83.py new file mode 100644 index 0000000..84fabf0 --- /dev/null +++ b/waveshare_epd/epd5in83.py @@ -0,0 +1,203 @@ +# ***************************************************************************** +# * | File : epd5in83.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 = 600 +EPD_HEIGHT = 448 + +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 + + # 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(2) + 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): + logger.debug("e-Paper busy") + while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy + epdconfig.delay_ms(100) + logger.debug("e-Paper busy release") + + def init(self): + if (epdconfig.module_init() != 0): + return -1 + # EPD hardware init start + self.reset() + + self.send_command(0x01) # POWER_SETTING + self.send_data(0x37) + self.send_data(0x00) + + self.send_command(0x00) # PANEL_SETTING + self.send_data(0xCF) + self.send_data(0x08) + + self.send_command(0x06) # BOOSTER_SOFT_START + self.send_data(0xc7) + self.send_data(0xcc) + self.send_data(0x28) + + self.send_command(0x04) # POWER_ON + self.ReadBusy() + + self.send_command(0x30) # PLL_CONTROL + self.send_data(0x3c) + + self.send_command(0x41) # TEMPERATURE_CALIBRATION + self.send_data(0x00) + + self.send_command(0x50) # VCOM_AND_DATA_INTERVAL_SETTING + self.send_data(0x77) + + self.send_command(0x60) # TCON_SETTING + self.send_data(0x22) + + self.send_command(0x61) # TCON_RESOLUTION + self.send_data(0x02) # source 600 + self.send_data(0x58) + self.send_data(0x01) # gate 448 + self.send_data(0xC0) + + self.send_command(0x82) # VCM_DC_SETTING + self.send_data(0x1E) # decide by LUT file + + self.send_command(0xe5) # FLASH MODE + self.send_data(0x03) + + # EPD hardware init end + return 0 + + def getbuffer(self, image): + buf = [0x00] * int(self.width * self.height / 4) + image_monocolor = image.convert('1') + imwidth, imheight = image_monocolor.size + pixels = image_monocolor.load() + logger.debug('imwidth = %d imheight = %d ',imwidth, imheight) + if(imwidth == self.width and imheight == self.height): + for y in range(imheight): + for x in range(imwidth): + # Set the bits for the column of pixels at the current position. + if pixels[x, y] < 64: # black + buf[int((x + y * self.width) / 4)] &= ~(0xC0 >> (x % 4 * 2)) + elif pixels[x, y] < 192: # convert gray to red + buf[int((x + y * self.width) / 4)] &= ~(0xC0 >> (x % 4 * 2)) + buf[int((x + y * self.width) / 4)] |= 0x40 >> (x % 4 * 2) + else: # white + buf[int((x + y * self.width) / 4)] |= 0xC0 >> (x % 4 * 2) + elif(imwidth == self.height and imheight == self.width): + for y in range(imheight): + for x in range(imwidth): + newx = y + newy = self.height - x - 1 + if pixels[x, y] < 64: # black + buf[int((newx + newy*self.width) / 4)] &= ~(0xC0 >> (y % 4 * 2)) + elif pixels[x, y] < 192: # convert gray to red + buf[int((newx + newy*self.width) / 4)] &= ~(0xC0 >> (y % 4 * 2)) + buf[int((newx + newy*self.width) / 4)] |= 0x40 >> (y % 4 * 2) + else: # white + buf[int((newx + newy*self.width) / 4)] |= 0xC0 >> (y % 4 * 2) + return buf + + def display(self, image): + self.send_command(0x10) + for i in range(0, int(self.width / 4 * self.height)): + temp1 = image[i] + j = 0 + while (j < 4): + if ((temp1 & 0xC0) == 0xC0): + temp2 = 0x03 + elif ((temp1 & 0xC0) == 0x00): + temp2 = 0x00 + else: + temp2 = 0x04 + temp2 = (temp2 << 4) & 0xFF + temp1 = (temp1 << 2) & 0xFF + j += 1 + if((temp1 & 0xC0) == 0xC0): + temp2 |= 0x03 + elif ((temp1 & 0xC0) == 0x00): + temp2 |= 0x00 + else: + temp2 |= 0x04 + temp1 = (temp1 << 2) & 0xFF + self.send_data(temp2) + j += 1 + + self.send_command(0x12) + epdconfig.delay_ms(100) + self.ReadBusy() + + def Clear(self): + self.send_command(0x10) + for i in range(0, int(self.width / 4 * self.height)): + for j in range(0, 4): + self.send_data(0x33) + self.send_command(0x12) + self.ReadBusy() + + def sleep(self): + self.send_command(0x02) # POWER_OFF + self.ReadBusy() + self.send_command(0x07) # DEEP_SLEEP + self.send_data(0XA5) + + epdconfig.delay_ms(2000) + epdconfig.module_exit() + +### END OF FILE ### + diff --git a/waveshare_epd/epd5in83_V2.py b/waveshare_epd/epd5in83_V2.py new file mode 100644 index 0000000..680fcc7 --- /dev/null +++ b/waveshare_epd/epd5in83_V2.py @@ -0,0 +1,170 @@ +# ***************************************************************************** +# * | File : epd5in83_V2.py +# * | Author : Waveshare team +# * | Function : Electronic paper driver +# * | Info : +# *---------------- +# * | This version: V1.0 +# * | Date : 2020-12-09 +# # | 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 = 648 +EPD_HEIGHT = 480 + +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 + + # 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(2) + 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): + logger.debug("e-Paper busy") + while(epdconfig.digital_read(self.busy_pin) == 0): + epdconfig.delay_ms(20) + logger.debug("e-Paper busy release") + + def TurnOnDisplay(self): + self.send_command(0x12); #POWER ON + epdconfig.delay_ms(100) + self.ReadBusy(); + + def init(self): + if (epdconfig.module_init() != 0): + return -1 + # EPD hardware init start + self.reset() + + self.send_command(0x01) #POWER SETTING + self.send_data (0x07) + self.send_data (0x07) #VGH=20V,VGL=-20V + self.send_data (0x3f) #VDH=15V + self.send_data (0x3f) #VDL=-15V + + self.send_command(0x04) #POWER ON + epdconfig.delay_ms(100) + self.ReadBusy() #waiting for the electronic paper IC to release the idle signal + + self.send_command(0X00) #PANNEL SETTING + self.send_data(0x1F) #KW-3f KWR-2F BWROTP 0f BWOTP 1f + + self.send_command(0x61) #tres + self.send_data (0x02) #source 648 + self.send_data (0x88) + self.send_data (0x01) #gate 480 + self.send_data (0xE0) + + self.send_command(0X15) + self.send_data(0x00) + + self.send_command(0X50) #VCOM AND DATA INTERVAL SETTING + self.send_data(0x10) + self.send_data(0x07) + + self.send_command(0X60) #TCON SETTING + self.send_data(0x22) + + # EPD hardware init end + return 0 + + def getbuffer(self, image): + # logger.debug("bufsiz = ",int(self.width/8) * self.height) + buf = [0xFF] * (int(self.width/8) * self.height) + image_monocolor = image.convert('1') + imwidth, imheight = image_monocolor.size + pixels = image_monocolor.load() + # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) + if(imwidth == self.width and imheight == self.height): + logger.debug("Vertical") + for y in range(imheight): + for x in range(imwidth): + # Set the bits for the column of pixels at the current position. + if pixels[x, y] == 0: + buf[int((x + y * self.width) / 8)] &= ~(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: + buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) + return buf + + def display(self, image): + self.send_command(0x10) + for i in range(0, int(self.width * self.height / 8)): + self.send_data(0x00) + self.send_command(0x13) + for i in range(0, int(self.width * self.height / 8)): + self.send_data(~image[i]) + self.TurnOnDisplay() + + def Clear(self): + self.send_command(0x10) + for i in range(0, int(self.width * self.height / 8)): + self.send_data(0x00) + self.send_command(0x13) + for i in range(0, int(self.width * self.height / 8)): + self.send_data(0x00) + self.TurnOnDisplay() + + def sleep(self): + self.send_command(0x02) # POWER_OFF + self.ReadBusy() + self.send_command(0x07) # DEEP_SLEEP + self.send_data(0XA5) + + epdconfig.delay_ms(2000) + epdconfig.module_exit() + +### END OF FILE ### + diff --git a/waveshare_epd/epd5in83b_V2.py b/waveshare_epd/epd5in83b_V2.py new file mode 100644 index 0000000..67fa7f7 --- /dev/null +++ b/waveshare_epd/epd5in83b_V2.py @@ -0,0 +1,174 @@ +# ***************************************************************************** +# * | File : epd5in83b_V2.py +# * | Author : Waveshare team +# * | Function : Electronic paper driver +# * | Info : +# *---------------- +# * | This version: V1.0 +# * | Date : 2020-07-04 +# # | 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 = 648 +EPD_HEIGHT = 480 + +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 + + # 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(1) + 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): + logger.debug("e-Paper busy") + self.send_command(0X71) + while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy + self.send_command(0X71) + epdconfig.delay_ms(200) + logger.debug("e-Paper busy release") + + def init(self): + if (epdconfig.module_init() != 0): + return -1 + + self.reset() + + self.send_command(0x01) #POWER SETTING + self.send_data (0x07) + self.send_data (0x07) #VGH=20V,VGL=-20V + self.send_data (0x3f) #VDH=15V + self.send_data (0x3f) #VDL=-15V + + self.send_command(0x04) #POWER ON + epdconfig.delay_ms(100) + self.ReadBusy() #waiting for the electronic paper IC to release the idle signal + + self.send_command(0X00) #PANNEL SETTING + self.send_data(0x0F) #KW-3f KWR-2F BWROTP 0f BWOTP 1f + + self.send_command(0x61) #tres + self.send_data (0x02) #source 648 + self.send_data (0x88) + self.send_data (0x01) #gate 480 + self.send_data (0xe0) + + self.send_command(0X15) + self.send_data(0x00) + + self.send_command(0X50) #VCOM AND DATA INTERVAL SETTING + self.send_data(0x11) + self.send_data(0x07) + + self.send_command(0X60) #TCON SETTING + self.send_data(0x22) + + return 0 + + def getbuffer(self, image): + # logger.debug("bufsiz = ",int(self.width/8) * self.height) + buf = [0xFF] * (int(self.width/8) * self.height) + image_monocolor = image.convert('1') + imwidth, imheight = image_monocolor.size + pixels = image_monocolor.load() + # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) + if(imwidth == self.width and imheight == self.height): + logger.debug("Vertical") + for y in range(imheight): + for x in range(imwidth): + # Set the bits for the column of pixels at the current position. + if pixels[x, y] == 0: + buf[int((x + y * self.width) / 8)] &= ~(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: + buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) + return buf + + def display(self, imageblack, imagered): + if (imageblack != None): + self.send_command(0X10) + for i in range(0, int(self.width * self.height / 8)): + self.send_data(imageblack[i]) + if (imagered != None): + self.send_command(0X13) + for i in range(0, int(self.width * self.height / 8)): + self.send_data(~imagered[i]) + + self.send_command(0x12) + epdconfig.delay_ms(200) + self.ReadBusy() + + def Clear(self): + self.send_command(0X10) + for i in range(0, int(self.width * self.height / 8)): + self.send_data(0xff) + self.send_command(0X13) + for i in range(0, int(self.width * self.height / 8)): + self.send_data(0x00) + + self.send_command(0x12) + epdconfig.delay_ms(200) + self.ReadBusy() + + def sleep(self): + self.send_command(0X02) # power off + self.ReadBusy() + self.send_command(0X07) # deep sleep + self.send_data(0xA5) + + epdconfig.delay_ms(2000) + epdconfig.module_exit() +### END OF FILE ### + diff --git a/waveshare_epd/epd5in83bc.py b/waveshare_epd/epd5in83bc.py new file mode 100644 index 0000000..cf5d4c4 --- /dev/null +++ b/waveshare_epd/epd5in83bc.py @@ -0,0 +1,203 @@ +# ***************************************************************************** +# * | File : epd5in83b.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 = 600 +EPD_HEIGHT = 448 + +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 + + # 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): + logger.debug("e-Paper busy") + while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy + epdconfig.delay_ms(100) + logger.debug("e-Paper busy release") + + def init(self): + if (epdconfig.module_init() != 0): + return -1 + + self.reset() + + self.send_command(0x01) # POWER_SETTING + self.send_data(0x37) + self.send_data(0x00) + + self.send_command(0x00) # PANEL_SETTING + self.send_data(0xCF) + self.send_data(0x08) + + self.send_command(0x30) # PLL_CONTROL + self.send_data(0x3A) # PLL: 0-15:0x3C, 15+:0x3A + self.send_command(0X82) # VCOM VOLTAGE SETTING + self.send_data(0x28) # all temperature range + + self.send_command(0x06) # boost + self.send_data(0xc7) + self.send_data(0xcc) + self.send_data(0x15) + + self.send_command(0X50) # VCOM AND DATA INTERVAL SETTING + self.send_data(0x77) + + self.send_command(0X60) # TCON SETTING + self.send_data(0x22) + + self.send_command(0X65) # FLASH CONTROL + self.send_data(0x00) + + self.send_command(0x61) # tres + self.send_data(0x02) # source 600 + self.send_data(0x58) + self.send_data(0x01) # gate 448 + self.send_data(0xc0) + + self.send_command(0xe5) # FLASH MODE + self.send_data(0x03) + self.send_data(0x03) + + return 0 + + def getbuffer(self, image): + # logger.debug("bufsiz = ",int(self.width/8) * self.height) + buf = [0xFF] * (int(self.width/8) * self.height) + image_monocolor = image.convert('1') + imwidth, imheight = image_monocolor.size + pixels = image_monocolor.load() + logger.debug('imwidth = %d imheight = %d ',imwidth, imheight) + if(imwidth == self.width and imheight == self.height): + logger.debug("Horizontal") + for y in range(imheight): + for x in range(imwidth): + # Set the bits for the column of pixels at the current position. + if pixels[x, y] == 0: + buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) + elif(imwidth == self.height and imheight == self.width): + logger.debug("Vertical") + for y in range(imheight): + for x in range(imwidth): + newx = y + newy = self.height - x - 1 + if pixels[x, y] == 0: + buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) + return buf + + def display(self, imageblack, imagered): + self.send_command(0x10) + for i in range(0, int(self.width / 8 * self.height)): + temp1 = imageblack[i] + temp2 = imagered[i] + j = 0 + while (j < 8): + if ((temp2 & 0x80) == 0x00): + temp3 = 0x04 #red + elif ((temp1 & 0x80) == 0x00): + temp3 = 0x00 #black + else: + temp3 = 0x03 #white + + temp3 = (temp3 << 4) & 0xFF + temp1 = (temp1 << 1) & 0xFF + temp2 = (temp2 << 1) & 0xFF + j += 1 + if((temp2 & 0x80) == 0x00): + temp3 |= 0x04 #red + elif ((temp1 & 0x80) == 0x00): + temp3 |= 0x00 #black + else: + temp3 |= 0x03 #white + temp1 = (temp1 << 1) & 0xFF + temp2 = (temp2 << 1) & 0xFF + self.send_data(temp3) + j += 1 + + self.send_command(0x04) # POWER ON + self.ReadBusy() + self.send_command(0x12) # display refresh + epdconfig.delay_ms(100) + self.ReadBusy() + + def Clear(self): + self.send_command(0x10) + for i in range(0, int(self.width / 8 * self.height)): + self.send_data(0x33) + self.send_data(0x33) + self.send_data(0x33) + self.send_data(0x33) + + self.send_command(0x04) # POWER ON + self.ReadBusy() + self.send_command(0x12) # display refresh + epdconfig.delay_ms(100) + self.ReadBusy() + + def sleep(self): + self.send_command(0x02) # POWER_OFF + self.ReadBusy() + self.send_command(0x07) # DEEP_SLEEP + self.send_data(0xA5) # check code + + epdconfig.delay_ms(2000) + epdconfig.module_exit() +### END OF FILE ### + diff --git a/waveshare_epd/epd7in5.py b/waveshare_epd/epd7in5.py new file mode 100644 index 0000000..2f8d8fa --- /dev/null +++ b/waveshare_epd/epd7in5.py @@ -0,0 +1,185 @@ +# ***************************************************************************** +# * | File : epd7in5.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 = 640 +EPD_HEIGHT = 384 + +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 + + # 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 send_data2(self, data): + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte2(data) + epdconfig.digital_write(self.cs_pin, 1) + + def ReadBusy(self): + logger.debug("e-Paper busy") + while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy + epdconfig.delay_ms(100) + logger.debug("e-Paper busy release") + + def init(self): + if (epdconfig.module_init() != 0): + return -1 + # EPD hardware init start + self.reset() + + self.send_command(0x01) # POWER_SETTING + self.send_data2([0x37, 0x00]) + + self.send_command(0x00) # PANEL_SETTING + self.send_data2([0xCF, 0x08]) + + self.send_command(0x06) # BOOSTER_SOFT_START + self.send_data2([0xc7, 0xcc, 0x28]) + + self.send_command(0x04) # POWER_ON + self.ReadBusy() + + self.send_command(0x30) # PLL_CONTROL + self.send_data(0x3c) + + self.send_command(0x41) # TEMPERATURE_CALIBRATION + self.send_data(0x00) + + self.send_command(0x50) # VCOM_AND_DATA_INTERVAL_SETTING + self.send_data(0x77) + + self.send_command(0x60) # TCON_SETTING + self.send_data(0x22) + + self.send_command(0x61) # TCON_RESOLUTION + self.send_data(EPD_WIDTH >> 8) #source 640 + self.send_data(EPD_WIDTH & 0xff) + self.send_data(EPD_HEIGHT >> 8) #gate 384 + self.send_data(EPD_HEIGHT & 0xff) + + self.send_command(0x82) # VCM_DC_SETTING + self.send_data(0x1E) # decide by LUT file + + self.send_command(0xe5) # FLASH MODE + self.send_data(0x03) + + # EPD hardware init end + return 0 + + def getbuffer(self, image): + img = image + imwidth, imheight = img.size + halfwidth = int(self.width / 2) + buf = [0x33] * halfwidth * self.height + + if(imwidth == self.width and imheight == self.height): + img = img.convert('1') + elif(imwidth == self.height and imheight == self.width): + img = img.rotate(90, expand=True).convert('1') + imwidth, imheight = img.size + else: + logger.warning("Wrong image dimensions: must be " + str(self.width) + "x" + str(self.height)) + # return a blank buffer + return buf + + pixels = img.load() + + for y in range(imheight): + offset = y * halfwidth + for x in range(1, imwidth, 2): + i = offset + x // 2 + if(pixels[x-1, y] > 191): + if(pixels[x, y] > 191): + buf[i] = 0x33 + else: + buf[i] = 0x30 + else: + if(pixels[x, y] > 191): + buf[i] = 0x03 + else: + buf[i] = 0x00 + return buf + + def display(self, image): + self.send_command(0x10) + self.send_data2(image) + self.send_command(0x12) + epdconfig.delay_ms(100) + self.ReadBusy() + + def Clear(self): + buf = [0x33] * int(self.width * self.height / 2) + self.send_command(0x10) + self.send_data2(buf) + self.send_command(0x12) + self.ReadBusy() + + def sleep(self): + self.send_command(0x02) # POWER_OFF + self.ReadBusy() + + self.send_command(0x07) # DEEP_SLEEP + self.send_data(0XA5) + + epdconfig.delay_ms(2000) + epdconfig.module_exit() +### END OF FILE ### + diff --git a/waveshare_epd/epd7in5_HD.py b/waveshare_epd/epd7in5_HD.py new file mode 100644 index 0000000..908d036 --- /dev/null +++ b/waveshare_epd/epd7in5_HD.py @@ -0,0 +1,182 @@ +# ***************************************************************************** +# * | File : epd7in5.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 = 880 +EPD_HEIGHT = 528 + +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 + + # 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(2) + 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 send_data2(self, data): + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte2(data) + epdconfig.digital_write(self.cs_pin, 1) + + def ReadBusy(self): + logger.debug("e-Paper busy") + busy = epdconfig.digital_read(self.busy_pin) + while(busy == 1): + busy = epdconfig.digital_read(self.busy_pin) + epdconfig.delay_ms(200) + + 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(0x46); # Auto Write Red RAM + self.send_data(0xf7); + self.ReadBusy(); + self.send_command(0x47); # Auto Write B/W RAM + self.send_data(0xf7); + self.ReadBusy(); + + self.send_command(0x0C); # Soft start setting + self.send_data2([0xAE, 0xC7, 0xC3, 0xC0, 0x40]) + + self.send_command(0x01); # Set MUX as 527 + self.send_data2([0xAF, 0x02, 0x01]) + + self.send_command(0x11); # Data entry mode + self.send_data(0x01); + + self.send_command(0x44); + self.send_data2([0x00, 0x00, 0x6F, 0x03]) # RAM x address start at 0 + self.send_command(0x45); + self.send_data2([0xAF, 0x02, 0x00, 0x00]) + + self.send_command(0x3C); # VBD + self.send_data(0x05); # LUT1, for white + + self.send_command(0x18); + self.send_data(0X80); + + + self.send_command(0x22); + self.send_data(0XB1); #Load Temperature and waveform setting. + self.send_command(0x20); + self.ReadBusy(); + + self.send_command(0x4E); # set RAM x address count to 0; + self.send_data2([0x00, 0x00]) + self.send_command(0x4F); + self.send_data2([0x00, 0x00]) + # EPD hardware init end + return 0 + + 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): + 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 [0xff] * int(self.width * self.height / 8) + + buf = bytearray(img.tobytes('raw')) + return buf + + def display(self, image): + self.send_command(0x4F); + self.send_data2([0x00, 0x00]) + self.send_command(0x24); + self.send_data2(image) + self.send_command(0x22); + self.send_data(0xF7);#Load LUT from MCU(0x32) + self.send_command(0x20); + epdconfig.delay_ms(10); + self.ReadBusy(); + + def Clear(self): + buf = [0xff] * int(self.width * self.height / 8) + self.send_command(0x4F); + self.send_data2([0x00, 0x00]) + self.send_command(0x24) + self.send_data2(buf) + + self.send_command(0x26) + self.send_data2(buf) + + self.send_command(0x22); + self.send_data(0xF7);#Load LUT from MCU(0x32) + self.send_command(0x20); + epdconfig.delay_ms(10); + self.ReadBusy(); + + def sleep(self): + self.send_command(0x10); + self.send_data(0x01); + + epdconfig.delay_ms(2000) + epdconfig.module_exit() +### END OF FILE ### + diff --git a/waveshare_epd/epd7in5_V2.py b/waveshare_epd/epd7in5_V2.py new file mode 100644 index 0000000..b1495ca --- /dev/null +++ b/waveshare_epd/epd7in5_V2.py @@ -0,0 +1,279 @@ +# ***************************************************************************** +# * | File : epd7in5.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 = 800 +EPD_HEIGHT = 480 + +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 + + Voltage_Frame_7IN5_V2 = [ + 0x6, 0x3F, 0x3F, 0x11, 0x24, 0x7, 0x17, + ] + + LUT_VCOM_7IN5_V2 = [ + 0x0, 0xF, 0xF, 0x0, 0x0, 0x1, + 0x0, 0xF, 0x1, 0xF, 0x1, 0x2, + 0x0, 0xF, 0xF, 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, + ] + + LUT_WW_7IN5_V2 = [ + 0x10, 0xF, 0xF, 0x0, 0x0, 0x1, + 0x84, 0xF, 0x1, 0xF, 0x1, 0x2, + 0x20, 0xF, 0xF, 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, + ] + + LUT_BW_7IN5_V2 = [ + 0x10, 0xF, 0xF, 0x0, 0x0, 0x1, + 0x84, 0xF, 0x1, 0xF, 0x1, 0x2, + 0x20, 0xF, 0xF, 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, + ] + + LUT_WB_7IN5_V2 = [ + 0x80, 0xF, 0xF, 0x0, 0x0, 0x1, + 0x84, 0xF, 0x1, 0xF, 0x1, 0x2, + 0x40, 0xF, 0xF, 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, + ] + + LUT_BB_7IN5_V2 = [ + 0x80, 0xF, 0xF, 0x0, 0x0, 0x1, + 0x84, 0xF, 0x1, 0xF, 0x1, 0x2, + 0x40, 0xF, 0xF, 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, + ] + + # Hardware reset + 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) + + 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 send_data2(self, data): + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.SPI.writebytes2(data) + epdconfig.digital_write(self.cs_pin, 1) + + def ReadBusy(self): + logger.debug("e-Paper busy") + self.send_command(0x71) + busy = epdconfig.digital_read(self.busy_pin) + while(busy == 0): + self.send_command(0x71) + busy = epdconfig.digital_read(self.busy_pin) + epdconfig.delay_ms(20) + logger.debug("e-Paper busy release") + + def SetLut(self, lut_vcom, lut_ww, lut_bw, lut_wb, lut_bb): + self.send_command(0x20) + for count in range(0, 42): + self.send_data(lut_vcom[count]) + + self.send_command(0x21) + for count in range(0, 42): + self.send_data(lut_ww[count]) + + self.send_command(0x22) + for count in range(0, 42): + self.send_data(lut_bw[count]) + + self.send_command(0x23) + for count in range(0, 42): + self.send_data(lut_wb[count]) + + self.send_command(0x24) + for count in range(0, 42): + self.send_data(lut_bb[count]) + + def init(self): + if (epdconfig.module_init() != 0): + return -1 + # EPD hardware init start + self.reset() + + # self.send_command(0x06) # btst + # self.send_data(0x17) + # self.send_data(0x17) + # self.send_data(0x28) # If an exception is displayed, try using 0x38 + # self.send_data(0x17) + + # self.send_command(0x01) #POWER SETTING + # self.send_data(0x07) + # self.send_data(0x07) #VGH=20V,VGL=-20V + # self.send_data(0x3f) #VDH=15V + # self.send_data(0x3f) #VDL=-15V + + self.send_command(0x01); # power setting + self.send_data(0x17); # 1-0=11: internal power + self.send_data(self.Voltage_Frame_7IN5_V2[6]); # VGH&VGL + self.send_data(self.Voltage_Frame_7IN5_V2[1]); # VSH + self.send_data(self.Voltage_Frame_7IN5_V2[2]); # VSL + self.send_data(self.Voltage_Frame_7IN5_V2[3]); # VSHR + + self.send_command(0x82); # VCOM DC Setting + self.send_data(self.Voltage_Frame_7IN5_V2[4]); # VCOM + + self.send_command(0x06); # Booster Setting + self.send_data(0x27); + self.send_data(0x27); + self.send_data(0x2F); + self.send_data(0x17); + + self.send_command(0x30); # OSC Setting + self.send_data(self.Voltage_Frame_7IN5_V2[0]); # 2-0=100: N=4 ; 5-3=111: M=7 ; 3C=50Hz 3A=100HZ + + self.send_command(0x04) #POWER ON + epdconfig.delay_ms(100) + self.ReadBusy() + + self.send_command(0X00) #PANNEL SETTING + self.send_data(0x3F) #KW-3f KWR-2F BWROTP 0f BWOTP 1f + + self.send_command(0x61) #tres + self.send_data(0x03) #source 800 + self.send_data(0x20) + self.send_data(0x01) #gate 480 + self.send_data(0xE0) + + self.send_command(0X15) + self.send_data(0x00) + + self.send_command(0X50) #VCOM AND DATA INTERVAL SETTING + self.send_data(0x10) + self.send_data(0x07) + + self.send_command(0X60) #TCON SETTING + self.send_data(0x22) + + self.send_command(0x65); # Resolution setting + self.send_data(0x00); + self.send_data(0x00); # 800*480 + self.send_data(0x00); + self.send_data(0x00); + + self.SetLut(self.LUT_VCOM_7IN5_V2, self.LUT_WW_7IN5_V2, self.LUT_BW_7IN5_V2, self.LUT_WB_7IN5_V2, self.LUT_BB_7IN5_V2) + # EPD hardware init end + return 0 + + 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')) + # The bytes need to be inverted, because in the PIL world 0=black and 1=white, but + # in the e-paper world 0=white and 1=black. + for i in range(len(buf)): + buf[i] ^= 0xFF + return buf + + def display(self, image): + self.send_command(0x13) + self.send_data2(image) + + self.send_command(0x12) + epdconfig.delay_ms(100) + self.ReadBusy() + + def Clear(self): + buf = [0x00] * (int(self.width/8) * self.height) + self.send_command(0x10) + self.send_data2(buf) + self.send_command(0x13) + self.send_data2(buf) + self.send_command(0x12) + epdconfig.delay_ms(100) + self.ReadBusy() + + def sleep(self): + self.send_command(0x02) # POWER_OFF + self.ReadBusy() + + self.send_command(0x07) # DEEP_SLEEP + self.send_data(0XA5) + + epdconfig.delay_ms(2000) + epdconfig.module_exit() +### END OF FILE ### + diff --git a/waveshare_epd/epd7in5b_HD.py b/waveshare_epd/epd7in5b_HD.py new file mode 100644 index 0000000..89f7979 --- /dev/null +++ b/waveshare_epd/epd7in5b_HD.py @@ -0,0 +1,208 @@ +# ***************************************************************************** +# * | File : epd7in5bc_HD.py +# * | Author : Waveshare team +# * | Function : Electronic paper driver +# * | Info : +# *---------------- +# * | This version: V1.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 = 880 +EPD_HEIGHT = 528 + +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 + + # 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(4) + 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): + logger.debug("e-Paper busy") + busy = epdconfig.digital_read(self.busy_pin) + while(busy == 1): + busy = epdconfig.digital_read(self.busy_pin) + epdconfig.delay_ms(200) + + def init(self): + if (epdconfig.module_init() != 0): + return -1 + + self.reset() + + self.send_command(0x12); #SWRESET + self.ReadBusy(); #waiting for the electronic paper IC to release the idle signal + + self.send_command(0x46); # Auto Write RAM + self.send_data(0xF7); + self.ReadBusy(); #waiting for the electronic paper IC to release the idle signal + + self.send_command(0x47); # Auto Write RAM + self.send_data(0xF7); + self.ReadBusy(); #waiting for the electronic paper IC to release the idle signal + + self.send_command(0x0C); # Soft start setting + self.send_data(0xAE); + self.send_data(0xC7); + self.send_data(0xC3); + self.send_data(0xC0); + self.send_data(0x40); + + self.send_command(0x01); # Set MUX as 527 + self.send_data(0xAF); + self.send_data(0x02); + self.send_data(0x01); + + self.send_command(0x11); # Data entry mode + self.send_data(0x01); + + self.send_command(0x44); + self.send_data(0x00); # RAM x address start at 0 + self.send_data(0x00); + self.send_data(0x6F); # RAM x address end at 36Fh -> 879 + self.send_data(0x03); + self.send_command(0x45); + self.send_data(0xAF); # RAM y address start at 20Fh; + self.send_data(0x02); + self.send_data(0x00); # RAM y address end at 00h; + self.send_data(0x00); + + self.send_command(0x3C); # VBD + self.send_data(0x01); # LUT1, for white + + self.send_command(0x18); + self.send_data(0X80); + self.send_command(0x22); + self.send_data(0XB1); #Load Temperature and waveform setting. + self.send_command(0x20); + self.ReadBusy(); #waiting for the electronic paper IC to release the idle signal + + self.send_command(0x4E); + self.send_data(0x00); + self.send_data(0x00); + self.send_command(0x4F); + self.send_data(0xAF); + self.send_data(0x02); + + return 0 + + def getbuffer(self, image): + # logger.debug("bufsiz = ",int(self.width/8) * self.height) + buf = [0xFF] * (int(self.width/8) * self.height) + image_monocolor = image.convert('1') + imwidth, imheight = image_monocolor.size + pixels = image_monocolor.load() + logger.debug('imwidth = %d imheight = %d ',imwidth, imheight) + if(imwidth == self.width and imheight == self.height): + logger.debug("Horizontal") + for y in range(imheight): + for x in range(imwidth): + # Set the bits for the column of pixels at the current position. + if pixels[x, y] == 0: + buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) + elif(imwidth == self.height and imheight == self.width): + logger.debug("Vertical") + for y in range(imheight): + for x in range(imwidth): + newx = y + newy = self.height - x - 1 + if pixels[x, y] == 0: + buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) + return buf + + def display(self, imageblack, imagered): + self.send_command(0x4F); + self.send_data(0xAf); + + self.send_command(0x24) + for i in range(0, int(self.width * self.height / 8)): + self.send_data(imageblack[i]); + + + self.send_command(0x26) + for i in range(0, int(self.width * self.height / 8)): + self.send_data(~imagered[i]); + + self.send_command(0x22); + self.send_data(0xC7); #Load LUT from MCU(0x32) + self.send_command(0x20); + epdconfig.delay_ms(200); #!!!The delay here is necessary, 200uS at least!!! + self.ReadBusy(); + + def Clear(self): + self.send_command(0x4F); + self.send_data(0xAf); + + self.send_command(0x24) + for i in range(0, int(self.width * self.height / 8)): + self.send_data(0xff); + + + self.send_command(0x26) + for i in range(0, int(self.width * self.height / 8)): + self.send_data(0x00); + + self.send_command(0x22); + self.send_data(0xC7); #Load LUT from MCU(0x32) + self.send_command(0x20); + epdconfig.delay_ms(200); #!!!The delay here is necessary, 200uS at least!!! + self.ReadBusy(); + + def sleep(self): + self.send_command(0x10); #deep sleep + self.send_data(0x01); + + epdconfig.delay_ms(2000) + epdconfig.module_exit() +### END OF FILE ### + diff --git a/waveshare_epd/epd7in5b_V2.py b/waveshare_epd/epd7in5b_V2.py new file mode 100644 index 0000000..df09ae3 --- /dev/null +++ b/waveshare_epd/epd7in5b_V2.py @@ -0,0 +1,192 @@ +# ***************************************************************************** +# * | File : epd7in5b_V2.py +# * | Author : Waveshare team +# * | Function : Electronic paper driver +# * | Info : +# *---------------- +# * | This version: V4.2 +# * | Date : 2022-01-08 +# # | 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 = 800 +EPD_HEIGHT = 480 + +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 + + # 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(4) + 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 send_data2(self, data): #faster + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.SPI.writebytes2(data) + epdconfig.digital_write(self.cs_pin, 1) + + def ReadBusy(self): + logger.debug("e-Paper busy") + self.send_command(0x71) + busy = epdconfig.digital_read(self.busy_pin) + while(busy == 0): + self.send_command(0x71) + busy = epdconfig.digital_read(self.busy_pin) + epdconfig.delay_ms(200) + logger.debug("e-Paper busy release") + + def init(self): + if (epdconfig.module_init() != 0): + return -1 + + self.reset() + + # self.send_command(0x06) # btst + # self.send_data(0x17) + # self.send_data(0x17) + # self.send_data(0x38) # If an exception is displayed, try using 0x38 + # self.send_data(0x17) + + self.send_command(0x01); #POWER SETTING + self.send_data(0x07); + self.send_data(0x07); #VGH=20V,VGL=-20V + self.send_data(0x3f); #VDH=15V + self.send_data(0x3f); #VDL=-15V + + self.send_command(0x04); #POWER ON + epdconfig.delay_ms(100); + self.ReadBusy(); + + self.send_command(0X00); #PANNEL SETTING + self.send_data(0x0F); #KW-3f KWR-2F BWROTP 0f BWOTP 1f + + self.send_command(0x61); #tres + self.send_data(0x03); #source 800 + self.send_data(0x20); + self.send_data(0x01); #gate 480 + self.send_data(0xE0); + + self.send_command(0X15); + self.send_data(0x00); + + self.send_command(0X50); #VCOM AND DATA INTERVAL SETTING + self.send_data(0x11); + self.send_data(0x07); + + self.send_command(0X60); #TCON SETTING + self.send_data(0x22); + + self.send_command(0x65); + self.send_data(0x00); + self.send_data(0x00); + self.send_data(0x00); + self.send_data(0x00); + + return 0 + + 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')) + # The bytes need to be inverted, because in the PIL world 0=black and 1=white, but + # in the e-paper world 0=white and 1=black. + for i in range(len(buf)): + buf[i] ^= 0xFF + return buf + + def display(self, imageblack, imagered): + self.send_command(0x10) + # The black bytes need to be inverted back from what getbuffer did + for i in range(len(imageblack)): + imageblack[i] ^= 0xFF + self.send_data2(imageblack) + + self.send_command(0x13) + self.send_data2(imagered) + + self.send_command(0x12) + epdconfig.delay_ms(100) + self.ReadBusy() + + def Clear(self): + buf = [0x00] * (int(self.width/8) * self.height) + buf2 = [0xff] * (int(self.width/8) * self.height) + self.send_command(0x10) + self.send_data2(buf2) + + self.send_command(0x13) + self.send_data2(buf) + + self.send_command(0x12) + epdconfig.delay_ms(100) + self.ReadBusy() + + def sleep(self): + self.send_command(0x02) # POWER_OFF + self.ReadBusy() + + self.send_command(0x07) # DEEP_SLEEP + self.send_data(0XA5) + + epdconfig.delay_ms(2000) + epdconfig.module_exit() +### END OF FILE ### + diff --git a/waveshare_epd/epd7in5bc.py b/waveshare_epd/epd7in5bc.py new file mode 100644 index 0000000..14c491c --- /dev/null +++ b/waveshare_epd/epd7in5bc.py @@ -0,0 +1,204 @@ +# ***************************************************************************** +# * | File : epd7in5bc.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 = 640 +EPD_HEIGHT = 384 + +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 + + # 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): + logger.debug("e-Paper busy") + while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy + epdconfig.delay_ms(100) + logger.debug("e-Paper busy release") + + def init(self): + if (epdconfig.module_init() != 0): + return -1 + + self.reset() + + self.send_command(0x01) # POWER_SETTING + self.send_data(0x37) + self.send_data(0x00) + + self.send_command(0x00) # PANEL_SETTING + self.send_data(0xCF) + self.send_data(0x08) + + self.send_command(0x30) # PLL_CONTROL + self.send_data(0x3A) # PLL: 0-15:0x3C, 15+:0x3A + + self.send_command(0x82) # VCM_DC_SETTING + self.send_data(0x28) #all temperature range + + self.send_command(0x06) # BOOSTER_SOFT_START + self.send_data(0xc7) + self.send_data(0xcc) + self.send_data(0x15) + + self.send_command(0x50) # VCOM AND DATA INTERVAL SETTING + self.send_data(0x77) + + self.send_command(0x60) # TCON_SETTING + self.send_data(0x22) + + self.send_command(0x65) # FLASH CONTROL + self.send_data(0x00) + + self.send_command(0x61) # TCON_RESOLUTION + self.send_data(self.width >> 8) # source 640 + self.send_data(self.width & 0xff) + self.send_data(self.height >> 8) # gate 384 + self.send_data(self.height & 0xff) + + self.send_command(0xe5) # FLASH MODE + self.send_data(0x03) + + return 0 + + def getbuffer(self, image): + # logger.debug("bufsiz = ",int(self.width/8) * self.height) + buf = [0xFF] * (int(self.width/8) * self.height) + image_monocolor = image.convert('1') + imwidth, imheight = image_monocolor.size + pixels = image_monocolor.load() + logger.debug('imwidth = %d imheight = %d ',imwidth, imheight) + if(imwidth == self.width and imheight == self.height): + logger.debug("Horizontal") + for y in range(imheight): + for x in range(imwidth): + # Set the bits for the column of pixels at the current position. + if pixels[x, y] == 0: + buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) + elif(imwidth == self.height and imheight == self.width): + logger.debug("Vertical") + for y in range(imheight): + for x in range(imwidth): + newx = y + newy = self.height - x - 1 + if pixels[x, y] == 0: + buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) + return buf + + def display(self, imageblack, imagered): + self.send_command(0x10) + for i in range(0, int(self.width / 8 * self.height)): + temp1 = imageblack[i] + temp2 = imagered[i] + j = 0 + while (j < 8): + if ((temp2 & 0x80) == 0x00): + temp3 = 0x04 #red + elif ((temp1 & 0x80) == 0x00): + temp3 = 0x00 #black + else: + temp3 = 0x03 #white + + temp3 = (temp3 << 4) & 0xFF + temp1 = (temp1 << 1) & 0xFF + temp2 = (temp2 << 1) & 0xFF + j += 1 + if((temp2 & 0x80) == 0x00): + temp3 |= 0x04 #red + elif ((temp1 & 0x80) == 0x00): + temp3 |= 0x00 #black + else: + temp3 |= 0x03 #white + temp1 = (temp1 << 1) & 0xFF + temp2 = (temp2 << 1) & 0xFF + self.send_data(temp3) + j += 1 + + self.send_command(0x04) # POWER ON + self.ReadBusy() + self.send_command(0x12) # display refresh + epdconfig.delay_ms(100) + self.ReadBusy() + + def Clear(self): + self.send_command(0x10) + for i in range(0, int(self.width / 8 * self.height)): + self.send_data(0x33) + self.send_data(0x33) + self.send_data(0x33) + self.send_data(0x33) + + self.send_command(0x04) # POWER ON + self.ReadBusy() + self.send_command(0x12) # display refresh + epdconfig.delay_ms(100) + self.ReadBusy() + + def sleep(self): + self.send_command(0x02) # POWER_OFF + self.ReadBusy() + + self.send_command(0x07) # DEEP_SLEEP + self.send_data(0XA5) + + epdconfig.delay_ms(2000) + epdconfig.module_exit() +### END OF FILE ### + diff --git a/waveshare_epd/epdconfig.py b/waveshare_epd/epdconfig.py new file mode 100644 index 0000000..f4feff0 --- /dev/null +++ b/waveshare_epd/epdconfig.py @@ -0,0 +1,160 @@ +# /***************************************************************************** +# * | File : epdconfig.py +# * | Author : Waveshare team +# * | Function : Hardware underlying interface +# * | Info : +# *---------------- +# * | This version: V1.0 +# * | Date : 2019-06-21 +# * | Info : +# ****************************************************************************** +# 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 os +import logging +import sys +import time + +logger = logging.getLogger(__name__) + + +class RaspberryPi: + # Pin definition + RST_PIN = 17 + DC_PIN = 25 + CS_PIN = 8 + BUSY_PIN = 24 + + def __init__(self): + import spidev + import RPi.GPIO + + self.GPIO = RPi.GPIO + self.SPI = spidev.SpiDev() + + def digital_write(self, pin, value): + self.GPIO.output(pin, value) + + def digital_read(self, pin): + return self.GPIO.input(pin) + + def delay_ms(self, delaytime): + time.sleep(delaytime / 1000.0) + + def spi_writebyte(self, data): + self.SPI.writebytes(data) + + def spi_writebyte2(self, data): + self.SPI.writebytes2(data) + + def module_init(self): + self.GPIO.setmode(self.GPIO.BCM) + self.GPIO.setwarnings(False) + self.GPIO.setup(self.RST_PIN, self.GPIO.OUT) + self.GPIO.setup(self.DC_PIN, self.GPIO.OUT) + self.GPIO.setup(self.CS_PIN, self.GPIO.OUT) + self.GPIO.setup(self.BUSY_PIN, self.GPIO.IN) + + # SPI device, bus = 0, device = 0 + self.SPI.open(0, 0) + self.SPI.max_speed_hz = 4000000 + self.SPI.mode = 0b00 + return 0 + + def module_exit(self): + logger.debug("spi end") + self.SPI.close() + + logger.debug("close 5V, Module enters 0 power consumption ...") + self.GPIO.output(self.RST_PIN, 0) + self.GPIO.output(self.DC_PIN, 0) + + self.GPIO.cleanup([self.RST_PIN, self.DC_PIN, self.CS_PIN, self.BUSY_PIN]) + + +class JetsonNano: + # Pin definition + RST_PIN = 17 + DC_PIN = 25 + CS_PIN = 8 + BUSY_PIN = 24 + + def __init__(self): + import ctypes + find_dirs = [ + os.path.dirname(os.path.realpath(__file__)), + '/usr/local/lib', + '/usr/lib', + ] + self.SPI = None + for find_dir in find_dirs: + so_filename = os.path.join(find_dir, 'sysfs_software_spi.so') + if os.path.exists(so_filename): + self.SPI = ctypes.cdll.LoadLibrary(so_filename) + break + if self.SPI is None: + raise RuntimeError('Cannot find sysfs_software_spi.so') + + import Jetson.GPIO + self.GPIO = Jetson.GPIO + + def digital_write(self, pin, value): + self.GPIO.output(pin, value) + + def digital_read(self, pin): + return self.GPIO.input(self.BUSY_PIN) + + def delay_ms(self, delaytime): + time.sleep(delaytime / 1000.0) + + def spi_writebyte(self, data): + self.SPI.SYSFS_software_spi_transfer(data[0]) + + def module_init(self): + self.GPIO.setmode(self.GPIO.BCM) + self.GPIO.setwarnings(False) + self.GPIO.setup(self.RST_PIN, self.GPIO.OUT) + self.GPIO.setup(self.DC_PIN, self.GPIO.OUT) + self.GPIO.setup(self.CS_PIN, self.GPIO.OUT) + self.GPIO.setup(self.BUSY_PIN, self.GPIO.IN) + self.SPI.SYSFS_software_spi_begin() + return 0 + + def module_exit(self): + logger.debug("spi end") + self.SPI.SYSFS_software_spi_end() + + logger.debug("close 5V, Module enters 0 power consumption ...") + self.GPIO.output(self.RST_PIN, 0) + self.GPIO.output(self.DC_PIN, 0) + + self.GPIO.cleanup([self.RST_PIN, self.DC_PIN, self.CS_PIN, self.BUSY_PIN]) + + +if os.path.exists('/sys/bus/platform/drivers/gpiomem-bcm2835'): + implementation = RaspberryPi() +else: + implementation = JetsonNano() + +for func in [x for x in dir(implementation) if not x.startswith('_')]: + setattr(sys.modules[__name__], func, getattr(implementation, func)) + + +### END OF FILE ### diff --git a/waveshare_epd/sysfs_gpio.so b/waveshare_epd/sysfs_gpio.so new file mode 100644 index 0000000..b8d9cdd Binary files /dev/null and b/waveshare_epd/sysfs_gpio.so differ diff --git a/waveshare_epd/sysfs_software_spi.so b/waveshare_epd/sysfs_software_spi.so new file mode 100644 index 0000000..f9ff3a6 Binary files /dev/null and b/waveshare_epd/sysfs_software_spi.so differ diff --git a/webapp.py b/webapp.py new file mode 100644 index 0000000..0981f37 --- /dev/null +++ b/webapp.py @@ -0,0 +1,90 @@ +# webapp.py - Mark Harris +# for E-Paper display +# This will provide a web interface to control the e-Paper display. + +from flask import Flask, render_template, request, flash, redirect, url_for, send_file, Response +import os +import sys +from shutdown import * +from metar_settings import * + +app = Flask(__name__) +app.secret_key = b'_5#y2L"F4Q8z\n\xec]/' + +# variables +PATH = '/home/pi/metar/' +rem_data = "0" + +# Routes for flask +@app.route("/", methods=["GET", "POST"]) +@app.route("/index", methods=["GET", "POST"]) +@app.route("/metar", methods=["GET", "POST"]) +def epaper(): + data_field1, data_field2, data_field3, rem_data = airport, use_disp_format, interval, use_remarks + data_field1, data_field2, data_field3, rem_data = get_data() + + if request.method == "POST": + display = request.form['display'] + data_field1 = request.form['data_field1'] + data_field2 = request.form['data_field2'] + data_field3 = request.form['data_field3'] + rem_data = request.form['rem_data'] + + if display == "powerdown": + shutdown() + print("Powering Off RPi") + os.system('sudo shutdown -h now') + + elif display == "reboot": + os.system("ps -ef | grep 'metar_main.py' | awk '{print $2}' | xargs sudo kill") + os.system('sudo reboot now') + flash("Rebooting RPi - One Moment...") + + elif display == "off": + os.system("ps -ef | grep 'metar_main.py' | awk '{print $2}' | xargs sudo kill") + os.system('sudo python3 ' + PATH + 'shutdown.py &') + flash("Turning Off E-Paper Display - One Moment...") + + else: + os.system("ps -ef | grep 'metar_main.py' | awk '{print $2}' | xargs sudo kill") + os.system('sudo python3 ' + PATH + 'metar_main.py '+ data_field1+' '+data_field2+' '+data_field3+' '+rem_data+' &') + flash("Running E-Paper Metar Airport ID = " + data_field1) + if data_field2 != "": + flash("Display Layout = " + data_field2) + + print(data_field1) # debug + write_data(data_field1, data_field2, data_field3, rem_data) + return render_template("epaper.html", data_field1=data_field1, data_field2=data_field2, data_field3=data_field3, rem_data=rem_data) + else: + return render_template("epaper.html", data_field1=data_field1, data_field2=data_field2, data_field3=data_field3, rem_data=rem_data) + + +# Functions +def write_data(data_field1, data_field2, data_field3, rem_data): + f= open(PATH + "data.txt","w+") + f.write(data_field1+"\n") + f.write(data_field2+"\n") + f.write(data_field3+"\n") + f.write(rem_data+"\n") + f.close() + return (True) + +def get_data(): + f=open(PATH + "data.txt", "r") + Lines = f.readlines() + data_field1 = Lines[0].strip() + data_field2 = Lines[1].strip() + data_field3 = Lines[2].strip() + rem_data = Lines[3].strip() + f.close() + return (data_field1, data_field2, data_field3, rem_data) + + +# Start of Flask +if __name__ == '__main__': +# error = 1/0 # Force webapp to stop executing for debug purposes + data_field1, data_field2, data_field3, rem_data = get_data() # read what is in data.txt to get last run + + os.system('sudo python3 ' + PATH + 'metar_main.py ' + data_field1 + ' ' + data_field2 + ' ' + data_field3 + " " + rem_data + ' &') + app.run(debug=True, use_reloader=False, host='0.0.0.0') # use use_reloader=False to stop double loading + \ No newline at end of file