SSD1306 with SPI on LoPy4? (/topic/1541/solved-ssd1306-with-spi on WiPy)

  • RE: SSD1306 with SPI?](/topic/1541/solved-ssd1306-with-spi)


    Using the ssd1306 driver (, I'll try to get the Adafruit 128x32 OLED SSD1306-SPI working with LoPy4. No luck thusfar.

    The OLED display is wired to my LoP4 (via Expansion board 3.0) as follows:

    SSD1306 -> LoPy4 -> Exp.bord
    Vin -> 3.3V
    GND -> GND
    DATA -> MOSI,P11 -> G22
    CLK -> CLK,P10 -> G17
    DC -> P9 -> G16
    RST -> P8 -> G15
    CS -> P12 -> G28

    This is the code I'm using to test, and for which I got error
    'TypeError: function expected at most 5 arguments, got 6'

    from machine import Pin, SPI
    from ssd1306 import SSD1306_SPI as ssd

    spi = SPI(0, mode=SPI.MASTER, baudrate=1000000, polarity=0, phase=0)

    dc = Pin('P9', mode=Pin.OUT) # G16
    rst = Pin('P8', mode=Pin.OUT) # G15
    cs = Pin('P12', mode=Pin.OUT) # G28

    oled = ssd(128, 32, spi, dc, rst, cs)

    Is it wired correctly?
    Is the ssd130 module from correct to use for LoPy4? There are 6, and not 5, arguments needed for the SSD1306_SPI constructor.

    When I leave out any of the pin-arguments (dc or rst), I'll got following error:
    'TypeError: object with buffer protocol required'

    Does anyone has a tip or pointer how to get the display working with the LoPy4?

    Pycom MicroPython 1.18.0.r1 [v1.8.6-849-9569a73] on 2018-07-20
    Thanks, Peter

  • The argument related issues are related to an issue with using a native class as a base class. See here:

    This doesn't work in Pycom's MicroPython release 1.18 (current stable) but the fix from the above linked issue has been incorporated into the development release 1.20 (currently at rc4).

    Additionally, the Pycom MicroPython flavor has a different I2C API than the official MicroPython, lacking the I2C methods start(), stop() and write(). There you need to apply the changes outlined in this old thread as well:

    Specifically, you'll need to replace the write_data() method with:

        def write_data(self, buf):
            self.i2c.writeto(self.addr, bytearray([0x40]) + buf) 

    (I see that you've already discussed the issue with Pycom's MicroPython flavor using framebuf.MVLSB where as the constant is named framebuf.MONO_VLSB in the official MicroPython).

    The SSD1306 driver in Pycom's MicroPython flavor has never worked and is still using non-existant APIs and constants even in the release-candidate tree:

    If you get noisy display you might have an SH1106 display. I'm using the below piece of code successfully with random eBay 0.96" and 1.3" I2C OLED displays. It's been a few years since I looked into this but IIRC the SH1106 module's internal memory layout is for 132 pixel strides but the screen only supports 128. So the noise in the form of random black pixels come from the fact that those extra two pixels on the left and on the right side are not accounted for (the display is centered somehow).

    from ssd1306 import SSD1306
    class SH1106_I2C(SSD1306):
        def __init__(self, width, height, i2c, addr=0x3c, external_vcc=False):
            self.i2c = i2c
            self.addr = addr
            self.temp = bytearray(2)
            super().__init__(width, height, external_vcc)
            # Parent does show() but is using the SSD1306 implementation..
        def write_cmd(self, cmd):
            self.temp[0] = 0x80 # Co=1, D/C#=0
            self.temp[1] = cmd
            self.i2c.writeto(self.addr, self.temp)
        def write_data(self, buf):
            self.i2c.writeto(self.addr, bytearray([0x40]) + buf)
        def poweron(self):
        def show(self):
            for page in range(8):
                self.write_cmd(0xb0 | page)
                self.write_cmd(0x02)    # Start addr low column
                self.write_cmd(0x10)    # Start addr high column
                mv = memoryview(self.buffer)
                self.write_data(mv[128*page: 128 + 128*page])
    from sh1106 import SH1106_I2C
    i2c = I2C(0, I2C.MASTER, baudrate=400000)
    d = SH1106_I2C(128, 64, i2c)
    d.text('ping', 1, 2)

  • @flexypepo Yes, that's rigth. The API for Pin changed a while ago from pin.high() to pin.value(1) or just pin(1). The latter is, what the genuine driver at uses.

  • @robert-hh Thanks for your information. I've tried the change to 'framebuf.MVLSB', but it did not helped. Neither connecting the Vin of OLED-display to +5V instead of +3V on Expansion board.

    However, using a two-year old 'ssd1306' module of Tony DiCola (, the OLED came to life! Only change in ssd1306 module, was to use 'aPin'.value(1) instead of 'aPin'.high(). Idemdito for 'aPin'.low()..

    I've not yet investigated what the differences are in the drivers, especially related to the 'strange' error message about the number of arguments. For the moment, I continue with this (slightly modified) ssd1306 driver, and will see what will happen.

    Thanks for the pointer about the P8-pin. I'll change it when I'm start to use the SD-card. I'm new to LoPy4 development, and found the P- and G-names very confusing. I have some experiences with micropython on a couple of ESP32 boards. Its a challenge (or pity?) to handle the various flavours of Micopython (Adafruit, Loboris, Pycom, vanilla micropython). Sigh.

    Best regards, Peter

  • @flexypepo I would not expect it to work right away, but the differences should be small. One I stumbled over is in line 35 of, which reads:
    super().__init__(self.buffer, self.width, self.height, framebuf.MONO_VLSB)
    The last argument should be framebuf.MVLSB with Pycom's flavor of micropython.
    The other thing I noticed is the use of Pins. P8 is used for the SD card data. So if you use the SD card, you must not use P8 for other purposes.
    And yes, you need all 6 arguments, since the signals mentioned by them are needed.
    Edit: I do not know why this error you mention is flagged. I would expect something else.

Log in to reply

Pycom on Twitter