Skip to content

Commit a5024b7

Browse files
authored
Rework SSD1351 initialization (#201)
* Extra ignores (pytest_cache) * Update deps version * Rework SSD1351 initialization * Set width/height accordingly * Use bgr=True flag to indicate BGR rather than RGB color ordering * Revert formatting changes * Add init sequence test for 96x96 SSD1351 with BGR pixels
1 parent b99633d commit a5024b7

File tree

4 files changed

+75
-44
lines changed

4 files changed

+75
-44
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ htmlcov/
4040
.tox/
4141
.coverage
4242
.cache
43+
.pytest_cache
4344
nosetests.xml
4445
coverage.xml
4546

luma/oled/device.py

+26-43
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,8 @@ class ssd1351(device):
324324
:param framebuffer: Framebuffering strategy, currently values of
325325
``diff_to_previous`` or ``full_frame`` are only supported.
326326
:type framebuffer: str
327+
:param bgr: Set to ``True`` if device pixels are BGR order (rather than RGB).
328+
:type bgr: bool
327329
:param h_offset: horizontal offset (in pixels) of screen to device memory
328330
(default: 0)
329331
:type h_offset: int
@@ -334,16 +336,12 @@ class ssd1351(device):
334336
.. versionadded:: 2.3.0
335337
"""
336338
def __init__(self, serial_interface=None, width=128, height=128, rotate=0,
337-
framebuffer="diff_to_previous", h_offset=0, v_offset=0, **kwargs):
339+
framebuffer="diff_to_previous", h_offset=0, v_offset=0,
340+
bgr=False, **kwargs):
338341
super(ssd1351, self).__init__(luma.oled.const.common, serial_interface)
339342
self.capabilities(width, height, rotate, mode="RGB")
340343
self.framebuffer = getattr(luma.core.framebuffer, framebuffer)(self)
341344

342-
settings = {
343-
(128, 128): dict(width=0x7F, height=0x7F, displayoffset=0x00, startline=0x00, remap=0x00),
344-
(96, 96): dict(width=0x6F, height=0x5F, displayoffset=0x00, startline=0x00, remap=0x02)
345-
}.get((width, height))
346-
347345
if h_offset != 0 or v_offset != 0:
348346
def offset(bbox):
349347
left, top, right, bottom = bbox
@@ -352,46 +350,31 @@ def offset(bbox):
352350
else:
353351
self.apply_offsets = lambda bbox: bbox
354352

355-
if settings is None:
353+
if (width, height) not in [(96, 96), (128, 128)]:
356354
raise luma.core.error.DeviceDisplayModeError(
357355
"Unsupported display mode: {0} x {1}".format(width, height))
358356

359-
# Unlock IC MCU interface
360-
self.command(0xFD, 0x12)
361-
# Command A2,B1,B3,BB,BE,C1 accessible if in unlock state
362-
self.command(0xFD, 0xB1)
363-
# Display off
364-
self.command(0xAE)
365-
# Clock divider
366-
self.command(0xB3, 0xF1)
367-
# Mux ratio
368-
self.command(0xCA, 0x7F)
369-
# Set column address
370-
self.command(0x15, settings['displayoffset'], settings['width'])
371-
# Set row address
372-
self.command(0x75, settings['displayoffset'], settings['height'])
373-
# Segment remapping - Column address remapping or else everything is mirrored
374-
self.command(0xA0, 0x74 | settings['remap'])
375-
# Set Display start line
376-
self.command(0xA1, settings['startline'])
377-
# Set display offset
378-
self.command(0xA2, 0x00)
379-
# Set GPIO
380-
self.command(0xB5, 0x00)
381-
# Function select (internal - diode drop)
382-
self.command(0xAB, 0x01)
383-
# Precharge
384-
self.command(0xB1, 0x32)
385-
# Set segment low voltage
386-
self.command(0xB4, 0xA0, 0xB5, 0x55)
387-
# Set VcomH voltage
388-
self.command(0xBE, 0x05)
389-
# Contrast master
390-
self.command(0xC7, 0x0F)
391-
# Precharge2
392-
self.command(0xB6, 0x01)
393-
# Normal display
394-
self.command(0xA6)
357+
# RGB or BGR order
358+
order = 0x02 if bgr else 0x00
359+
360+
self.command(0xFD, 0x12) # Unlock IC MCU interface
361+
self.command(0xFD, 0xB1) # Command A2,B1,B3,BB,BE,C1 accessible if in unlock state
362+
self.command(0xAE) # Display off
363+
self.command(0xB3, 0xF1) # Clock divider
364+
self.command(0xCA, 0x7F) # Mux ratio
365+
self.command(0x15, 0x00, width - 1) # Set column address
366+
self.command(0x75, 0x00, height - 1) # Set row address
367+
self.command(0xA0, 0x74 | order) # Segment remapping
368+
self.command(0xA1, 0x00) # Set Display start line
369+
self.command(0xA2, 0x00) # Set display offset
370+
self.command(0xB5, 0x00) # Set GPIO
371+
self.command(0xAB, 0x01) # Function select (internal - diode drop)
372+
self.command(0xB1, 0x32) # Precharge
373+
self.command(0xB4, 0xA0, 0xB5, 0x55) # Set segment low voltage
374+
self.command(0xBE, 0x05) # Set VcomH voltage
375+
self.command(0xC7, 0x0F) # Contrast master
376+
self.command(0xB6, 0x01) # Precharge2
377+
self.command(0xA6) # Normal display
395378

396379
self.contrast(0xFF)
397380
self.clear()

setup.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ def find_version(*file_paths):
5757
namespace_packages=["luma"],
5858
packages=["luma.oled"],
5959
zip_safe=False,
60-
install_requires=["luma.core>=1.1.1"],
60+
install_requires=["luma.core>=1.6.0"],
6161
setup_requires=pytest_runner,
6262
tests_require=test_deps,
6363
extras_require={

tests/test_ssd1351.py

+47
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,53 @@ def command(*cmd):
5757
]
5858

5959

60+
def test_init_96x96_with_BGR():
61+
"""
62+
SSD1351 OLED with a 96 x 96 resolution and BGR pixels works correctly.
63+
"""
64+
recordings = []
65+
66+
def data(data):
67+
recordings.append({'data': data})
68+
69+
def command(*cmd):
70+
recordings.append({'command': list(cmd)})
71+
72+
serial.command.side_effect = command
73+
serial.data.side_effect = data
74+
75+
ssd1351(serial, width=96, height=96, bgr=True)
76+
77+
assert serial.data.called
78+
assert serial.command.called
79+
80+
assert recordings == [
81+
{'command': [253]}, {'data': [18]},
82+
{'command': [253]}, {'data': [177]},
83+
{'command': [174]},
84+
{'command': [179]}, {'data': [241]},
85+
{'command': [202]}, {'data': [127]},
86+
{'command': [21]}, {'data': [0, 95]},
87+
{'command': [117]}, {'data': [0, 95]},
88+
{'command': [160]}, {'data': [118]},
89+
{'command': [161]}, {'data': [0]},
90+
{'command': [162]}, {'data': [0]},
91+
{'command': [181]}, {'data': [0]},
92+
{'command': [171]}, {'data': [1]},
93+
{'command': [177]}, {'data': [50]},
94+
{'command': [180]}, {'data': [160, 181, 85]},
95+
{'command': [190]}, {'data': [5]},
96+
{'command': [199]}, {'data': [15]},
97+
{'command': [182]}, {'data': [1]},
98+
{'command': [166]},
99+
{'command': [193]}, {'data': [255, 255, 255]},
100+
{'command': [21]}, {'data': [0, 95]},
101+
{'command': [117]}, {'data': [0, 95]},
102+
{'command': [92]}, {'data': [0] * (96 * 96 * 2)},
103+
{'command': [175]}
104+
]
105+
106+
60107
def test_init_invalid_dimensions():
61108
"""
62109
SSD1351 OLED with an invalid resolution raises a

0 commit comments

Comments
 (0)