I2C oled driver mods by NurseJackass

I2C oled config can be added in the config.toml
Default is 128x64 display on i2c address 0x3C

ui.display.type = "i2coled"
ui.display.i2c_addr = 0x3C
ui.display.width = 128
ui.display.height = 64
This commit is contained in:
RasTacsko
2024-04-18 17:39:53 +02:00
parent 9a941c1d46
commit fef442edbb
5 changed files with 57 additions and 33 deletions

View File

@ -3,20 +3,33 @@
# https://github.com/adafruit/Adafruit_Python_SSD1306 # https://github.com/adafruit/Adafruit_Python_SSD1306
# SMBus parts coming from BLavery's lib_oled96 repo: # SMBus parts coming from BLavery's lib_oled96 repo:
# https://github.com/BLavery/lib_oled96 # https://github.com/BLavery/lib_oled96
# I2C address, width and height import from config.toml made by NurseJackass
import logging import logging
import pwnagotchi.ui.fonts as fonts import pwnagotchi.ui.fonts as fonts
from pwnagotchi.ui.hw.base import DisplayImpl from pwnagotchi.ui.hw.base import DisplayImpl
#
# Default is 128x64 display on i2c address 0x3C
#
# Configure i2c address and dimensions in config.toml:
#
# ui.display.type = "i2coled"
# ui.display.i2c_addr = 0x3C
# ui.display.width = 128
# ui.display.height = 64
#
class I2COled(DisplayImpl): class I2COled(DisplayImpl):
def __init__(self, config): def __init__(self, config):
self._config = config['ui']['display']
super(I2COled, self).__init__(config, 'i2coled') super(I2COled, self).__init__(config, 'i2coled')
def layout(self): def layout(self):
fonts.setup(8, 8, 8, 10, 10, 8) fonts.setup(8, 8, 8, 10, 10, 8)
self._layout['width'] = 128 self._layout['width'] = self._config['width'] if 'width' in self._config else 128
self._layout['height'] = 64 self._layout['height'] = self._config['height'] if 'height' in self._config else 64
self._layout['face'] = (0, 30) self._layout['face'] = (0, 30)
self._layout['name'] = (0, 10) self._layout['name'] = (0, 10)
self._layout['channel'] = (72, 10) self._layout['channel'] = (72, 10)
@ -36,10 +49,14 @@ class I2COled(DisplayImpl):
return self._layout return self._layout
def initialize(self): def initialize(self):
logging.info("initializing 128x64 I2C Oled Display on address 0x3C") i2caddr = self._config['i2c_addr'] if 'i2c_addr' in self._config else 0x3C
logging.info("To change resolution or address check pwnagotchi/ui/hw/libs/i2coled/epd.py") width = self._config['width'] if 'width' in self._config else 128
height = self._config['height'] if 'height' in self._config else 64
logging.info("initializing %dx%d I2C Oled Display on address 0x%X" % (width, height, i2caddr))
from pwnagotchi.ui.hw.libs.i2coled.epd import EPD from pwnagotchi.ui.hw.libs.i2coled.epd import EPD
self._display = EPD() self._display = EPD(address=i2caddr, width=width, height=height)
self._display.Init() self._display.Init()
self._display.Clear() self._display.Clear()

View File

@ -100,13 +100,19 @@ class SSD1306Base(object):
"""Send command byte to display.""" """Send command byte to display."""
# I2C write. # I2C write.
assert(len(cmd) <= 31) assert(len(cmd) <= 31)
try:
self.bus.write_i2c_block_data(self.addr, self.cmd_mode, list(cmd)) self.bus.write_i2c_block_data(self.addr, self.cmd_mode, list(cmd))
except Exception as e:
logging.exception(e)
def data(self, data): def data(self, data):
"""Send byte of data to display.""" """Send byte of data to display."""
# I2C write. # I2C write.
try:
for i in range(0, len(data), 31): for i in range(0, len(data), 31):
self.bus.write_i2c_block_data(self.addr, self.data_mode, list(data[i:i+31])) self.bus.write_i2c_block_data(self.addr, self.data_mode, list(data[i:i+31]))
except Exception as e:
logging.exception(e)
def begin(self, vccstate=SSD1306_SWITCHCAPVCC): def begin(self, vccstate=SSD1306_SWITCHCAPVCC):
"""Initialize display.""" """Initialize display."""
@ -128,9 +134,11 @@ class SSD1306Base(object):
self.command(SSD1306_PAGEADDR) self.command(SSD1306_PAGEADDR)
self.command(0) # Page start address. (0 = reset) self.command(0) # Page start address. (0 = reset)
self.command(self._pages-1) # Page end address. self.command(self._pages-1) # Page end address.
try:
for i in range(0, len(self._buffer), 16): for i in range(0, len(self._buffer), 16):
self.bus.write_i2c_block_data(self.addr, self.data_mode, self._buffer[i:i+16]) self.bus.write_i2c_block_data(self.addr, self.data_mode, self._buffer[i:i+16])
except Exception as e:
logging.exception(e)
def getbuffer(self, image): def getbuffer(self, image):
"""Set buffer to value of Python Imaging Library image. The image should """Set buffer to value of Python Imaging Library image. The image should
@ -229,7 +237,7 @@ class SSD1306_128_64(SSD1306Base):
class SSD1306_128_32(SSD1306Base): class SSD1306_128_32(SSD1306Base):
def __init__(self, width, height, address=None, bus=None): def __init__(self, width, height, address=None, bus=None):
# Call base class constructor. # Call base class constructor.
super(SSD1306_128_64, self).__init__(128, 64, address, bus) super(SSD1306_128_32, self).__init__(128, 32, address, bus)
def _initialize(self): def _initialize(self):
# 128x32 pixel specific initialization. # 128x32 pixel specific initialization.

View File

@ -8,20 +8,27 @@ EPD_HEIGHT = 64
# disp = SSD1306.SSD1306_128_32(128, 32, address=0x3C) # disp = SSD1306.SSD1306_128_32(128, 32, address=0x3C)
# disp = SSD1306.SSD1306_96_16(96, 16, address=0x3C) # disp = SSD1306.SSD1306_96_16(96, 16, address=0x3C)
# If you change for different resolution, you have to modify the layout in pwnagotchi/ui/hw/i2coled.py # If you change for different resolution, you have to modify the layout in pwnagotchi/ui/hw/i2coled.py
disp = SSD1306.SSD1306_128_64(128, 64, address=0x3C)
class EPD(object): class EPD(object):
def __init__(self): def __init__(self, address=0x3D, width=EPD_WIDTH, height=EPD_HEIGHT):
self.width = EPD_WIDTH self.width = width
self.height = EPD_HEIGHT self.height = height
# choose subclass based on dimensions
if height == 32:
self.disp = SSD1306.SSD1306_128_32(width, height, address)
elif height == 16:
self.disp = SSD1306.SSD1306_96_16(width, height, address)
else:
self.disp = SSD1306.SSD1306_128_64(width, height, address)
def Init(self): def Init(self):
disp.begin() self.disp.begin()
def Clear(self): def Clear(self):
disp.clear() self.disp.clear()
def display(self, image): def display(self, image):
disp.getbuffer(image) self.disp.getbuffer(image)
disp.ShowImage() self.disp.ShowImage()

View File

@ -95,11 +95,8 @@ class ST7789(object):
offset_left=0, offset_left=0,
offset_top=0): offset_top=0):
"""Create an instance of the display using SPI communication. """Create an instance of the display using SPI communication.
Must provide the GPIO pin number for the D/C pin and the SPI driver. Must provide the GPIO pin number for the D/C pin and the SPI driver.
Can optionally provide the GPIO pin number for the reset pin as the rst parameter. Can optionally provide the GPIO pin number for the reset pin as the rst parameter.
:param port: SPI port number :param port: SPI port number
:param cs: SPI chip-select number (0 or 1 for BCM :param cs: SPI chip-select number (0 or 1 for BCM
:param backlight: Pin for controlling backlight :param backlight: Pin for controlling backlight
@ -109,7 +106,6 @@ class ST7789(object):
:param rotation: Rotation of display connected to ST7789 :param rotation: Rotation of display connected to ST7789
:param invert: Invert display :param invert: Invert display
:param spi_speed_hz: SPI speed (in Hz) :param spi_speed_hz: SPI speed (in Hz)
""" """
if rotation not in [0, 90, 180, 270]: if rotation not in [0, 90, 180, 270]:
raise ValueError("Invalid rotation {}".format(rotation)) raise ValueError("Invalid rotation {}".format(rotation))
@ -287,9 +283,7 @@ class ST7789(object):
def begin(self): def begin(self):
"""Set up the display """Set up the display
Deprecated. Included in __init__. Deprecated. Included in __init__.
""" """
pass pass
@ -326,9 +320,7 @@ class ST7789(object):
def display(self, image): def display(self, image):
"""Write the provided image to the hardware. """Write the provided image to the hardware.
:param image: Should be RGB format and the same dimensions as the display hardware. :param image: Should be RGB format and the same dimensions as the display hardware.
""" """
# Set address bounds to entire display. # Set address bounds to entire display.
self.set_window() self.set_window()