Skip to content

Commit 6ba7fd3

Browse files
committed
add ssd1683
1 parent dc6bda8 commit 6ba7fd3

File tree

2 files changed

+266
-5
lines changed

2 files changed

+266
-5
lines changed

adafruit_epd/ssd1680.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@ def power_up(self):
242242

243243
self.command(
244244
_SSD1680_DRIVER_CONTROL,
245-
bytearray([self._height, (self._height) >> 8, 0x00]),
245+
bytearray([self._height & 0xFF, (self._height) >> 8, 0x00]),
246246
)
247247
self.command(_SSD1680_DATA_MODE, bytearray([0x03]))
248248

@@ -251,19 +251,19 @@ def power_up(self):
251251
self.command(_SSD1680_GATE_VOLTAGE, bytearray([0x17]))
252252
self.command(_SSD1680_SOURCE_VOLTAGE, bytearray([0x41, 0x00, 0x32]))
253253

254-
self.command(_SSD1680_SET_RAMXPOS, bytearray([0x00, (self._width // 8)]))
254+
self.command(_SSD1680_SET_RAMXPOS, bytearray([0x00, (self._width // 8) - 1]))
255255
self.command(
256256
_SSD1680_SET_RAMYPOS,
257-
bytearray([0x00, 0x00, self._height, (self._height) >> 8]),
257+
bytearray([0x00, 0x00, (self._height - 1) & 0xFF, (self._height - 1) >> 8]),
258258
)
259259

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

263263
# Set ram X count
264-
self.command(_SSD1680_SET_RAMXCOUNT, bytearray([0x01]))
264+
self.command(_SSD1680_SET_RAMXCOUNT, bytearray([0x00]))
265265
# Set ram Y count
266-
self.command(_SSD1680_SET_RAMYCOUNT, bytearray([self._height, 0]))
266+
self.command(_SSD1680_SET_RAMYCOUNT, bytearray([0x00, 0x00]))
267267
self.busy_wait()
268268

269269
def update(self):

adafruit_epd/ssd1683.py

Lines changed: 261 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,261 @@
1+
# SPDX-FileCopyrightText: 2025 Liz Clark for Adafruit Industries
2+
#
3+
# SPDX-License-Identifier: MIT
4+
5+
"""
6+
`adafruit_epd.ssd1683` - Adafruit SSD1683 - ePaper display driver
7+
====================================================================================
8+
CircuitPython driver for Adafruit SSD1683 display breakouts
9+
* Author(s): Liz Clark
10+
"""
11+
12+
import time
13+
14+
import adafruit_framebuf
15+
from micropython import const
16+
17+
from adafruit_epd.epd import Adafruit_EPD
18+
19+
try:
20+
"""Needed for type annotations"""
21+
import typing
22+
23+
from busio import SPI
24+
from digitalio import DigitalInOut
25+
from typing_extensions import Literal
26+
27+
except ImportError:
28+
pass
29+
30+
__version__ = "0.0.0+auto.0"
31+
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_EPD.git"
32+
33+
# Command constants
34+
_SSD1683_DRIVER_CONTROL = const(0x01)
35+
_SSD1683_GATE_VOLTAGE = const(0x03)
36+
_SSD1683_SOURCE_VOLTAGE = const(0x04)
37+
_SSD1683_PROGOTP_INITIAL = const(0x08)
38+
_SSD1683_PROGREG_INITIAL = const(0x09)
39+
_SSD1683_READREG_INITIAL = const(0x0A)
40+
_SSD1683_BOOST_SOFTSTART = const(0x0C)
41+
_SSD1683_DEEP_SLEEP = const(0x10)
42+
_SSD1683_DATA_MODE = const(0x11)
43+
_SSD1683_SW_RESET = const(0x12)
44+
_SSD1683_HV_READY = const(0x14)
45+
_SSD1683_VCI_DETECT = const(0x15)
46+
_SSD1683_PROGRAM_WSOTP = const(0x16)
47+
_SSD1683_PROGRAM_AUTO = const(0x17)
48+
_SSD1683_TEMP_CONTROL = const(0x18)
49+
_SSD1683_TEMP_WRITE = const(0x1A)
50+
_SSD1683_TEMP_READ = const(0x1B)
51+
_SSD1683_TEMP_CONTROLEXT = const(0x1C)
52+
_SSD1683_MASTER_ACTIVATE = const(0x20)
53+
_SSD1683_DISP_CTRL1 = const(0x21)
54+
_SSD1683_DISP_CTRL2 = const(0x22)
55+
_SSD1683_WRITE_RAM1 = const(0x24)
56+
_SSD1683_WRITE_RAM2 = const(0x26)
57+
_SSD1683_READ_RAM1 = const(0x27)
58+
_SSD1683_SENSE_VCOM = const(0x28)
59+
_SSD1683_SENSEDUR_VCOM = const(0x29)
60+
_SSD1683_PROGOTP_VCOM = const(0x2A)
61+
_SSD1683_WRITE_VCOM = const(0x2C)
62+
_SSD1683_READ_OTP = const(0x2D)
63+
_SSD1683_READ_USERID = const(0x2E)
64+
_SSD1683_READ_STATUS = const(0x2F)
65+
_SSD1683_WRITE_LUT = const(0x32)
66+
_SSD1683_WRITE_BORDER = const(0x3C)
67+
_SSD1683_END_OPTION = const(0x3F)
68+
_SSD1683_SET_RAMXPOS = const(0x44)
69+
_SSD1683_SET_RAMYPOS = const(0x45)
70+
_SSD1683_SET_RAMXCOUNT = const(0x4E)
71+
_SSD1683_SET_RAMYCOUNT = const(0x4F)
72+
73+
# Other constants
74+
_EPD_RAM_BW = const(0x10)
75+
_EPD_RAM_RED = const(0x13)
76+
_BUSY_WAIT = const(500)
77+
78+
79+
class Adafruit_SSD1683(Adafruit_EPD):
80+
"""driver class for Adafruit SSD1683 ePaper display breakouts"""
81+
82+
def __init__(
83+
self,
84+
width: int,
85+
height: int,
86+
spi: SPI,
87+
*,
88+
cs_pin: DigitalInOut,
89+
dc_pin: DigitalInOut,
90+
sramcs_pin: DigitalInOut,
91+
rst_pin: DigitalInOut,
92+
busy_pin: DigitalInOut,
93+
) -> None:
94+
super().__init__(width, height, spi, cs_pin, dc_pin, sramcs_pin, rst_pin, busy_pin)
95+
96+
stride = width
97+
if stride % 8 != 0:
98+
stride += 8 - stride % 8
99+
100+
self._buffer1_size = int(stride * height / 8)
101+
self._buffer2_size = self._buffer1_size
102+
103+
if sramcs_pin:
104+
self._buffer1 = self.sram.get_view(0)
105+
self._buffer2 = self.sram.get_view(self._buffer1_size)
106+
else:
107+
self._buffer1 = bytearray(self._buffer1_size)
108+
self._buffer2 = bytearray(self._buffer2_size)
109+
110+
self._framebuf1 = adafruit_framebuf.FrameBuffer(
111+
self._buffer1, width, height, buf_format=adafruit_framebuf.MHMSB
112+
)
113+
self._framebuf2 = adafruit_framebuf.FrameBuffer(
114+
self._buffer2, width, height, buf_format=adafruit_framebuf.MHMSB
115+
)
116+
self.set_black_buffer(0, True)
117+
self.set_color_buffer(1, False)
118+
119+
# Set single byte transactions flag
120+
self._single_byte_tx = True
121+
122+
# Set the display update value
123+
self._display_update_val = 0xF7
124+
125+
# Default initialization sequence (tri-color mode)
126+
self._default_init_code = bytes([
127+
_SSD1683_SW_RESET, 0, # Software reset
128+
0xFF, 50, # Wait for busy (50ms delay)
129+
130+
_SSD1683_WRITE_BORDER, 1, # Border waveform control
131+
0x05, # Border color/waveform
132+
133+
_SSD1683_TEMP_CONTROL, 1, # Temperature control
134+
0x80, # Read temp
135+
136+
_SSD1683_DATA_MODE, 1, # Data entry mode
137+
0x03, # Y decrement, X increment
138+
139+
0xFE # End of initialization
140+
])
141+
142+
def begin(self, reset: bool = True) -> None:
143+
"""Begin communication with the display and set basic settings"""
144+
if reset:
145+
self.hardware_reset()
146+
self.power_down()
147+
148+
def busy_wait(self) -> None:
149+
"""Wait for display to be done with current task, either by polling the
150+
busy pin, or pausing"""
151+
if self._busy:
152+
while self._busy.value: # wait for busy low
153+
time.sleep(0.01)
154+
else:
155+
time.sleep(_BUSY_WAIT / 1000.0) # Convert ms to seconds
156+
157+
def power_up(self) -> None:
158+
"""Power up the display in preparation for writing RAM and updating"""
159+
self.hardware_reset()
160+
time.sleep(0.1)
161+
self.busy_wait()
162+
163+
# Use custom init code if provided, otherwise use default
164+
init_code = self._default_init_code
165+
if hasattr(self, '_epd_init_code') and self._epd_init_code is not None:
166+
init_code = self._epd_init_code
167+
168+
# Send initialization sequence
169+
self._send_command_list(init_code)
170+
171+
# Set RAM window
172+
self.set_ram_window(0, 0, (self._width // 8) - 1, self._height - 1)
173+
174+
# Set RAM address to start position
175+
self.set_ram_address(0, 0)
176+
177+
# Set LUT if we have one
178+
if hasattr(self, '_epd_lut_code') and self._epd_lut_code:
179+
self._send_command_list(self._epd_lut_code)
180+
181+
# Set display size and driver output control
182+
_b0 = (self._height - 1) & 0xFF
183+
_b1 = ((self._height - 1) >> 8) & 0xFF
184+
_b2 = 0x00
185+
self.command(_SSD1683_DRIVER_CONTROL, bytearray([_b0, _b1, _b2]))
186+
187+
def power_down(self) -> None:
188+
"""Power down the display - required when not actively displaying!"""
189+
# Only deep sleep if we can get out of it
190+
if self._rst:
191+
# deep sleep
192+
self.command(_SSD1683_DEEP_SLEEP, bytearray([0x01]))
193+
time.sleep(0.1)
194+
else:
195+
self.command(_SSD1683_SW_RESET)
196+
self.busy_wait()
197+
198+
def update(self) -> None:
199+
"""Update the display from internal memory"""
200+
# display update sequence
201+
self.command(_SSD1683_DISP_CTRL2, bytearray([self._display_update_val]))
202+
self.command(_SSD1683_MASTER_ACTIVATE)
203+
self.busy_wait()
204+
205+
if not self._busy:
206+
time.sleep(1) # wait 1 second
207+
208+
def write_ram(self, index: Literal[0, 1]) -> int:
209+
"""Send the one byte command for starting the RAM write process. Returns
210+
the byte read at the same time over SPI. index is the RAM buffer, can be
211+
0 or 1 for tri-color displays."""
212+
if index == 0:
213+
return self.command(_SSD1683_WRITE_RAM1, end=False)
214+
if index == 1:
215+
return self.command(_SSD1683_WRITE_RAM2, end=False)
216+
raise RuntimeError("RAM index must be 0 or 1")
217+
218+
def set_ram_address(self, x: int, y: int) -> None:
219+
"""Set the RAM address location"""
220+
# set RAM x address count
221+
self.command(_SSD1683_SET_RAMXCOUNT, bytearray([x & 0xFF]))
222+
223+
# set RAM y address count
224+
self.command(_SSD1683_SET_RAMYCOUNT, bytearray([y & 0xFF, (y >> 8) & 0xFF]))
225+
226+
def set_ram_window(self, x1: int, y1: int, x2: int, y2: int) -> None:
227+
"""Set the RAM window for partial updates"""
228+
# Set ram X start/end position
229+
self.command(_SSD1683_SET_RAMXPOS, bytearray([x1 & 0xFF, x2 & 0xFF]))
230+
231+
# Set ram Y start/end position
232+
self.command(_SSD1683_SET_RAMYPOS, bytearray([
233+
y1 & 0xFF, (y1 >> 8) & 0xFF,
234+
y2 & 0xFF, (y2 >> 8) & 0xFF
235+
]))
236+
237+
def _send_command_list(self, init_sequence: bytes) -> None:
238+
"""Send a sequence of commands from an initialization list"""
239+
i = 0
240+
while i < len(init_sequence):
241+
cmd = init_sequence[i]
242+
i += 1
243+
244+
if cmd == 0xFE: # End marker
245+
break
246+
elif cmd == 0xFF: # Delay marker
247+
if i < len(init_sequence):
248+
delay_ms = init_sequence[i]
249+
i += 1
250+
time.sleep(delay_ms / 1000.0)
251+
else:
252+
# Regular command
253+
if i < len(init_sequence):
254+
num_args = init_sequence[i]
255+
i += 1
256+
if num_args > 0 and (i + num_args) <= len(init_sequence):
257+
args = init_sequence[i:i + num_args]
258+
self.command(cmd, bytearray(args))
259+
i += num_args
260+
else:
261+
self.command(cmd)

0 commit comments

Comments
 (0)