
LittlevGL – A High-Level Micropython GUI Library - homarp
https://blog.littlevgl.com/2019-02-20/micropython-bindings
======
seniorsassycat
I'm working on my first electronics project, it's using Adafruit's Feather M0
Express and a SSD1306 oled screen.

The Feather is a a ATSAMD21 microcontroller with circuitpython - Adafruit's
versoin of Micropython (?). The oled screen is controlled by spi, but can be
controlled with i2c, and I think a non-serial protocol.

I've noticed that refreshing the display is very slow, a loop like this
flashing the screen is very slow.

    
    
        while True:
          oled.fill(0)
          oled.show()
          oled.fill(1)
          oled.show()
    

Even writing a line of text is slow

    
    
          oled.text("Hello", 1, 1)
    

And the old text is not cleared from the screen so I have to write over the
previous display to clear it.

    
    
        oled.text("0", 1, 1, 0)
        oled.show()
        oled.text("1", 1, 1, 1)
        oled.show()
        // at this point the screen shows a 0 and 1 overlaid.
    
        // this is a foolproof way to clear the screen, but it's very slow
        oled.fill(0)
        oled.text("1", 1, 1, 1)
        oled.show();
      
        // This is a little faster than the previous example, but will become harder to maintain as the display becomes more complicated.
        oled.text(lastText, 1, 1, 0)
        oled.text(newText, 1, 1, 1)
        oled.show()
        lastText = newText
    

I'm not expecting a 60hz display, but I don't think I'm getting 12hz.

\- Why is this so slow? The microcontroller, the display, the spi protocol,
circuitpython? \- Would a display library like LittlevGL speed up rendering?
\- Would switching from micropython to c or rust improve performance? \- Could
it be as simple as increasing the spi clock (I'm using defaults from the
SSD1306 library)?

~~~
joshvm
There are two things you need to consider: how fast you can push pixels
(determined by bus speed), and how fast/often you're actually pushing pixels
(library efficiency). A faster clock will usually speed things up.

One oddity about many displays (including the SSD1306) is that you can't write
to a single pixel. Single pixels are not addressable (it would be a waste of
RAM on a 1-bit display), so you usually have to send a write sequence that
includes a memory offset and then a data byte (8 pixels). That also implies
you can only write to 8-pixel wide blocks on the display in one go.

If you have RAM on your micro, the way to minimise write overhead and code
complexity is to buffer the entire display and then update it in one go; I
assume this is what adafruit does. Most displays have a mode where you keep
sending bytes and it'll auto increment the display pointer. However now you
have the cost of updating the entire display if you just want to update say
four numbers for a sensor readout.

An approach I've used in the past is to defined a variable width font 8 pixels
high (i.e. each character is 8xN). This is stored column-wise in memory (so
character[10][0] has the bits in the first col). Then a write operation simply
involved writing to a memory location, and iterating through each character's
columns in the string. It's very fast even over I2C.

I would define an imaginary grid on the display and then call something like
put_text(row, x, "my_string"). The approach means your write regions must be
multiples of eight high, but the width doesn't matter. And you can also use
this for things like simple sparkline plots where you don't need to store an
entire displays' worth of data. I believe on the SSD1306 you get to choose
whether the RAM is treated in column-wise order or row-wise order (or
something like that to make this approach work).

Obviously refresh rate is determined by how much you change on the display per
second, but for a few numeric fields it's really fast.

EDIT:
[https://www.electrodragon.com/w/images/9/95/SSD1306.pdf](https://www.electrodragon.com/w/images/9/95/SSD1306.pdf)

Yes - it has either vertical or horizontal page addressing which you can
exploit.

I strongly recommend trying to write a display driver. The SSD1306 is great,
and they're so cheap on eBay. You get instant feedback when stuff isn't right
and it's a lot of fun trying to write efficient routines on 8-bit
microcontrollers.

~~~
embeddedt
I'm one of the developers on the LittlevGL project. As a note, the display
architecture does buffer chunks of the display and then write them.

~~~
joshvm
Good to know! I checked though, Adafruit's doesn't :)

[https://github.com/adafruit/Adafruit_CircuitPython_SSD1306/b...](https://github.com/adafruit/Adafruit_CircuitPython_SSD1306/blob/master/adafruit_ssd1306.py)

------
pjmlp
Very nice project.

My only remark is that the GL suffix might be mistaken by a tiny OpenGL
subset.

~~~
azhenley
I almost didn't click on this because I thought it was just a wrapper/library
built around OpenGL.

------
ethanpil
I love these kind of projects, really making stuff smaller and more
accessible. I'm hoping that we can see something as simple as AppJar [
[http://appjar.info/](http://appjar.info/) ] to really boost the tinker/maker
community, and especially beginners and younger students as AppJar does.

------
albertzeyer
I recently developed some Python GUI app using Kivy for Raspberry Pi, and I'm
quite happy with the result. From the short code examples of LittleGL, it
looks similarly easy. I wonder how they compare. But maybe it would be hard to
run Kivy on Micropython / micro controllers, although not sure.

------
traverseda
Very impressive! I'd like to use this in regular python as well.

~~~
tinix
micropython IS regular python, that's the point. i see no reason why this
wouldn't work on cpython.

~~~
jononor
But LittlevGL is not written in Python. It is written in C. From the website:
"All LittlevGL functionality (such as rendering the graphics) is still in C.
The Micropython binding only provides wrappers for LittlevGL API..."

The C interface of Micropython and CPython are different. So I would expect
that you have to port/redo the bindings for this to work on CPython.

~~~
embeddedt
I'm one of the developers on the LittlevGL project. The Micropython binding is
not compatible with regular Python at all. See this comment:
[https://github.com/littlevgl/lv_binding_micropython/issues/1...](https://github.com/littlevgl/lv_binding_micropython/issues/13#issuecomment-468803729)

