Skip to content

add two more eink displays, fix linux support #28

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 19 commits into from
Oct 8, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 12 additions & 17 deletions adafruit_epd/epd.py
Original file line number Diff line number Diff line change
Expand Up @@ -340,24 +340,19 @@ def image(self, image):
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))
if self.sram:
raise RuntimeError("PIL image is not for use with SRAM assist")
# Grab all the pixels from the image, faster than getpixel.
pix = image.load()
# clear out any display buffers
self.fill(Adafruit_EPD.WHITE)

for y in iter(range(image.size[1])):
for x in iter(range(image.size[0])):
if x == 0:
x = 1
for y in range(image.size[1]):
for x in range(image.size[0]):
pixel = pix[x, y]

addr = int(((self._width - x) * self._height + y)/8)

if pixel == (0xFF, 0, 0):
addr = addr + self._buffer1_size
current = self.sram.read8(addr)

if pixel in ((0xFF, 0, 0), (0, 0, 0)):
current = current & ~(1 << (7 - y%8))
else:
current = current | (1 << (7 - y%8))

self.sram.write8(addr, current)
if (pixel[0] >= 0x80) and (pixel[1] < 0x80) and (pixel[2] < 0x80):
# reddish
self.pixel(x, y, Adafruit_EPD.RED)
elif (pixel[0] < 0x80) and (pixel[1] < 0x80) and (pixel[2] < 0x80):
# dark
self.pixel(x, y, Adafruit_EPD.BLACK)
11 changes: 6 additions & 5 deletions adafruit_epd/ssd1675.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,11 @@ class Adafruit_SSD1675(Adafruit_EPD):
def __init__(self, width, height, spi, *, cs_pin, dc_pin, sramcs_pin, rst_pin, busy_pin):
super(Adafruit_SSD1675, self).__init__(width, height, spi, cs_pin, dc_pin,
sramcs_pin, rst_pin, busy_pin)
if width % 8 != 0:
width += (8 - width % 8)
stride = width
if stride % 8 != 0:
stride += (8 - stride % 8)

self._buffer1_size = int(width * height / 8)
self._buffer1_size = int(stride * height / 8)
self._buffer2_size = self._buffer1_size

if sramcs_pin:
Expand All @@ -82,9 +83,9 @@ def __init__(self, width, height, spi, *, cs_pin, dc_pin, sramcs_pin, rst_pin, b
self._buffer2 = bytearray(self._buffer2_size)
# since we have *two* framebuffers - one for red and one for black
# we dont subclass but manage manually
self._framebuf1 = adafruit_framebuf.FrameBuffer(self._buffer1, width, height,
self._framebuf1 = adafruit_framebuf.FrameBuffer(self._buffer1, width, height, stride=stride,
buf_format=adafruit_framebuf.MHMSB)
self._framebuf2 = adafruit_framebuf.FrameBuffer(self._buffer2, width, height,
self._framebuf2 = adafruit_framebuf.FrameBuffer(self._buffer2, width, height, stride=stride,
buf_format=adafruit_framebuf.MHMSB)
self.set_black_buffer(0, True)
self.set_color_buffer(0, True)
Expand Down
214 changes: 214 additions & 0 deletions adafruit_epd/ssd1675b.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
# The MIT License (MIT)
#
# Copyright (c) 2018 Dean Miller for Adafruit Industries
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation 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
# furnished 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 FOR 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.
"""
`adafruit_epd.ssd1675b` - Adafruit SSD1675 - ePaper display driver
====================================================================================
CircuitPython driver for Adafruit SSD1675 display breakouts
* Author(s): Dean Miller, Ladyada
"""

import time
from micropython import const
import adafruit_framebuf
from adafruit_epd.epd import Adafruit_EPD

__version__ = "0.0.0-auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_EPD.git"

_SSD1675B_DRIVER_CONTROL = const(0x01)
_SSD1675B_GATE_VOLTAGE = const(0x03)
_SSD1675B_SOURCE_VOLTAGE = const(0x04)
_SSD1675B_INIT_SETTING = const(0x08)
_SSD1675B_INIT_WRITE_REG = const(0x09)
_SSD1675B_INIT_READ_REG = const(0x0A)
_SSD1675B_BOOSTER_SOFT_START = const(0x0C)
_SSD1675B_GATESCAN_START = const(0x0F)
_SSD1675B_DEEP_SLEEP = const(0x10)
_SSD1675B_DATA_MODE = const(0x11)
_SSD1675B_SW_RESET = const(0x12)
_SSD1675B_HV_READY = const(0x14)
_SSD1675B_VCI_READY = const(0x15)
_SSD1675B_TEMP_CONTROL = const(0x18)
_SSD1675B_TEMP_WRITE = const(0x1A)
_SSD1675B_TEMP_READ = const(0x1B)
_SSD1675B_EXTTEMP_WRITE = const(0x1C)
_SSD1675B_MASTER_ACTIVATE = const(0x20)
_SSD1675B_DISP_CTRL1 = const(0x21)
_SSD1675B_DISP_CTRL2 = const(0x22)
_SSD1675B_WRITE_RAM1 = const(0x24)
_SSD1675B_WRITE_RAM2 = const(0x26)
_SSD1675B_READ_RAM = const(0x27)
_SSD1675B_VCOM_SENSE = const(0x28)
_SSD1675B_VCOM_DURATION = const(0x29)
_SSD1675B_WRITE_VCOM_OTP = const(0x2A)
_SSD1675B_WRITE_VCOM_CTRL = const(0x2B)
_SSD1675B_WRITE_VCOM_REG = const(0x2C)
_SSD1675B_READ_OTP = const(0x2D)
_SSD1675B_READ_USERID = const(0x2E)
_SSD1675B_READ_STATUS = const(0x2F)
_SSD1675B_WRITE_WS_OTP = const(0x30)
_SSD1675B_LOAD_WS_OTP = const(0x31)
_SSD1675B_WRITE_LUT = const(0x32)
_SSD1675B_CRC_CALC = const(0x34)
_SSD1675B_CRC_READ = const(0x35)
_SSD1675B_PROG_OTP = const(0x36)
_SSD1675B_WRITE_DISPLAY_OPT = const(0x37)
_SSD1675B_WRITE_USERID = const(0x38)
_SSD1675B_OTP_PROGMODE = const(0x39)
_SSD1675B_WRITE_DUMMY = const(0x3A)
_SSD1675B_WRITE_GATELINE = const(0x3B)
_SSD1675B_WRITE_BORDER = const(0x3C)
_SSD1675B_SET_RAMXPOS = const(0x44)
_SSD1675B_SET_RAMYPOS = const(0x45)
_SSD1675B_AUTOWRITE_RED = const(0x46)
_SSD1675B_AUTOWRITE_BW = const(0x47)
_SSD1675B_SET_RAMXCOUNT = const(0x4E)
_SSD1675B_SET_RAMYCOUNT = const(0x4F)
_SSD1675B_SET_ANALOGBLOCK = const(0x74)
_SSD1675B_SET_DIGITALBLOCK = const(0x7E)
_SSD1675B_NOP = const(0xFF)
_LUT_DATA = b'\xa0\x90P\x00\x00\x00\x00\x00\x00\x00P\x90\xa0\x00\x00\x00\x00\x00\x00\x00\xa0\x90P\x00\x00\x00\x00\x00\x00\x00P\x90\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0f\x0f\x00\x00\x00\x0f\x0f\x00\x00\x03\x0f\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x15A\xa82P,\x0b' # pylint: disable=line-too-long

class Adafruit_SSD1675B(Adafruit_EPD):
"""driver class for Adafruit SSD1675B ePaper display breakouts"""
# pylint: disable=too-many-arguments
def __init__(self, width, height, spi, *, cs_pin, dc_pin, sramcs_pin, rst_pin, busy_pin):
super(Adafruit_SSD1675B, self).__init__(width, height, spi, cs_pin, dc_pin,
sramcs_pin, rst_pin, busy_pin)
stride = width
if stride % 8 != 0:
stride += (8 - stride % 8)

self._buffer1_size = int(stride * height / 8)
self._buffer2_size = self._buffer1_size

if sramcs_pin:
self._buffer1 = self.sram.get_view(0)
self._buffer2 = self.sram.get_view(self._buffer1_size)
else:
self._buffer1 = bytearray(self._buffer1_size)
self._buffer2 = bytearray(self._buffer2_size)
# since we have *two* framebuffers - one for red and one for black
# we dont subclass but manage manually
self._framebuf1 = adafruit_framebuf.FrameBuffer(self._buffer1, width, height, stride=stride,
buf_format=adafruit_framebuf.MHMSB)
self._framebuf2 = adafruit_framebuf.FrameBuffer(self._buffer2, width, height, stride=stride,
buf_format=adafruit_framebuf.MHMSB)
self.set_black_buffer(0, True)
self.set_color_buffer(0, True)
# pylint: enable=too-many-arguments

def begin(self, reset=True):
"""Begin communication with the display and set basic settings"""
if reset:
self.hardware_reset()
self.power_down()

def busy_wait(self):
"""Wait for display to be done with current task, either by polling the
busy pin, or pausing"""
if self._busy:
while self._busy.value:
time.sleep(0.01)
else:
time.sleep(0.5)

def power_up(self):
"""Power up the display in preparation for writing RAM and updating"""
self.hardware_reset()
time.sleep(0.1)
self.busy_wait()

self.command(_SSD1675B_SW_RESET)
self.busy_wait()

# set analog block control
self.command(_SSD1675B_SET_ANALOGBLOCK, bytearray([0x54]))
# set digital block control
self.command(_SSD1675B_SET_DIGITALBLOCK, bytearray([0x3B]))

self.command(_SSD1675B_DRIVER_CONTROL,
bytearray([self._height-1, (self._height-1) >> 8, 0x00]))

# Data entry sequence
self.command(_SSD1675B_DATA_MODE, bytearray([0x03]))

# Set ram X start/end postion
self.command(_SSD1675B_SET_RAMXPOS, bytearray([0x00, self._width // 8]))
# Set ram Y start/end postion
self.command(_SSD1675B_SET_RAMYPOS,
bytearray([0x0, 0x0, self._height-1, (self._height-1) >> 8]))

# Border color
self.command(_SSD1675B_WRITE_BORDER, bytearray([0x03]))

# Vcom Voltage
self.command(_SSD1675B_WRITE_VCOM_REG, bytearray([0x50]))
# Set gate voltage
self.command(_SSD1675B_GATE_VOLTAGE, _LUT_DATA[100:101])
# Set source voltage
self.command(_SSD1675B_SOURCE_VOLTAGE, _LUT_DATA[101:104])
# Set dummy line period
self.command(_SSD1675B_WRITE_DUMMY, _LUT_DATA[105:106])
# Set gate line width
self.command(_SSD1675B_WRITE_GATELINE, _LUT_DATA[106:107])
# LUT
self.command(_SSD1675B_WRITE_LUT, _LUT_DATA[0:100])

# Set temperature control
#self.command(_SSD1675B_TEMP_CONTROL, bytearray([0x80]))

# Set RAM X address counter
self.command(_SSD1675B_SET_RAMXCOUNT, bytearray([0]))
# Set RAM Y address counter
self.command(_SSD1675B_SET_RAMYCOUNT, bytearray([self._height-1, (self._height-1) >> 8]))

self.busy_wait()

def power_down(self):
"""Power down the display - required when not actively displaying!"""
self.command(_SSD1675B_DEEP_SLEEP, bytearray([0x01]))
time.sleep(0.1)

def update(self):
"""Update the display from internal memory"""
self.command(_SSD1675B_DISP_CTRL2, bytearray([0xC7]))
self.command(_SSD1675B_MASTER_ACTIVATE)
self.busy_wait()
if not self._busy:
time.sleep(3) # wait 3 seconds

def write_ram(self, index):
"""Send the one byte command for starting the RAM write process. Returns
the byte read at the same time over SPI. index is the RAM buffer, can be
0 or 1 for tri-color displays."""
if index == 0:
return self.command(_SSD1675B_WRITE_RAM1, end=False)
if index == 1:
return self.command(_SSD1675B_WRITE_RAM2, end=False)
raise RuntimeError("RAM index must be 0 or 1")

def set_ram_address(self, x, y): # pylint: disable=unused-argument, no-self-use
"""Set the RAM address location, not used on this chipset but required by
the superclass"""
self.command(_SSD1675B_SET_RAMXCOUNT, bytearray([x]))
self.command(_SSD1675B_SET_RAMYCOUNT, bytearray([y, y>>8]))
Loading