From e7f2b219192be823a9acbb30f5d72477691e6944 Mon Sep 17 00:00:00 2001 From: Adam Candy Date: Sat, 20 Feb 2021 15:14:36 +0100 Subject: [PATCH 1/6] Support for Page Addressing Mode since not all screens appear to support Horizontal Addressing Mode --- adafruit_ssd1306.py | 73 ++++++++++++++++++++++++++++++--------------- 1 file changed, 49 insertions(+), 24 deletions(-) diff --git a/adafruit_ssd1306.py b/adafruit_ssd1306.py index e448321..72233a8 100644 --- a/adafruit_ssd1306.py +++ b/adafruit_ssd1306.py @@ -48,13 +48,14 @@ class _SSD1306(framebuf.FrameBuffer): """Base class for SSD1306 display driver""" # pylint: disable-msg=too-many-arguments - def __init__(self, buffer, width, height, *, external_vcc, reset): + def __init__(self, buffer, width, height, *, external_vcc, reset, page_addressing): super().__init__(buffer, width, height) self.width = width self.height = height self.external_vcc = external_vcc # reset may be None if not needed self.reset_pin = reset + self.page_addressing = page_addressing if self.reset_pin: self.reset_pin.switch_to_output(value=0) self.pages = self.height // 8 @@ -62,6 +63,18 @@ def __init__(self, buffer, width, height, *, external_vcc, reset): # This is necessary because the underlying data buffer is different # between I2C and SPI implementations (I2C needs an extra byte). self._power = False + # Parameters for efficient Page Addressing Mode (typical of U8Glib libraries) + # Important as not all screens appear to support Horizontal Addressing Mode + if self.page_addressing: + self.pagebuffer = bytearray(width + 1) + self.pagebuffer[0] = 0x40 # Set first byte of data buffer to Co=0, D/C=1 + self.page_column_start = bytearray(2) + self.page_column_start[0] = self.width % 32 + self.page_column_start[1] = 0x10 + self.width // 32 + else: + self.pagebuffer = None + self.page_column_start = None + # Let's get moving! self.poweron() self.init_display() @@ -86,7 +99,9 @@ def init_display(self): SET_DISP | 0x00, # off # address setting SET_MEM_ADDR, - 0x00, # horizontal + 0x10 # Page Addressing Mode + if self.page_addressing + else 0x00, # Horizontal Addressing Mode # resolution and layout SET_DISP_START_LINE | 0x00, SET_SEG_REMAP | 0x01, # column addr 127 mapped to SEG0 @@ -105,7 +120,7 @@ def init_display(self): SET_PRECHARGE, 0x22 if self.external_vcc else 0xF1, SET_VCOM_DESEL, - 0x30, # 0.83*Vcc + 0x30, # 0.83*Vcc # n.b. specs for ssd1306 64x32 oled screens imply this should be 0x40 # display SET_CONTRAST, 0xFF, # maximum @@ -159,22 +174,23 @@ def poweron(self): def show(self): """Update the display""" - xpos0 = 0 - xpos1 = self.width - 1 - if self.width == 64: - # displays with width of 64 pixels are shifted by 32 - xpos0 += 32 - xpos1 += 32 - if self.width == 72: - # displays with width of 72 pixels are shifted by 28 - xpos0 += 28 - xpos1 += 28 - self.write_cmd(SET_COL_ADDR) - self.write_cmd(xpos0) - self.write_cmd(xpos1) - self.write_cmd(SET_PAGE_ADDR) - self.write_cmd(0) - self.write_cmd(self.pages - 1) + if not self.page_addressing: + xpos0 = 0 + xpos1 = self.width - 1 + if self.width == 64: + # displays with width of 64 pixels are shifted by 32 + xpos0 += 32 + xpos1 += 32 + if self.width == 72: + # displays with width of 72 pixels are shifted by 28 + xpos0 += 28 + xpos1 += 28 + self.write_cmd(SET_COL_ADDR) + self.write_cmd(xpos0) + self.write_cmd(xpos1) + self.write_cmd(SET_PAGE_ADDR) + self.write_cmd(0) + self.write_cmd(self.pages - 1) self.write_framebuf() @@ -191,10 +207,11 @@ class SSD1306_I2C(_SSD1306): """ def __init__( - self, width, height, i2c, *, addr=0x3C, external_vcc=False, reset=None + self, width, height, i2c, *, addr=0x3C, external_vcc=False, reset=None, page_addressing=False ): self.i2c_device = i2c_device.I2CDevice(i2c, addr) self.addr = addr + self.page_addressing = page_addressing self.temp = bytearray(2) # Add an extra byte to the data buffer to hold an I2C data/command byte # to use hardware-compatible I2C transactions. A memoryview of the @@ -209,10 +226,11 @@ def __init__( height, external_vcc=external_vcc, reset=reset, + page_addressing=self.page_addressing, ) def write_cmd(self, cmd): - """Send a command to the SPI device""" + """Send a command to the I2C device""" self.temp[0] = 0x80 # Co=1, D/C#=0 self.temp[1] = cmd with self.i2c_device: @@ -221,9 +239,16 @@ def write_cmd(self, cmd): def write_framebuf(self): """Blast out the frame buffer using a single I2C transaction to support hardware I2C interfaces.""" - with self.i2c_device: - self.i2c_device.write(self.buffer) - + if self.page_addressing: + for page in range(self.pages): + self.write_cmd(0xB0 + page) + self.write_cmd(self.page_column_start[0]) + self.write_cmd(self.page_column_start[1]) + self.pagebuffer[1:] = self.buffer[1 + self.width * page:1 + self.width * (page + 1)] + self.i2c_device.write(self.pagebuffer) + else: + with self.i2c_device: + self.i2c_device.write(self.buffer) # pylint: disable-msg=too-many-arguments class SSD1306_SPI(_SSD1306): From 25fa2caea488590a519dcf52be87a6a07c1c719d Mon Sep 17 00:00:00 2001 From: Adam Candy Date: Sat, 20 Feb 2021 15:21:39 +0100 Subject: [PATCH 2/6] Formatting adjustments for black --- adafruit_ssd1306.py | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/adafruit_ssd1306.py b/adafruit_ssd1306.py index 72233a8..db3a1d0 100644 --- a/adafruit_ssd1306.py +++ b/adafruit_ssd1306.py @@ -99,9 +99,9 @@ def init_display(self): SET_DISP | 0x00, # off # address setting SET_MEM_ADDR, - 0x10 # Page Addressing Mode + 0x10 # Page Addressing Mode if self.page_addressing - else 0x00, # Horizontal Addressing Mode + else 0x00, # Horizontal Addressing Mode # resolution and layout SET_DISP_START_LINE | 0x00, SET_SEG_REMAP | 0x01, # column addr 127 mapped to SEG0 @@ -207,11 +207,19 @@ class SSD1306_I2C(_SSD1306): """ def __init__( - self, width, height, i2c, *, addr=0x3C, external_vcc=False, reset=None, page_addressing=False + self, + width, + height, + i2c, + *, + addr=0x3C, + external_vcc=False, + reset=None, + page_addressing=False ): self.i2c_device = i2c_device.I2CDevice(i2c, addr) self.addr = addr - self.page_addressing = page_addressing + self.page_addressing = page_addressing self.temp = bytearray(2) # Add an extra byte to the data buffer to hold an I2C data/command byte # to use hardware-compatible I2C transactions. A memoryview of the @@ -244,12 +252,15 @@ def write_framebuf(self): self.write_cmd(0xB0 + page) self.write_cmd(self.page_column_start[0]) self.write_cmd(self.page_column_start[1]) - self.pagebuffer[1:] = self.buffer[1 + self.width * page:1 + self.width * (page + 1)] + self.pagebuffer[1:] = self.buffer[ + 1 + self.width * page : 1 + self.width * (page + 1) + ] self.i2c_device.write(self.pagebuffer) else: with self.i2c_device: self.i2c_device.write(self.buffer) + # pylint: disable-msg=too-many-arguments class SSD1306_SPI(_SSD1306): """ From 8c9176bc7c2272510fabc7f77fc10c3fc67cbf85 Mon Sep 17 00:00:00 2001 From: Adam Candy Date: Sat, 20 Feb 2021 17:54:47 +0100 Subject: [PATCH 3/6] Fix Pylint error to ensure E1125 --- adafruit_ssd1306.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/adafruit_ssd1306.py b/adafruit_ssd1306.py index db3a1d0..9c1f65d 100644 --- a/adafruit_ssd1306.py +++ b/adafruit_ssd1306.py @@ -234,7 +234,7 @@ def __init__( height, external_vcc=external_vcc, reset=reset, - page_addressing=self.page_addressing, + page_addressing=self.page_addressing ) def write_cmd(self, cmd): @@ -288,7 +288,8 @@ def __init__( external_vcc=False, baudrate=8000000, polarity=0, - phase=0 + phase=0, + page_addressing=False ): self.rate = 10 * 1024 * 1024 dc.switch_to_output(value=0) @@ -303,6 +304,7 @@ def __init__( height, external_vcc=external_vcc, reset=reset, + page_addressing=self.page_addressing ) def write_cmd(self, cmd): From abdf5333d39814ed7f4732f92da5270793018676 Mon Sep 17 00:00:00 2001 From: Adam Candy Date: Sat, 20 Feb 2021 18:29:17 +0100 Subject: [PATCH 4/6] Restored commas following black parse --- adafruit_ssd1306.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/adafruit_ssd1306.py b/adafruit_ssd1306.py index 9c1f65d..33369ab 100644 --- a/adafruit_ssd1306.py +++ b/adafruit_ssd1306.py @@ -234,7 +234,7 @@ def __init__( height, external_vcc=external_vcc, reset=reset, - page_addressing=self.page_addressing + page_addressing=self.page_addressing, ) def write_cmd(self, cmd): @@ -304,7 +304,7 @@ def __init__( height, external_vcc=external_vcc, reset=reset, - page_addressing=self.page_addressing + page_addressing=self.page_addressing, ) def write_cmd(self, cmd): From ad6241f5e9decef5408d5b93b96a2a02b75b3c17 Mon Sep 17 00:00:00 2001 From: Adam Candy Date: Sat, 20 Feb 2021 18:36:54 +0100 Subject: [PATCH 5/6] Satisfy Pylint W0613, using page_addressing in SPI by alerting not implemented --- adafruit_ssd1306.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/adafruit_ssd1306.py b/adafruit_ssd1306.py index 33369ab..28ce466 100644 --- a/adafruit_ssd1306.py +++ b/adafruit_ssd1306.py @@ -291,6 +291,9 @@ def __init__( phase=0, page_addressing=False ): + if page_addressing: + raise NotImplementedError("Page addressing mode with SPI has not yet been implemented.") + self.rate = 10 * 1024 * 1024 dc.switch_to_output(value=0) self.spi_device = spi_device.SPIDevice( From 6d77e0775d215b40e0ef28cf723fe026ded9413a Mon Sep 17 00:00:00 2001 From: Adam Candy Date: Sat, 20 Feb 2021 18:41:04 +0100 Subject: [PATCH 6/6] More formatting compliance --- adafruit_ssd1306.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/adafruit_ssd1306.py b/adafruit_ssd1306.py index 28ce466..2a94aa5 100644 --- a/adafruit_ssd1306.py +++ b/adafruit_ssd1306.py @@ -292,7 +292,9 @@ def __init__( page_addressing=False ): if page_addressing: - raise NotImplementedError("Page addressing mode with SPI has not yet been implemented.") + raise NotImplementedError( + "Page addressing mode with SPI has not yet been implemented." + ) self.rate = 10 * 1024 * 1024 dc.switch_to_output(value=0)