How to implement the buffer protocol

Discussion about programs, libraries and tools that work with MicroPython. Mostly these are provided by a third party.
Target audience: All users and developers of MicroPython.
Post Reply
c22
Posts: 11
Joined: Tue Sep 29, 2020 8:03 pm

How to implement the buffer protocol

Post by c22 » Tue Oct 27, 2020 9:35 pm

Hi all.

I'm writing a small library to drive the Seeed Grove OLED display ( https://wiki.seeedstudio.com/Grove-OLED ... _1.12inch/ ). I'm following the Arduino example source code, it has been pretty easy so far.

I'd like to let the FrameBuffer class to directly write into the display ram but I need to grab the FrameBuffer's write operations on the bytearray object used as image buffer. As far as I can tell the only (and proper) way is to write a class that implements the buffer protocol but this cannot be done in pure Python.

Is it possible to implement the buffer protocol in MicroPython? How?

thanks in advance for any hint.

Bye

User avatar
jimmo
Posts: 2754
Joined: Tue Aug 08, 2017 1:57 am
Location: Sydney, Australia
Contact:

Re: How to implement the buffer protocol

Post by jimmo » Wed Oct 28, 2020 1:11 am

c22 wrote:
Tue Oct 27, 2020 9:35 pm
Is it possible to implement the buffer protocol in MicroPython? How?
Not that I'm aware of. The buffer prototcol is all about being able to extract a "uint8_t*" out of something, which doesn't really make sense to implement in Python.

However I don't quite understand what you're trying to do.

The normal use case with a display driver is to inherit from FrameBuffer, and then pass a bytearray to the FrameBuffer constructor, which it will then write the pixel data into (in the requested format). Then you implement a method that is used to send that bytearray to the display module (over SPI/I2C).

It sounds like what you're trying to do is pass your own thing in place of that bytearray in order to intercept the writes to the data?

c22
Posts: 11
Joined: Tue Sep 29, 2020 8:03 pm

Re: How to implement the buffer protocol

Post by c22 » Wed Oct 28, 2020 7:33 am

Exactly: I'd like to send to the display, though the I2C bus, only the bytes actively written by the FrameBuffer class, and I need to replace the bytearray with something else - but it must to implement the buffer protocol.

Currently I'm sending the whole bytearray to the display when needed and it take 140ms to update the 128x128 pixel matrix (I'm trying to optimize the data send on the bus, I think it could go down up to 50ms, but this is another topic).
It isn't that bad after all, but for small draw operations like updating just some text, it is very inefficient; also, the rolling pixel redraw is sometimes visible.

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

Re: How to implement the buffer protocol

Post by pythoncoder » Wed Oct 28, 2020 8:24 am

...I'd like to send to the display, though the I2C bus, only the bytes actively written by the FrameBuffer class...
This must be highly dependent on the display hardware. If you look at the show method in this driver, the hardware allows individual display lines to be updated. The driver doesn't actually take advantage of this, updating all lines sequentially, but the essence of doing this is there: using a memoryview into the buffer to enable slices to be extracted at high speed.

Does your hardware allow something similar?
Peter Hinch
Index to my micropython libraries.

User avatar
jimmo
Posts: 2754
Joined: Tue Aug 08, 2017 1:57 am
Location: Sydney, Australia
Contact:

Re: How to implement the buffer protocol

Post by jimmo » Wed Oct 28, 2020 8:35 am

What you want is currently not possible with FrameBuffer.

But yes, some sort of generalised "dirty rectangles" feature would be a really good optimisation, but as pythoncoder points out, highly dependent on the particular display on terms of how to take advantage of it.

It's worth noting that implementing the buffer protocol in Python would basically remove all the performance benefits of FrameBuffer -- you'd be executing Python code for every pixel update, so you might as well just implement FrameBuffer in Python. This is why a dirty rectangles feature would be better -- FrameBuffer could keep track of this info in C and let the driver know what's changed.

c22
Posts: 11
Joined: Tue Sep 29, 2020 8:03 pm

Re: How to implement the buffer protocol

Post by c22 » Wed Oct 28, 2020 8:36 am

Yes, this display module allows the update of a single byte, 8 pixels.

Edit: I'm not expecting to do this writing regular Python code, C or even something else would be fine. But I'm glad to know that there's currently no way to do this. Thanks.

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

Re: How to implement the buffer protocol

Post by pythoncoder » Wed Oct 28, 2020 8:43 am

If a display has its own internal frame buffer accessible at byte level it may be simplest to ignore the framebuf class and write a dedicated driver. See the official lcd160cr driver for an example. This driver is very fast and efficient.
Peter Hinch
Index to my micropython libraries.

c22
Posts: 11
Joined: Tue Sep 29, 2020 8:03 pm

Re: How to implement the buffer protocol

Post by c22 » Wed Oct 28, 2020 9:13 am

Yes, I thought about it, but I don't agree it is simpler. FrameBuffer gives me all the basic drawing primitives for free, especially a tedious feature like text drawing. Also (if I'm not going wrong) could be considered as standard in MicroPython, and future new FrameBuffer features will be available at zero cost to this display module.

I'm just looking for an easy way to get a significant efficiency boost over the whole display update. If I needed to squeeze out every possibile microsecond out of this module then I'd go on the route of writing a completely ad-hoc display driver.

Thanks for you suggestion!

c22
Posts: 11
Joined: Tue Sep 29, 2020 8:03 pm

Re: How to implement the buffer protocol

Post by c22 » Sat Nov 21, 2020 10:00 am

Just un update about how I solved my problem.

I used a second image buffer to mirror what it is shown on the display, and byte-by-byte look for the differences against the FrameBuffer actual buffer, and then send data to the display only for those differences. This additional computational cost is largely compensated by the time saved due to the lower usage of the I2C bus; for small (and I'd say even not so small) image changes the display update now appears to be istantaneous.

https://github.com/clci/sh1107g

Bye

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

Re: How to implement the buffer protocol

Post by pythoncoder » Sat Nov 21, 2020 10:12 am

Nice solution.
Peter Hinch
Index to my micropython libraries.

Post Reply