SSD1306 OLED display: enhanced driver

Discuss development of drivers for external hardware and components, such as LCD screens, sensors, motor drivers, etc.
Target audience: Users and developers of drivers.
Post Reply
User avatar
pythoncoder
Posts: 5956
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

SSD1306 OLED display: enhanced driver

Post by pythoncoder » Sat Aug 18, 2018 10:18 am

Two years ago I wrote font_to_py.py: a utility for converting fonts to Python source. This enables fonts to be stored as frozen bytecode and used with minimal RAM allocation. To demonstrate it I wrote a very basic Writer class intended as a proof of concept. A number of people are using this as it stands so I have improved it, taking on board various requests and suggestions, to make it a practical solution.

A MicroPython module adds functionality to the official SSD1306 driver, enabling the rendering of Python fontfiles. It supports fields and labels with inverse and normal text:
Image
Mixed text and graphics:
Image
Right or centre justified text:
Image
Scrolling text with multiple fonts:
Image

Row wrapping options are clip or scroll. Column wrapping options are clip, character wrap and simple word wrap. Text display honours tab and newline characters. Inverse (background on foreground) text may be displayed and an inverted (upside down) display option is provided.

It supports multiple displays on the same host. It is designed to support any display device whose driver is subclassed from Framebuf. Currently only the SSD1306 OLED driver meets that requirement.
Peter Hinch
Index to my micropython libraries.

User avatar
mcauser
Posts: 507
Joined: Mon Jun 15, 2015 8:03 am

Re: SSD1306 OLED display: enhanced driver

Post by mcauser » Sat Aug 18, 2018 6:58 pm

Added subclassed version of my Nokia 5110 / PCD8544 driver:
https://github.com/mcauser/micropython- ... 8544_fb.py

It uses the MONO_VLSB format, as there is currently no compatible Framebuf format for the vertical addressing supported by the display.
More details on the display addressing: https://github.com/mcauser/micropython- ... addressing

User avatar
pythoncoder
Posts: 5956
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: SSD1306 OLED display: enhanced driver

Post by pythoncoder » Sun Aug 19, 2018 8:04 am

Just ordered a Nokia display so I'll give it a try.
Peter Hinch
Index to my micropython libraries.

User avatar
devnull
Posts: 473
Joined: Sat Jan 07, 2017 1:52 am
Location: Singapore / Cornwall
Contact:

Re: SSD1306 OLED display: enhanced driver

Post by devnull » Thu Nov 15, 2018 12:58 pm

Currently only the SSD1306 OLED driver meets that requirement.
Hi, I have have previously used the ssd1306 and just tried using the writer with the 1.3" sh1106 and of course it fails:

Code: Select all

ValueError: Device must be derived from FrameBuffer.
This is the result:

Code: Select all

import sh1106
>>> sh=sh1106.SH1106_I2C(128,64,gpio.i2c)
>>> dir(sh)
['__class__', '__dict__', '__init__', '__module__', '__qualname__', 'addr', 'blit', 'buffer', 'fill', 'fill_rect', 'framebuf', 'hline', 'invert', 'line', 'pixel', 'rect', 'reset', 'scroll', 'sleep', 'text', 'vline', 'res', 'init_display', 'poweroff', 'poweron', 'contrast', 'show', 'width', 'height', 'external_vcc', 'pages', 'write_cmd', 'write_data', 'i2c', 'temp', 'rotate', 'hw_write_data', 'sw_write_data']
>>> fm = Writer(ssd, f10, verbose=False)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "writer.py", line 70, in __init__
  File "writer.py", line 45, in _get_id
ValueError: Device must be derived from FrameBuffer.
But it looks like it is derived from framebuffer ?

User avatar
devnull
Posts: 473
Joined: Sat Jan 07, 2017 1:52 am
Location: Singapore / Cornwall
Contact:

Re: SSD1306 OLED display: enhanced driver

Post by devnull » Thu Nov 15, 2018 1:56 pm

I attempted to convert an existing sh1106 library to a similar format as ssd1306, but it fails at the init() probably as I don't understand how to use super():

Code: Select all

import framebuf

'''
import gpio, sh1106_i2c as sh
ssd = sh.SH1106(gpio.i2c)
'''

class SH1106(framebuf.FrameBuffer):

  _byte = bytearray(1)
  _word = bytearray(2)
    
  def __init__(self,  i2c, address=0x3c, width=128, height=64):
    self._address = address
    self.width = width
    self.height = height
    self._i2c = i2c

    buffer = bytearray(1024)
    self._buffer = memoryview(buffer)
    super().__init__(self._buffer, self._i2c, self._address,self.width,self.height)
    self.init_display()

  def init_display(self):
    self._command = bytearray(b'\xb0\x02\x10')
    if self.width > 128: self._command[1] = 0x00
    self._i2c.writeto_mem(self._address, 0x00, b'\xae\xd5\x80\xa8\x3f\xd3'
                          b'\x00\x40\x80\x14\x20\x00\xc0\xa0\xda\x12'
                          b'\x81\xcf\xd9\xf1\xdb\x40\xa4\xa6\xaf')    

    def active(self, val):
      self._i2c.writeto_mem(self._address, 0x00, b'\xaf' if val else b'\xae')

    def inverse(self, val):
      self._i2c.writeto_mem(self._address, 0x00, b'\xa7' if val else b'\xa6')

    def vscroll(self, dy):
      self._byte[0] = 0x40 | dy & 0x3f
      self._i2c.writeto_mem(self._address, 0x00, self._byte)

    def flip(self, val):
      self._i2c.writeto_mem(self._address, 0x00, b'\xc0' if val else b'\xc8')

    def mirror(self, val):
      self._i2c.writeto_mem(self._address, 0x00, b'\xa0' if val else b'\xa1')

    def contrast(self, val):
      self._word[0] = 0x81
      self._word[1] = val & 0xff
      self._i2c.writeto_mem(self._address, 0x00, self._word)

    def update(self):
      index = 0
      for page in range(self.height // 8):
        self._command[0] = 0xb0 | page
        self._i2c.writeto_mem(self._address, 0x00, self._command)
        self._i2c.writeto_mem(self._address, 0x40,self._buffer[index:index + self.width])
        index += self.width

Code: Select all

>>> import gpio, sh1106_i2c as sh
>>> ssd = sh.SH1106(gpio.i2c)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "sh1106_i2c.py", line 21, in __init__
TypeError: can't convert I2C to int

User avatar
Roberthh
Posts: 3667
Joined: Sat May 09, 2015 4:13 pm
Location: Rhineland, Europe

Re: SSD1306 OLED display: enhanced driver

Post by Roberthh » Thu Nov 15, 2018 2:54 pm

did you check the order of arguments in the super.__init__() call. That may be the problem. It calls the framebuffer class' init(), which does not requires i2c and address. Should look like
super().__init__(width, height, external_vcc)

User avatar
devnull
Posts: 473
Joined: Sat Jan 07, 2017 1:52 am
Location: Singapore / Cornwall
Contact:

Re: SSD1306 OLED display: enhanced driver

Post by devnull » Fri Nov 16, 2018 5:03 am

Thanks Robert, that was it.

I have updated the driver which can be found here: https://github.com/pacmac/micropython-s ... 106_i2c.py

Post Reply