Epaper display driver

Hi falks,
i am new in this forum, first of all i wanted to congratulate you on the great job both for lvgl itself and porting it to micropython.

i want to know if is possible or already exist a driver for https://www.waveshare.com/product/displays/e-paper/epaper-3/1.54inch-e-paper-module-b.htm
the board used is stm32 - PYBD_SF6 official micropython board.

i found some drivers https://github.com/mcauser/micropython-waveshare-epaper/blob/master/epaper1in54b.py, how can i adapt them to lvgl needs?

have any of you experimented on this? or does it already have something I can try? or can you direct me on porting?

Thanks and regards,

Hi @Damiano_Mazzella, welcome!

No, currently this specific display is not supported.
But it should be relatively simple to create a display driver for LVGL.
See the docs for details about how to implement a display driver. You can implement it in either Python or C.
Let us know if you need any help or advice.

I can see that the driver you found has a set_pixel function. You can use it to implement set_px_cb of the LVGL display driver.
However, writing the image pixel by pixel in Micropython is going to be pretty slow… I would recommend either using some DMA engine or at least implementing the critical parts in C.

Somewhere in my task list there’s eInk display integration for ESP32, but not anytime soon.
If you create a display driver please consider creating a PR and contributing it back to LVGL!

For reference see LVGL docs and existing display drivers under lv_binding_micropython.

Thanks, as soon as I have something usable it will be my great pleasure to do a PR.

any advice on configuration in lv_conf.h to make the most of the eink display? colors to use etc?

Thanks again,

@kisvegabor @embeddedt is there somewhere an example of some C (non-micropython) LVGL project that uses eInk display?

Maybe this?

It depends largely on how the eInk display is configured in hardware. The Kobo e-reader which that port works with has an eInk display, but it essentially behaves like a framebuffer when interacting with it from userspace. (The main difference is that you have to send a framebuffer ioctl to get any changes reflected on the physical display.) As such, our fbdev driver can work unmodified on that platform.

micropython has framebuf module, can this module be used with lvgl?

import framebuf
buf = bytearray(200 * 200 // 8)
fb = framebuf.FrameBuffer(buf, 200, 200, framebuf.MONO_HLSB)


No, LVGL frame buffer and Micropython built-in frame buffer are unrelated.
And suppose there was a way to use the Micropython frame buffer in LVGL, do you have an eInk display driver for it?

the driver i found use framebuf

micropython-waveshare-epaper/epaper1in54b.py at 24c454cdd004c273d8dc3349ec365e87dec371ea · mcauser/micropython-waveshare-epaper (github.com)


micropython-waveshare-epaper/epaper1in54.py at 24c454cdd004c273d8dc3349ec365e87dec371ea · mcauser/micropython-waveshare-epaper (github.com)

No, sorry it use bytearray, use fb as container.

I am trying the integration with lvgl using the flush_cb function as shown in the example in the file ili9XXX.py but I can’t get it to work.

The basic driver I am using is https://github.com/mcauser/micropython-waveshare-epaper/blob/master/epaper1in54.py and this actually with the micropython framebuf module works fine, below the code

e = epaper1in54.EPD(spi, cs, dc, rst, busy)

w = 200
h = 200
x = 0
y = 0

buf = bytearray(200 * 200 // 8)
fb = framebuf.FrameBuffer(buf, 200, 200, framebuf.MONO_HLSB)
black = 0
white = 1
fb.text('Hello World',30,0,black)
fb.pixel(30, 10, black)
fb.hline(30, 30, 10, black)
fb.vline(30, 50, 10, black)
fb.line(30, 70, 40, 80, black)
fb.rect(30, 90, 10, 10, black)
fb.fill_rect(30, 110, 10, 10, black)
for row in range(0,25):
fb.text('Line 25',60,188,black)
e.set_frame_memory(buf, x, y, w, h)

and the rusult is this:

the code test i have user for lvgl is:

# st.lvstm32()

e = display.EPD(spi, cs, dc, rst, busy)

scr = lv.obj()
btn = lv.btn(scr)
btn.align(scr, lv.ALIGN.IN_TOP_MID, 0, 10)
label = lv.label(btn)
label.set_text('Hello World!')

while True:

the flush_cb i have used is this:

 def flush(self, disp_drv, area, color_p):
        # epaper1in54
        data_view = color_p.__dereference__(area.get_size())
        self._e.set_frame_memory(data_view, area.x1, area.y1, area.x2, area.y2)

        if disp_drv.flush_is_last():
            # epaper1in54

the result is this:

what am I doing wrong?

Thanks and regards,

In your working sample you call e.set_frame_memory (buf, x, y, w, h)

Your non working lvgl sample you call self._e.set_frame_memory (data_view, area.x1, area,y1, area,x2, area.y2)

w is not necessarily the same as area.x2 and h is not necessarily the same as area.y2

Into flush_cb the values are:

x1 0 y1 0 x2 199 y2 24
x1 0 y1 25 x2 199 y2 49
x1 0 y1 50 x2 199 y2 74
x1 0 y1 75 x2 199 y2 99
x1 0 y1 100 x2 199 y2 124
x1 0 y1 125 x2 199 y2 149
x1 0 y1 150 x2 199 y2 174
x1 0 y1 175 x2 199 y2 199

how this can help?

Thanks and regards,

Again, as far as I can see the function set_frame_memory expects a x and a y position
and width (w) and height (h)

But in flush_cb you provide x1 and y1 (which is ok) but you do not provide the width and height. You provide x2 and y2 (from area).
And this is not the width and not the height which set_frame_memory expects (needs!)

The width is calculated as (area.x2 - area.x1 + 1).
And the height is calculated as (area.y2 - area.y1 + 1).

So, for the first line of your traced data, this would be:
w = 199 - 0 + 1 ==> 200
h = 24 - 0 + 1 ==> 25