Skip to content

Commit ae58672

Browse files
authored
Merge pull request #99 from adafruit/uc8253
adding UC8253 driver
2 parents a454736 + 1624322 commit ae58672

File tree

1 file changed

+258
-0
lines changed

1 file changed

+258
-0
lines changed

adafruit_epd/uc8253.py

Lines changed: 258 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,258 @@
1+
# SPDX-FileCopyrightText: 2025 Liz Clark for Adafruit Industries
2+
#
3+
# SPDX-License-Identifier: MIT
4+
5+
"""
6+
`adafruit_epd.uc8253` - Adafruit UC8253 - ePaper display driver
7+
====================================================================================
8+
CircuitPython driver for Adafruit UC8253 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+
_UC8253_PANELSETTING = const(0x00)
34+
_UC8253_POWEROFF = const(0x02)
35+
_UC8253_POWERON = const(0x04)
36+
_UC8253_DEEPSLEEP = const(0x07)
37+
_UC8253_DISPLAYREFRESH = const(0x12)
38+
_UC8253_WRITE_RAM1 = const(0x10)
39+
_UC8253_WRITE_RAM2 = const(0x13)
40+
_UC8253_VCOM_CDI = const(0x50)
41+
_UC8253_GET_STATUS = const(0x71)
42+
43+
_BUSY_WAIT = const(500)
44+
45+
46+
class Adafruit_UC8253(Adafruit_EPD):
47+
"""Base driver class for Adafruit UC8253 ePaper display breakouts"""
48+
49+
def __init__(
50+
self,
51+
width: int,
52+
height: int,
53+
spi: SPI,
54+
*,
55+
cs_pin: DigitalInOut,
56+
dc_pin: DigitalInOut,
57+
sramcs_pin: DigitalInOut,
58+
rst_pin: DigitalInOut,
59+
busy_pin: DigitalInOut,
60+
) -> None:
61+
super().__init__(width, height, spi, cs_pin, dc_pin, sramcs_pin, rst_pin, busy_pin)
62+
63+
self._single_byte_tx = True
64+
65+
stride = height
66+
if stride % 8 != 0:
67+
stride += 8 - stride % 8
68+
69+
self._buffer1_size = int(width * stride / 8)
70+
self._buffer2_size = self._buffer1_size
71+
72+
if sramcs_pin:
73+
self._buffer1 = self.sram.get_view(0)
74+
self._buffer2 = self.sram.get_view(self._buffer1_size)
75+
else:
76+
self._buffer1 = bytearray(self._buffer1_size)
77+
self._buffer2 = bytearray(self._buffer2_size)
78+
79+
self._framebuf1 = adafruit_framebuf.FrameBuffer(
80+
self._buffer1,
81+
width,
82+
height,
83+
buf_format=adafruit_framebuf.MHMSB,
84+
)
85+
self._framebuf2 = adafruit_framebuf.FrameBuffer(
86+
self._buffer2,
87+
width,
88+
height,
89+
buf_format=adafruit_framebuf.MHMSB,
90+
)
91+
92+
self.set_black_buffer(0, True)
93+
self.set_color_buffer(1, False)
94+
95+
def begin(self, reset: bool = True) -> None:
96+
"""Begin communication with the display and set basic settings"""
97+
if reset:
98+
self.hardware_reset()
99+
self.power_up()
100+
self.power_down()
101+
102+
def busy_wait(self) -> None:
103+
"""Wait for display to be done with current task, either by polling the
104+
busy pin, or pausing"""
105+
if self._busy:
106+
while not self._busy.value: # UC8253 waits for busy HIGH
107+
self.command(_UC8253_GET_STATUS)
108+
time.sleep(0.05)
109+
else:
110+
time.sleep(_BUSY_WAIT / 1000.0) # Convert ms to seconds
111+
112+
def power_up(self) -> None:
113+
"""Power up the display in preparation for writing RAM and updating"""
114+
self.hardware_reset()
115+
# Default initialization sequence
116+
self.command(_UC8253_POWERON)
117+
self.busy_wait()
118+
# Panel settings with default values
119+
self.command(_UC8253_PANELSETTING, bytearray([0xCF, 0x8D]))
120+
self.busy_wait()
121+
122+
def power_down(self) -> None:
123+
"""Power down the display - required when not actively displaying!"""
124+
self.command(_UC8253_POWEROFF)
125+
self.busy_wait()
126+
time.sleep(1.0)
127+
128+
if self._rst:
129+
self.command(_UC8253_DEEPSLEEP, bytearray([0xA5]))
130+
131+
def update(self) -> None:
132+
"""Update the display from internal memory"""
133+
self.command(_UC8253_DISPLAYREFRESH)
134+
time.sleep(0.1)
135+
self.busy_wait()
136+
137+
if not self._busy:
138+
refresh_delay = getattr(self, "_refresh_delay", 1.0)
139+
time.sleep(refresh_delay)
140+
141+
def write_ram(self, index: Literal[0, 1]) -> int:
142+
"""Send the one byte command for starting the RAM write process. Returns
143+
the byte read at the same time over SPI. index is the RAM buffer, can be
144+
0 or 1 for tri-color displays."""
145+
if index == 0:
146+
return self.command(_UC8253_WRITE_RAM1, end=False)
147+
if index == 1:
148+
return self.command(_UC8253_WRITE_RAM2, end=False)
149+
raise RuntimeError("RAM index must be 0 or 1")
150+
151+
def set_ram_address(self, x: int, y: int) -> None:
152+
"""Set the RAM address location, not used on UC8253 but required by
153+
the superclass"""
154+
# UC8253 doesn't use RAM address setting
155+
pass
156+
157+
158+
class Adafruit_UC8253_Mono(Adafruit_UC8253):
159+
"""Driver for UC8253 monochrome ePaper displays (370 Mono BAAMFGN)"""
160+
161+
def __init__(
162+
self,
163+
width: int,
164+
height: int,
165+
spi: SPI,
166+
*,
167+
cs_pin: DigitalInOut,
168+
dc_pin: DigitalInOut,
169+
sramcs_pin: DigitalInOut,
170+
rst_pin: DigitalInOut,
171+
busy_pin: DigitalInOut,
172+
) -> None:
173+
super().__init__(
174+
width,
175+
height,
176+
spi,
177+
cs_pin=cs_pin,
178+
dc_pin=dc_pin,
179+
sramcs_pin=sramcs_pin,
180+
rst_pin=rst_pin,
181+
busy_pin=busy_pin,
182+
)
183+
# Set refresh delay for monochrome
184+
self._refresh_delay = 1.0 # 1000ms
185+
186+
def begin(self, reset: bool = True) -> None:
187+
"""Begin communication with the monochrome display"""
188+
if reset:
189+
self.hardware_reset()
190+
191+
self.set_color_buffer(1, True)
192+
self.set_black_buffer(1, True)
193+
194+
def power_up(self) -> None:
195+
"""Power up the monochrome display with specific initialization"""
196+
self.hardware_reset()
197+
198+
# Soft reset sequence
199+
self.command(_UC8253_POWERON)
200+
time.sleep(0.05) # 50ms busy wait
201+
202+
# VCOM CDI setting for monochrome
203+
self.command(_UC8253_VCOM_CDI, bytearray([0x97]))
204+
205+
# Panel settings for monochrome: 0b11011111 = 0xDF
206+
self.command(_UC8253_PANELSETTING, bytearray([0xDF, 0x8D]))
207+
208+
self.busy_wait()
209+
210+
211+
class Adafruit_UC8253_Tricolor(Adafruit_UC8253):
212+
"""Driver for UC8253 tricolor ePaper displays (370 Tricolor BABMFGNR)"""
213+
214+
def __init__(
215+
self,
216+
width: int,
217+
height: int,
218+
spi: SPI,
219+
*,
220+
cs_pin: DigitalInOut,
221+
dc_pin: DigitalInOut,
222+
sramcs_pin: DigitalInOut,
223+
rst_pin: DigitalInOut,
224+
busy_pin: DigitalInOut,
225+
) -> None:
226+
super().__init__(
227+
width,
228+
height,
229+
spi,
230+
cs_pin=cs_pin,
231+
dc_pin=dc_pin,
232+
sramcs_pin=sramcs_pin,
233+
rst_pin=rst_pin,
234+
busy_pin=busy_pin,
235+
)
236+
# Set refresh delay for tricolor
237+
self._refresh_delay = 13.0 # 13000ms
238+
239+
def begin(self, reset: bool = True) -> None:
240+
"""Begin communication with the tricolor display"""
241+
if reset:
242+
self.hardware_reset()
243+
244+
self.set_color_buffer(0, True) # Red/color buffer in RAM1, inverted
245+
self.set_black_buffer(1, False) # Black buffer in RAM2, not inverted
246+
247+
def power_up(self) -> None:
248+
"""Power up the tricolor display with specific initialization"""
249+
self.hardware_reset()
250+
251+
# Soft reset sequence
252+
self.command(_UC8253_POWERON)
253+
time.sleep(0.05) # 50ms busy wait
254+
255+
# Panel settings for tricolor: 0b11001111 = 0xCF
256+
self.command(_UC8253_PANELSETTING, bytearray([0xCF, 0x8D]))
257+
258+
self.busy_wait()

0 commit comments

Comments
 (0)