Skip to content

Move new SSD1680 driver variant to dedicated module and update examples #86

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

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
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
82 changes: 7 additions & 75 deletions adafruit_epd/ssd1680.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@
import adafruit_framebuf
from adafruit_epd.epd import Adafruit_EPD

# for backwards compatibility
from adafruit_epd.ssd1680b import ( # pylint: disable=unused-import
Adafruit_SSD1680B as Adafruit_SSD1680Z,
)

try:
"""Needed for type annotations"""
import typing # pylint: disable=unused-import
Expand Down Expand Up @@ -68,13 +73,14 @@
_SSD1680_OTP_PROGMODE = const(0x39)
_SSD1680_WRITE_BORDER = const(0x3C)
_SSD1680_END_OPTION = const(0x3F)
_SSD1680_READ_RAM_OPT = const(0x41)
_SSD1680_SET_RAMXPOS = const(0x44)
_SSD1680_SET_RAMYPOS = const(0x45)
_SSD1680_AUTOWRITE_RED = const(0x46)
_SSD1680_AUTOWRITE_BW = const(0x47)
_SSD1680_SET_RAMXCOUNT = const(0x4E)
_SSD1680_SET_RAMYCOUNT = const(0x4F)
_SSD1680_NOP = const(0xFF)
_SSD1680_NOP = const(0x7F)


class Adafruit_SSD1680(Adafruit_EPD):
Expand Down Expand Up @@ -211,77 +217,3 @@ def set_ram_address(
self.command(_SSD1680_SET_RAMXCOUNT, bytearray([x + 1]))
# Set RAM Y address counter
self.command(_SSD1680_SET_RAMYCOUNT, bytearray([y, y >> 8]))


class Adafruit_SSD1680Z(Adafruit_SSD1680):
"""Driver for SSD1680Z ePaper display, overriding SSD1680 settings."""

# pylint: disable=too-many-arguments, useless-parent-delegation
def __init__(
self, width, height, spi, *, cs_pin, dc_pin, sramcs_pin, rst_pin, busy_pin
):
# Call the parent class's __init__() to initialize attributes
super().__init__(
width,
height,
spi,
cs_pin=cs_pin,
dc_pin=dc_pin,
sramcs_pin=sramcs_pin,
rst_pin=rst_pin,
busy_pin=busy_pin,
)
self.busy_pin = busy_pin # Ensure busy_pin is set

# pylint: enable=too-many-arguments, useless-parent-delegation

def power_up(self):
"""Power up sequence specifically for SSD1680Z."""
self.hardware_reset()
self.busy_wait()
self.command(_SSD1680_SW_RESET)
self.busy_wait()

self.command(
_SSD1680_DRIVER_CONTROL,
bytearray([self._height, (self._height) >> 8, 0x00]),
)
self.command(_SSD1680_DATA_MODE, bytearray([0x03]))

# Set voltages
self.command(_SSD1680_WRITE_VCOM_REG, bytearray([0x36]))
self.command(_SSD1680_GATE_VOLTAGE, bytearray([0x17]))
self.command(_SSD1680_SOURCE_VOLTAGE, bytearray([0x41, 0x00, 0x32]))

self.command(_SSD1680_SET_RAMXPOS, bytearray([0x00, (self._width // 8)]))
self.command(
_SSD1680_SET_RAMYPOS,
bytearray([0x00, 0x00, self._height, (self._height) >> 8]),
)

# Set border waveform
self.command(_SSD1680_WRITE_BORDER, bytearray([0x05]))

# Set ram X count
self.command(_SSD1680_SET_RAMXCOUNT, bytearray([0x01]))
# Set ram Y count
self.command(_SSD1680_SET_RAMYCOUNT, bytearray([self._height, 0]))
self.busy_wait()

def update(self):
"""Update the display specifically for SSD1680Z."""
self.command(_SSD1680_DISP_CTRL2, bytearray([0xF7])) # Full update for SSD1680Z
self.command(_SSD1680_MASTER_ACTIVATE)
self.busy_wait()
if not self.busy_pin:
time.sleep(3) # Wait for update to complete

def set_ram_address(
self, x: int, y: int
) -> None: # 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(_SSD1680_SET_RAMXCOUNT, bytearray([x]))
# Set RAM Y address counter
self.command(_SSD1680_SET_RAMYCOUNT, bytearray([y, y >> 8]))
218 changes: 218 additions & 0 deletions adafruit_epd/ssd1680b.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
# SPDX-FileCopyrightText: 2018 Dean Miller for Adafruit Industries
# SPDX-FileCopyrightText: 2024 Joel Miller for Adafruit Industries
#
# SPDX-License-Identifier: MIT

"""
`adafruit_epd.ssd1680b` - Adafruit SSD1680B - ePaper display driver
====================================================================================
CircuitPython driver for Adafruit SSD1680B displays (GDEY0213B74 display module)
* Author(s): Melissa LeBlanc-Williams, Joel Miller, Mikey Sklar
"""

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

try:
"""Needed for type annotations"""
# pylint: disable=unused-import
import typing
from typing_extensions import Literal
from busio import SPI
from digitalio import DigitalInOut
except ImportError:
pass

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

_SSD1680B_DRIVER_CONTROL = const(0x01)
_SSD1680B_GATE_VOLTAGE = const(0x03)
_SSD1680B_SOURCE_VOLTAGE = const(0x04)
_SSD1680B_INIT_SETTING = const(0x08)
_SSD1680B_INIT_WRITE_REG = const(0x09)
_SSD1680B_INIT_READ_REG = const(0x0A)
_SSD1680B_BOOSTER_SOFT_START = const(0x0C)
_SSD1680B_DEEP_SLEEP = const(0x10)
_SSD1680B_DATA_MODE = const(0x11)
_SSD1680B_SW_RESET = const(0x12)
_SSD1680B_HV_DETECT = const(0x14)
_SSD1680B_VCI_DETECT = const(0x15)
_SSD1680B_TEMP_CONTROL = const(0x18)
_SSD1680B_TEMP_WRITE = const(0x1A)
_SSD1680B_TEMP_READ = const(0x1B)
_SSD1680B_EXTTEMP_WRITE = const(0x1C)
_SSD1680B_MASTER_ACTIVATE = const(0x20)
_SSD1680B_DISP_CTRL1 = const(0x21)
_SSD1680B_DISP_CTRL2 = const(0x22)
_SSD1680B_WRITE_BWRAM = const(0x24)
_SSD1680B_WRITE_REDRAM = const(0x26)
_SSD1680B_READ_RAM = const(0x27)
_SSD1680B_VCOM_SENSE = const(0x28)
_SSD1680B_VCOM_DURATION = const(0x29)
_SSD1680B_WRITE_VCOM_OTP = const(0x2A)
_SSD1680B_WRITE_VCOM_CTRL = const(0x2B)
_SSD1680B_WRITE_VCOM_REG = const(0x2C)
_SSD1680B_READ_OTP = const(0x2D)
_SSD1680B_READ_USERID = const(0x2E)
_SSD1680B_READ_STATUS = const(0x2F)
_SSD1680B_WRITE_WS_OTP = const(0x30)
_SSD1680B_LOAD_WS_OTP = const(0x31)
_SSD1680B_WRITE_LUT = const(0x32)
_SSD1680B_CRC_CALC = const(0x34)
_SSD1680B_CRC_READ = const(0x35)
_SSD1680B_PROG_OTP = const(0x36)
_SSD1680B_WRITE_DISPLAY_OPT = const(0x37)
_SSD1680B_WRITE_USERID = const(0x38)
_SSD1680B_OTP_PROGMODE = const(0x39)
_SSD1680B_WRITE_BORDER = const(0x3C)
_SSD1680B_END_OPTION = const(0x3F)
_SSD1680B_READ_RAM_OPT = const(0x41)
_SSD1680B_SET_RAMXPOS = const(0x44)
_SSD1680B_SET_RAMYPOS = const(0x45)
_SSD1680B_AUTOWRITE_RED = const(0x46)
_SSD1680B_AUTOWRITE_BW = const(0x47)
_SSD1680B_SET_RAMXCOUNT = const(0x4E)
_SSD1680B_SET_RAMYCOUNT = const(0x4F)
_SSD1680B_NOP = const(0x7F)


class Adafruit_SSD1680B(Adafruit_EPD):
"""
Driver class for Adafruit SSD1680 "B" ePaper displays. This class is meant
to be used with Adafruit boards equipped with an SSD1680 driver chip paired
with a GDEY0213B74 display module.
"""

def __init__(
self,
width: int,
height: int,
spi: SPI,
*,
cs_pin: DigitalInOut,
dc_pin: DigitalInOut,
sramcs_pin: DigitalInOut,
rst_pin: DigitalInOut,
busy_pin: DigitalInOut,
) -> None:
super().__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)

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(1, False)

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

def busy_wait(self) -> None:
"""
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) -> None:
"""Power up the display in preparation for writing RAM and updating"""
self.hardware_reset()
self.busy_wait()
self.command(_SSD1680B_SW_RESET)
self.busy_wait()
# driver output control
self.command(
_SSD1680B_DRIVER_CONTROL,
bytearray([self._height, self._height >> 8, 0x00]),
)
# data entry mode
self.command(_SSD1680B_DATA_MODE, bytearray([0x03]))

# Set voltages
self.command(_SSD1680B_WRITE_VCOM_REG, bytearray([0x36]))
self.command(_SSD1680B_GATE_VOLTAGE, bytearray([0x17]))
self.command(_SSD1680B_SOURCE_VOLTAGE, bytearray([0x41, 0x00, 0x32]))

# Set ram X start/end postion
self.command(_SSD1680B_SET_RAMXPOS, bytearray([0x00, self._width // 8]))
# Set ram Y start/end postion
self.command(
_SSD1680B_SET_RAMYPOS,
bytearray([0, 0, self._height, self._height >> 8]),
)
# Set border waveform
self.command(_SSD1680B_WRITE_BORDER, bytearray([0x05]))

# Set ram X count
self.command(_SSD1680B_SET_RAMXCOUNT, bytearray([0x01]))
# Set ram Y count
self.command(_SSD1680B_SET_RAMYCOUNT, bytearray([self._height, 0]))
self.busy_wait()

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

def update(self) -> None:
"""Update the display from internal memory"""
self.command(_SSD1680B_DISP_CTRL2, bytearray([0xF7]))
self.command(_SSD1680B_MASTER_ACTIVATE)
self.busy_wait()
if not self._busy:
time.sleep(3) # wait 3 seconds

def write_ram(self, index: Literal[0, 1]) -> int:
"""
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(_SSD1680B_WRITE_BWRAM, end=False)
if index == 1:
return self.command(_SSD1680B_WRITE_REDRAM, end=False)
raise RuntimeError("RAM index must be 0 or 1")

def set_ram_address(self, x: int, y: int) -> None:
"""Set the RAM address location"""
# Set RAM X address counter
self.command(_SSD1680B_SET_RAMXCOUNT, bytearray([x]))
# Set RAM Y address counter
self.command(_SSD1680B_SET_RAMYCOUNT, bytearray([y, y >> 8]))
2 changes: 2 additions & 0 deletions examples/epd_bitmap.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from adafruit_epd.ssd1608 import Adafruit_SSD1608 # pylint: disable=unused-import
from adafruit_epd.ssd1675 import Adafruit_SSD1675 # pylint: disable=unused-import
from adafruit_epd.ssd1680 import Adafruit_SSD1680 # pylint: disable=unused-import
from adafruit_epd.ssd1680b import Adafruit_SSD1680B # pylint: disable=unused-import
from adafruit_epd.ssd1681 import Adafruit_SSD1681 # pylint: disable=unused-import
from adafruit_epd.uc8151d import Adafruit_UC8151D # pylint: disable=unused-import
from adafruit_epd.ek79686 import Adafruit_EK79686 # pylint: disable=unused-import
Expand All @@ -29,6 +30,7 @@
# display = Adafruit_SSD1608(200, 200, # 1.54" HD mono display
# display = Adafruit_SSD1675(122, 250, # 2.13" HD mono display
# display = Adafruit_SSD1680(122, 250, # 2.13" HD Tri-color display
# display = Adafruit_SSD1680B(122, 250 # 2.13" HD (Tri-color or mono) with GDEY0213B74
# display = Adafruit_SSD1681(200, 200, # 1.54" HD Tri-color display
# display = Adafruit_IL91874(176, 264, # 2.7" Tri-color display
# display = Adafruit_EK79686(176, 264, # 2.7" Tri-color display
Expand Down
2 changes: 2 additions & 0 deletions examples/epd_blinka.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from adafruit_epd.ssd1675 import Adafruit_SSD1675 # pylint: disable=unused-import
from adafruit_epd.ssd1675b import Adafruit_SSD1675B # pylint: disable=unused-import
from adafruit_epd.ssd1680 import Adafruit_SSD1680 # pylint: disable=unused-import
from adafruit_epd.ssd1680b import Adafruit_SSD1680B # pylint: disable=unused-import
from adafruit_epd.ssd1681 import Adafruit_SSD1681 # pylint: disable=unused-import
from adafruit_epd.uc8151d import Adafruit_UC8151D # pylint: disable=unused-import
from adafruit_epd.ek79686 import Adafruit_EK79686 # pylint: disable=unused-import
Expand All @@ -36,6 +37,7 @@
print("Creating display")
# display = Adafruit_SSD1608(200, 200, # 1.54" HD mono display
# display = Adafruit_SSD1680(122, 250, # 2.13" HD Tri-color display
# display = Adafruit_SSD1680B(122, 250 # 2.13" HD (Tri-color or mono) with GDEY0213B74
# display = Adafruit_SSD1681(200, 200, # 1.54" HD Tri-color display
# display = Adafruit_SSD1675(122, 250, # 2.13" HD mono display
# display = Adafruit_IL91874(176, 264, # 2.7" Tri-color display
Expand Down
Binary file added examples/epd_bonnet_grid_250x122.bmp
Binary file not shown.
2 changes: 2 additions & 0 deletions examples/epd_bonnet_grid_250x122.bmp.license
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# SPDX-FileCopyrightText: 2024 Joel Miller for Adafruit Industries
# SPDX-License-Identifier: MIT
2 changes: 2 additions & 0 deletions examples/epd_pillow_demo.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from adafruit_epd.ssd1608 import Adafruit_SSD1608 # pylint: disable=unused-import
from adafruit_epd.ssd1675 import Adafruit_SSD1675 # pylint: disable=unused-import
from adafruit_epd.ssd1680 import Adafruit_SSD1680 # pylint: disable=unused-import
from adafruit_epd.ssd1680b import Adafruit_SSD1680B # pylint: disable=unused-import
from adafruit_epd.ssd1681 import Adafruit_SSD1681 # pylint: disable=unused-import
from adafruit_epd.uc8151d import Adafruit_UC8151D # pylint: disable=unused-import
from adafruit_epd.ek79686 import Adafruit_EK79686 # pylint: disable=unused-import
Expand Down Expand Up @@ -44,6 +45,7 @@
# display = Adafruit_SSD1608(200, 200, # 1.54" HD mono display
# display = Adafruit_SSD1675(122, 250, # 2.13" HD mono display
# display = Adafruit_SSD1680(122, 250, # 2.13" HD Tri-color or mono display
# display = Adafruit_SSD1680B(122, 250 # 2.13" HD (Tri-color or mono) with GDEY0213B74
# display = Adafruit_SSD1681(200, 200, # 1.54" HD Tri-color display
# display = Adafruit_IL91874(176, 264, # 2.7" Tri-color display
# display = Adafruit_EK79686(176, 264, # 2.7" Tri-color display
Expand Down
2 changes: 2 additions & 0 deletions examples/epd_pillow_image.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from adafruit_epd.ssd1608 import Adafruit_SSD1608 # pylint: disable=unused-import
from adafruit_epd.ssd1675 import Adafruit_SSD1675 # pylint: disable=unused-import
from adafruit_epd.ssd1680 import Adafruit_SSD1680 # pylint: disable=unused-import
from adafruit_epd.ssd1680b import Adafruit_SSD1680B # pylint: disable=unused-import
from adafruit_epd.ssd1681 import Adafruit_SSD1681 # pylint: disable=unused-import
from adafruit_epd.uc8151d import Adafruit_UC8151D # pylint: disable=unused-import
from adafruit_epd.ek79686 import Adafruit_EK79686 # pylint: disable=unused-import
Expand All @@ -35,6 +36,7 @@
# display = Adafruit_SSD1608(200, 200, # 1.54" HD mono display
# display = Adafruit_SSD1675(122, 250, # 2.13" HD mono display
# display = Adafruit_SSD1680(122, 250, # 2.13" HD Tri-color or mono display
# display = Adafruit_SSD1680B(122, 250 # 2.13" HD (Tri-color or mono) with GDEY0213B74
# display = Adafruit_SSD1681(200, 200, # 1.54" HD Tri-color display
# display = Adafruit_IL91874(176, 264, # 2.7" Tri-color display
# display = Adafruit_EK79686(176, 264, # 2.7" Tri-color display
Expand Down
Loading
Loading