Skip to content

Commit 2b7fe36

Browse files
authored
Merge pull request #57 from adamcandy/add-page-addressing-mode
Add page addressing mode
2 parents fa4d599 + 6d77e07 commit 2b7fe36

File tree

1 file changed

+67
-24
lines changed

1 file changed

+67
-24
lines changed

adafruit_ssd1306.py

Lines changed: 67 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -48,20 +48,33 @@ class _SSD1306(framebuf.FrameBuffer):
4848
"""Base class for SSD1306 display driver"""
4949

5050
# pylint: disable-msg=too-many-arguments
51-
def __init__(self, buffer, width, height, *, external_vcc, reset):
51+
def __init__(self, buffer, width, height, *, external_vcc, reset, page_addressing):
5252
super().__init__(buffer, width, height)
5353
self.width = width
5454
self.height = height
5555
self.external_vcc = external_vcc
5656
# reset may be None if not needed
5757
self.reset_pin = reset
58+
self.page_addressing = page_addressing
5859
if self.reset_pin:
5960
self.reset_pin.switch_to_output(value=0)
6061
self.pages = self.height // 8
6162
# Note the subclass must initialize self.framebuf to a framebuffer.
6263
# This is necessary because the underlying data buffer is different
6364
# between I2C and SPI implementations (I2C needs an extra byte).
6465
self._power = False
66+
# Parameters for efficient Page Addressing Mode (typical of U8Glib libraries)
67+
# Important as not all screens appear to support Horizontal Addressing Mode
68+
if self.page_addressing:
69+
self.pagebuffer = bytearray(width + 1)
70+
self.pagebuffer[0] = 0x40 # Set first byte of data buffer to Co=0, D/C=1
71+
self.page_column_start = bytearray(2)
72+
self.page_column_start[0] = self.width % 32
73+
self.page_column_start[1] = 0x10 + self.width // 32
74+
else:
75+
self.pagebuffer = None
76+
self.page_column_start = None
77+
# Let's get moving!
6578
self.poweron()
6679
self.init_display()
6780

@@ -86,7 +99,9 @@ def init_display(self):
8699
SET_DISP | 0x00, # off
87100
# address setting
88101
SET_MEM_ADDR,
89-
0x00, # horizontal
102+
0x10 # Page Addressing Mode
103+
if self.page_addressing
104+
else 0x00, # Horizontal Addressing Mode
90105
# resolution and layout
91106
SET_DISP_START_LINE | 0x00,
92107
SET_SEG_REMAP | 0x01, # column addr 127 mapped to SEG0
@@ -105,7 +120,7 @@ def init_display(self):
105120
SET_PRECHARGE,
106121
0x22 if self.external_vcc else 0xF1,
107122
SET_VCOM_DESEL,
108-
0x30, # 0.83*Vcc
123+
0x30, # 0.83*Vcc # n.b. specs for ssd1306 64x32 oled screens imply this should be 0x40
109124
# display
110125
SET_CONTRAST,
111126
0xFF, # maximum
@@ -159,22 +174,23 @@ def poweron(self):
159174

160175
def show(self):
161176
"""Update the display"""
162-
xpos0 = 0
163-
xpos1 = self.width - 1
164-
if self.width == 64:
165-
# displays with width of 64 pixels are shifted by 32
166-
xpos0 += 32
167-
xpos1 += 32
168-
if self.width == 72:
169-
# displays with width of 72 pixels are shifted by 28
170-
xpos0 += 28
171-
xpos1 += 28
172-
self.write_cmd(SET_COL_ADDR)
173-
self.write_cmd(xpos0)
174-
self.write_cmd(xpos1)
175-
self.write_cmd(SET_PAGE_ADDR)
176-
self.write_cmd(0)
177-
self.write_cmd(self.pages - 1)
177+
if not self.page_addressing:
178+
xpos0 = 0
179+
xpos1 = self.width - 1
180+
if self.width == 64:
181+
# displays with width of 64 pixels are shifted by 32
182+
xpos0 += 32
183+
xpos1 += 32
184+
if self.width == 72:
185+
# displays with width of 72 pixels are shifted by 28
186+
xpos0 += 28
187+
xpos1 += 28
188+
self.write_cmd(SET_COL_ADDR)
189+
self.write_cmd(xpos0)
190+
self.write_cmd(xpos1)
191+
self.write_cmd(SET_PAGE_ADDR)
192+
self.write_cmd(0)
193+
self.write_cmd(self.pages - 1)
178194
self.write_framebuf()
179195

180196

@@ -191,10 +207,19 @@ class SSD1306_I2C(_SSD1306):
191207
"""
192208

193209
def __init__(
194-
self, width, height, i2c, *, addr=0x3C, external_vcc=False, reset=None
210+
self,
211+
width,
212+
height,
213+
i2c,
214+
*,
215+
addr=0x3C,
216+
external_vcc=False,
217+
reset=None,
218+
page_addressing=False
195219
):
196220
self.i2c_device = i2c_device.I2CDevice(i2c, addr)
197221
self.addr = addr
222+
self.page_addressing = page_addressing
198223
self.temp = bytearray(2)
199224
# Add an extra byte to the data buffer to hold an I2C data/command byte
200225
# to use hardware-compatible I2C transactions. A memoryview of the
@@ -209,10 +234,11 @@ def __init__(
209234
height,
210235
external_vcc=external_vcc,
211236
reset=reset,
237+
page_addressing=self.page_addressing,
212238
)
213239

214240
def write_cmd(self, cmd):
215-
"""Send a command to the SPI device"""
241+
"""Send a command to the I2C device"""
216242
self.temp[0] = 0x80 # Co=1, D/C#=0
217243
self.temp[1] = cmd
218244
with self.i2c_device:
@@ -221,8 +247,18 @@ def write_cmd(self, cmd):
221247
def write_framebuf(self):
222248
"""Blast out the frame buffer using a single I2C transaction to support
223249
hardware I2C interfaces."""
224-
with self.i2c_device:
225-
self.i2c_device.write(self.buffer)
250+
if self.page_addressing:
251+
for page in range(self.pages):
252+
self.write_cmd(0xB0 + page)
253+
self.write_cmd(self.page_column_start[0])
254+
self.write_cmd(self.page_column_start[1])
255+
self.pagebuffer[1:] = self.buffer[
256+
1 + self.width * page : 1 + self.width * (page + 1)
257+
]
258+
self.i2c_device.write(self.pagebuffer)
259+
else:
260+
with self.i2c_device:
261+
self.i2c_device.write(self.buffer)
226262

227263

228264
# pylint: disable-msg=too-many-arguments
@@ -252,8 +288,14 @@ def __init__(
252288
external_vcc=False,
253289
baudrate=8000000,
254290
polarity=0,
255-
phase=0
291+
phase=0,
292+
page_addressing=False
256293
):
294+
if page_addressing:
295+
raise NotImplementedError(
296+
"Page addressing mode with SPI has not yet been implemented."
297+
)
298+
257299
self.rate = 10 * 1024 * 1024
258300
dc.switch_to_output(value=0)
259301
self.spi_device = spi_device.SPIDevice(
@@ -267,6 +309,7 @@ def __init__(
267309
height,
268310
external_vcc=external_vcc,
269311
reset=reset,
312+
page_addressing=self.page_addressing,
270313
)
271314

272315
def write_cmd(self, cmd):

0 commit comments

Comments
 (0)