Skip to content

Add two more chipsets - SSD1675 and SSD1608 #10

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 6 commits into from
Apr 1, 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
34 changes: 18 additions & 16 deletions adafruit_epd/epd.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,24 +133,25 @@ def display(self): # pylint: disable=too-many-branches
self.spi_device.write(self._buf, end=3)
self.spi_device.unlock()

#first data byte from SRAM will be transfered in at the
#same time as the EPD command is transferred out
databyte = self.write_ram(1)
if self._buffer2_size != 0:
#first data byte from SRAM will be transfered in at the
#same time as the EPD command is transferred out
databyte = self.write_ram(1)

while not self.spi_device.try_lock():
pass
self._dc.value = True
while not self.spi_device.try_lock():
pass
self._dc.value = True

if self.sram:
for _ in range(self._buffer2_size):
databyte = self._spi_transfer(databyte)
self.sram.cs_pin.value = True
else:
for databyte in self._buffer2:
self._spi_transfer(databyte)
if self.sram:
for _ in range(self._buffer2_size):
databyte = self._spi_transfer(databyte)
self.sram.cs_pin.value = True
else:
for databyte in self._buffer2:
self._spi_transfer(databyte)

self._cs.value = True
self.spi_device.unlock()
self._cs.value = True
self.spi_device.unlock()
self.update()


Expand Down Expand Up @@ -305,7 +306,8 @@ def rotation(self):
@rotation.setter
def rotation(self, val):
self._framebuf1.rotation = val
self._framebuf2.rotation = val
if self._framebuf2:
self._framebuf2.rotation = val

def hline(self, x, y, width, color):
"""draw a horizontal line"""
Expand Down
159 changes: 159 additions & 0 deletions adafruit_epd/ssd1608.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
# 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.ssd1608` - Adafruit SSD1608 - ePaper display driver
====================================================================================
CircuitPython driver for Adafruit SSD1608 display breakouts
* Author(s): Dean Miller, Ladyada
"""

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

_SSD1608_DRIVER_CONTROL = const(0x01)
_SSD1608_GATE_VOLTAGE = const(0x03)
_SSD1608_SOURCE_VOLTAGE = const(0x04)
_SSD1608_DISPLAY_CONTROL = const(0x07)
_SSD1608_NON_OVERLAP = const(0x0B)
_SSD1608_BOOSTER_SOFT_START = const(0x0C)
_SSD1608_GATE_SCAN_START = const(0x0F)
_SSD1608_DEEP_SLEEP = const(0x10)
_SSD1608_DATA_MODE = const(0x11)
_SSD1608_SW_RESET = const(0x12)
_SSD1608_TEMP_WRITE = const(0x1A)
_SSD1608_TEMP_READ = const(0x1B)
_SSD1608_TEMP_CONTROL = const(0x1C)
_SSD1608_TEMP_LOAD = const(0x1D)
_SSD1608_MASTER_ACTIVATE = const(0x20)
_SSD1608_DISP_CTRL1 = const(0x21)
_SSD1608_DISP_CTRL2 = const(0x22)
_SSD1608_WRITE_RAM = const(0x24)
_SSD1608_READ_RAM = const(0x25)
_SSD1608_VCOM_SENSE = const(0x28)
_SSD1608_VCOM_DURATION = const(0x29)
_SSD1608_WRITE_VCOM = const(0x2C)
_SSD1608_READ_OTP = const(0x2D)
_SSD1608_WRITE_LUT = const(0x32)
_SSD1608_WRITE_DUMMY = const(0x3A)
_SSD1608_WRITE_GATELINE = const(0x3B)
_SSD1608_WRITE_BORDER = const(0x3C)
_SSD1608_SET_RAMXPOS = const(0x44)
_SSD1608_SET_RAMYPOS = const(0x45)
_SSD1608_SET_RAMXCOUNT = const(0x4E)
_SSD1608_SET_RAMYCOUNT = const(0x4F)
_SSD1608_NOP = const(0xFF)
_LUT_DATA = b'\x02\x02\x01\x11\x12\x12""fiiYX\x99\x99\x88\x00\x00\x00\x00\xf8\xb4\x13Q5QQ\x19\x01\x00' # pylint: disable=line-too-long

class Adafruit_SSD1608(Adafruit_EPD):
"""driver class for Adafruit SSD1608 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_SSD1608, self).__init__(width, height, spi, cs_pin, dc_pin,
sramcs_pin, rst_pin, busy_pin)

if height % 8 != 0:
height += (8 - height % 8)
self._height = height

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

if sramcs_pin:
self._buffer1 = self.sram.get_view(0)
else:
self._buffer1 = bytearray((width * height) // 8)
self._framebuf1 = adafruit_framebuf.FrameBuffer(self._buffer1, width, height,
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()
self.busy_wait()
self.command(_SSD1608_SW_RESET)
self.busy_wait()
# driver output control
self.command(_SSD1608_DRIVER_CONTROL,
bytearray([self._width-1, (self._width-1) >> 8, 0x00]))
# Set dummy line period
self.command(_SSD1608_WRITE_DUMMY, bytearray([0x1B]))
# Set gate line width
self.command(_SSD1608_WRITE_GATELINE, bytearray([0x0B]))
# Data entry sequence
self.command(_SSD1608_DATA_MODE, bytearray([0x03]))
# Set ram X start/end postion
self.command(_SSD1608_SET_RAMXPOS, bytearray([0x00, self._height//8 - 1]))
# Set ram Y start/end postion
self.command(_SSD1608_SET_RAMYPOS,
bytearray([0, 0, self._height - 1, (self._height - 1) >> 8]))
# Vcom Voltage
self.command(_SSD1608_WRITE_VCOM, bytearray([0x70]))
# LUT
self.command(_SSD1608_WRITE_LUT, _LUT_DATA)
self.busy_wait()

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

def update(self):
"""Update the display from internal memory"""
self.command(_SSD1608_DISP_CTRL2, bytearray([0xC7]))
self.command(_SSD1608_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(_SSD1608_WRITE_RAM, end=False)
raise RuntimeError("RAM index must be 0")

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"""
# Set RAM X address counter
self.command(_SSD1608_SET_RAMXCOUNT, bytearray([x]))
# Set RAM Y address counter
self.command(_SSD1608_SET_RAMYCOUNT, bytearray([y>>8, y]))
176 changes: 176 additions & 0 deletions adafruit_epd/ssd1675.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
# 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.ssd1675` - 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

_SSD1675_DRIVER_CONTROL = const(0x01)
_SSD1675_GATE_VOLTAGE = const(0x03)
_SSD1675_SOURCE_VOLTAGE = const(0x04)
_SSD1675_DEEP_SLEEP = const(0x10)
_SSD1675_DATA_MODE = const(0x11)
_SSD1675_SW_RESET = const(0x12)
_SSD1675_HV_READY = const(0x14)
_SSD1675_VCI_READY = const(0x15)
_SSD1675_TEMP_WRITE = const(0x1A)
_SSD1675_MASTER_ACTIVATE = const(0x20)
_SSD1675_DISP_CTRL1 = const(0x21)
_SSD1675_DISP_CTRL2 = const(0x22)
_SSD1675_WRITE_RAM1 = const(0x24)
_SSD1675_WRITE_RAM2 = const(0x26)
_SSD1675_WRITE_VCOM = const(0x2C)
_SSD1675_READ_OTP = const(0x2D)
_SSD1675_WRITE_LUT = const(0x32)
_SSD1675_WRITE_DUMMY = const(0x3A)
_SSD1675_WRITE_GATELINE = const(0x3B)
_SSD1675_WRITE_BORDER = const(0x3C)
_SSD1675_SET_RAMXPOS = const(0x44)
_SSD1675_SET_RAMYPOS = const(0x45)
_SSD1675_SET_RAMXCOUNT = const(0x4E)
_SSD1675_SET_RAMYCOUNT = const(0x4F)
_SSD1675_SET_ANALOGBLOCK = const(0x74)
_SSD1675_SET_DIGITALBLOCK = const(0x7E)
_LUT_DATA = b'\x80`@\x00\x00\x00\x00\x10` \x00\x00\x00\x00\x80`@\x00\x00\x00\x00\x10` \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x03\x00\x00\x02\t\t\x00\x00\x02\x03\x03\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x15A\xa820\n' # pylint: disable=line-too-long

class Adafruit_SSD1675(Adafruit_EPD):
"""driver class for Adafruit SSD1675 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_SSD1675, self).__init__(width, height, spi, cs_pin, dc_pin,
sramcs_pin, rst_pin, busy_pin)
if width % 8 != 0:
width += (8 - width % 8)

self._buffer1_size = int(width * 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,
buf_format=adafruit_framebuf.MHMSB)
self._framebuf2 = adafruit_framebuf.FrameBuffer(self._buffer2, width, height,
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(_SSD1675_SW_RESET)
self.busy_wait()

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

# driver output control
self.command(_SSD1675_DRIVER_CONTROL,
bytearray([0xFA, 0x01, 0x00]))
# Data entry sequence
self.command(_SSD1675_DATA_MODE, bytearray([0x03]))
# Set ram X start/end postion
self.command(_SSD1675_SET_RAMXPOS, bytearray([0x00, 0x0F]))
# Set ram Y start/end postion
self.command(_SSD1675_SET_RAMYPOS, bytearray([0, 0, 0xF9, 0]))
# Border color
self.command(_SSD1675_WRITE_BORDER, bytearray([0x03]))
# Vcom Voltage
self.command(_SSD1675_WRITE_VCOM, bytearray([0x70]))
# Set gate voltage
self.command(_SSD1675_GATE_VOLTAGE, _LUT_DATA[70:71])
# Set gate voltage
self.command(_SSD1675_SOURCE_VOLTAGE, _LUT_DATA[71:74])
# Set dummy line period
self.command(_SSD1675_WRITE_DUMMY, _LUT_DATA[74:75])
# Set gate line width
self.command(_SSD1675_WRITE_GATELINE, _LUT_DATA[75:76])
# LUT
self.command(_SSD1675_WRITE_LUT, _LUT_DATA[0:70])

self.command(_SSD1675_SET_RAMXCOUNT, bytearray([0]))
# Set RAM Y address counter
self.command(_SSD1675_SET_RAMYCOUNT, bytearray([0xF9, 0]))

self.busy_wait()

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

def update(self):
"""Update the display from internal memory"""
self.command(_SSD1675_DISP_CTRL2, bytearray([0xC7]))
self.command(_SSD1675_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(_SSD1675_WRITE_RAM1, end=False)
if index == 1:
return self.command(_SSD1675_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(_SSD1675_SET_RAMXCOUNT, bytearray([x]))
self.command(_SSD1675_SET_RAMYCOUNT, bytearray([y, y>>8]))
Loading