Displaying bitmap graphics on OLED

All ESP8266 boards running MicroPython.
Official boards are the Adafruit Huzzah and Feather boards.
Target audience: MicroPython users with an ESP8266 board.
jhadd
Posts: 3
Joined: Tue Jan 10, 2017 6:45 pm

Displaying bitmap graphics on OLED

Post by jhadd » Tue Jan 31, 2017 12:05 am

I'm trying to display simple monochrome bitmap graphics on a 128x64 OLED screen (SSD1306). It looks like there are simple ways to accomplish this with Arduino using Adafruit's GFX library, which has a drawbitmap method (see also here). Is there something similar for MicroPython?

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

Re: Displaying bitmap graphics on OLED

Post by pythoncoder » Tue Jan 31, 2017 8:43 am

As I suggested in response to your PM, I can see two approaches. One is to use the SSD1306 pixel method to output it in a bitwise fashion. The other is to use the framebuf's blit() method which looks as if it takes a buffer followed by destination x and y coordinates as arguments (see extmod/modframebuf.c).

This stuff is new so documentation is sparse; experimenting and testing are king...
Peter Hinch
Index to my micropython libraries.

User avatar
deshipu
Posts: 1388
Joined: Thu May 28, 2015 5:54 pm

Re: Displaying bitmap graphics on OLED

Post by deshipu » Tue Jan 31, 2017 9:47 am

Here's an example program that displays the (old) MicroPython logo on the WeMos D1 Mini OLED shield. For a different display you need to modify the parameters passed to the driver. Also, note that you need to copy the ssd1306.py driver file to your ESP8266 for this to work.

Code: Select all

import ssd1306
import framebuf
from machine import I2C, Pin
i2c = I2C(-1, Pin(5), Pin(4))
display = ssd1306.SSD1306_I2C(64, 48, i2c)

buffer = bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x10\x8a\n0\x10$\xc8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00x\xfe\xff?\xfe\xfd|\xfb\xf8\xfc\xff|\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\xc0@\xe0\xe0\xe0\xc0\xc1c\x9f\xff\x0f\xce\xff\xff\xcf\xe3\xf0pp\xa0\xe0\xe0\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf0\xff\xfb\xe7\xdf\x8e\x9e\xfd\x95"$%\x00\xfe\xff\xff\xed\xdd\xce\xce\xff\xe7\xe7\xf7\xfb\xf9\xfep\xe0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00@6\x9bg7\xcfo\x9d\xdb?\xbbws\xf7\xfa\xfa\xf9\xf4\xfd\xf7\xf3\xf1\xfdsy\xbd;\xd9\x9do\xcc6g\x9b6@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x02\x01\x04\x03\t\x06\x13\x0c&\x19\r\x1b\x1b\r\x19&\x0c\x13\x06\t\x03\x04\x01\x02\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
fb = framebuf.FrameBuffer(buffer, 48, 48, framebuf.MVLSB)
display.fill(0)
display.framebuf.blit(fb, 8, 0)
display.show()
I hope that helps.
Last edited by deshipu on Tue Jan 31, 2017 10:18 am, edited 1 time in total.

User avatar
deshipu
Posts: 1388
Joined: Thu May 28, 2015 5:54 pm

Re: Displaying bitmap graphics on OLED

Post by deshipu » Tue Jan 31, 2017 10:15 am

The buffer in the previous exampe is created by scanning the original image pixel-by-pixel and setting the bits of the bytes depending on whether they are supposed to be on or off. The alignment of the bytes is as follows (example of a 16x16 image, the digits signify the bits of each byte):

Code: Select all

a7 b7 c7 d7 e7 f7 g7 h7 i7 j7 k7 l7 m7 n7 o7 p7
a6 b6 c6 d6 e6 f6 g6 h6 i6 j6 k6 l6 m6 n6 o6 p6
a5 b5 c5 d5 e5 f5 g5 h5 i5 j5 k5 l5 m5 n5 o5 p5
a4 b4 c4 d4 e4 f4 g4 h4 i4 j4 k4 l4 m4 n4 o4 p4
a3 b3 c3 d3 e3 f3 g3 h3 i3 j3 k3 l3 m3 n3 o3 p3
a2 b2 c2 d2 e2 f2 g2 h2 i2 j2 k2 l2 m2 n2 o2 p2
a1 b1 c1 d1 e1 f1 g1 h1 i1 j1 k1 l1 m1 n1 o1 p1
a0 b0 c0 d0 e0 f0 g0 h0 i0 j0 k0 l0 m0 n0 o0 p0
q7 r7 s7 t7 u7 v7 w7 x7 y7 z7 A7 B7 C7 D7 E7 F7
q6 r6 s6 t6 u6 v6 w6 x6 y6 z6 A6 B6 C6 D6 E6 F6
q5 r5 s5 t5 u5 v5 w5 x5 y5 z5 A5 B5 C5 D5 E5 F5
q4 r4 s4 t4 u4 v4 w4 x4 y4 z4 A4 B4 C4 D4 E4 F4
q3 r3 s3 t3 u3 v3 w3 x3 y3 z3 A3 B3 C3 D3 E3 F3
q2 r2 s2 t2 u2 v2 w2 x2 y2 z2 A2 B2 C2 D2 E2 F2
q1 r1 s1 t1 u1 v1 w1 x1 y1 z1 A1 B1 C1 D1 E1 F1
q0 r0 s0 t0 u0 v0 w0 x0 y0 z0 A0 B0 C0 D0 E0 F0
I used the following code to generate it:

Code: Select all

import pygame

image = pygame.image.load("1bit-logo.png")
buffer = bytearray((image.get_height() // 8) * image.get_width())
i = 0
for y in range(image.get_height() // 8):
    for x in range(image.get_width()):
        byte = 0
        for bit in range(8):
            pixel = image.get_at((x, y * 8 + bit))
            if pixel[0] != 255:
                byte |= (1 << bit)
        buffer[i] = byte
        i += 1
print(repr(buffer))
Last edited by deshipu on Tue Jan 31, 2017 12:34 pm, edited 1 time in total.

User avatar
kamikaze
Posts: 154
Joined: Tue Aug 16, 2016 10:10 am
Location: Latvia
Contact:

Re: Displaying bitmap graphics on OLED

Post by kamikaze » Tue Jan 31, 2017 12:08 pm

or you could use ImageMagick`s convert and store it in file to save RAM

User avatar
deshipu
Posts: 1388
Joined: Thu May 28, 2015 5:54 pm

Re: Displaying bitmap graphics on OLED

Post by deshipu » Tue Jan 31, 2017 12:30 pm

Sure, I just thought that example code will be better for a precise explanation of the format. How you generate the data exactly is up to you, this is only an example.

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

Re: Displaying bitmap graphics on OLED

Post by pythoncoder » Fri Feb 03, 2017 5:21 pm

deshipu wrote:... The alignment of the bytes is as follows (example of a 16x16 image, the digits signify the bits of each byte)...
I know I've carped about this before but I see we're still stuck with this weird SSD1306 pseudo-horizontal mapping. The SSD1306 does support a true vertical mapping. I have tested it in this mode and it works as expected. The framebuf is supposed (eventually) to support four mappings; alas this isn't one of them ;)

What would be your view on a PR to the official driver to use this mode? As far as I can see the mode has no intrinsic merit and we're using it because nobody has got round to fixing it. Or for fear of breaking code. Perhaps the mapping should be a runtime option to ssd1306.py, defaulting to weird.

Ideally the blit function would be capable of blitting between framebufs with heterogeneous mappings (but only the four variants discussed - vertical, horizontal, normal and bit-reversed). This isn't a priority for my current interest - font rendering - because I can generate any of the four agreed mappings.
Peter Hinch
Index to my micropython libraries.

User avatar
deshipu
Posts: 1388
Joined: Thu May 28, 2015 5:54 pm

Re: Displaying bitmap graphics on OLED

Post by deshipu » Sat Feb 04, 2017 8:00 pm

pythoncoder wrote: What would be your view on a PR to the official driver to use this mode?
As you know, I have no say in this.
I would love to work on making the framebuf module really usable p -- adding support for more modes, for read-only buffers, for getting the size from Python, etc. -- alas, with no pull requests accepted, I'm not keen on doing work that would be wasted.

In the mean time I will just work on my own fork for my game engine, and if anybody wants to use any of that code, they are welcome to pull it into their implementation.

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

Re: Displaying bitmap graphics on OLED

Post by pythoncoder » Sun Feb 05, 2017 6:19 am

deshipu wrote:As you know, I have no say in this...
I've now studied your updated modframebuf.c and have finally understood what you've been driving at. It does a great job of abstracting the physical layout of the buffer into three functions, so blits between heterogeneous framebufs should "just work". In principle my font_to_py.py code only needs to support one supported framebuf mode to support them all. Sorry it's taken me a while to cotton on :oops:

So there's no point in changing the SSD1306 mode.

I'll have a go at adding support to modframebuf.c for the four original modes (horizontal and vertical mappings with normal and reversed bit ordering) and test them with my font files. I'll submit a PR in due course - I'm in no hurry but I'd like to see fonts being rendered by blitting rather than bitwise as at present.
Peter Hinch
Index to my micropython libraries.

User avatar
jgriessen
Posts: 191
Joined: Mon Sep 29, 2014 4:20 pm
Contact:

Re: Displaying bitmap graphics on OLED

Post by jgriessen » Sat Jul 01, 2017 6:11 pm

I'm going to be wanting to use a LCD driver soon. Does any of what you two are working on translate to the driver adafruit uses? ILI9341/ILI9340 TFT displays? Is this only for ESP8266?
John Griessen blog.kitmatic.com

Post Reply