It seems the set_px_cp is used incorrectly. I assume display.drawPixel writes to the display directly, but the set pixel callback should set the pixel in buf assuming the buffer’s width is buf_w.
So something like (not tested):
uint32_t ofs = buf_w * y + x;
uint32_t byte_index = ofs / 2; // as there are 2 pixels on a byte
if(ofs & 1) {
//set the color on the lower part
buf[byte_index] &= 0xF0;
buf[byte_index] |= (color << 4);
} else {
//set the color on the upper part
buf[byte_index] &= 0x0F;
buf[byte_index] |= color;
}
Hello @kisvegabor
The drawPixel draws the pixel in the buffer only. With update is finally sending to the display, but many thanks for your reply.
Is now working better I just needed to add more buffer memory. I will look into @zapta answer maybe that’s a way to improve speed considerably.
Updated my fork to add Lilygo EPD47 touch controller that is L58 similar to FocalTech existing ones but with an INT pin ( low on event )
Hello @kisvegabor
I followed your approach and come a bit further
There is still something off, but is enough to render simple interfaces on epaper, I hope someone else can try it out and help with ideas.
I left here a quick way to try it:
Only requirement is an epaper display like Lilygo EPD047 or any other that is supported by EPDiy esp32 project. Thanks a lot for your help!
I’m really dissapointed by this Forum restrictions where you cannot even put a simple link on the content. Why such a restriction? If it’s to avoid spam I understand but at least links to github and similar should be allowed.
Hello @kisvegabor
I try to answer and then I will make some tests at home
where epd_hl_update_area is implemented?
epd_hl_update_area is implemented in EPDiy esp32 parallel driver for epapers. It’s part of the high level API of this driver. What it does is to refresh only that area of the display, all other parts remain untouched.
can you see any issue without lvgl? E.g. draw a 100x100 rectangle to x=10, y=10, clear the screen, draw it to 20,20, clear, 30,30 etc.
When using only EPDiy I can do this without any problem, and refresh only that part of the screen, it seems to works as expected (Both with full update or partial refresh)
If the above rectangle drawing works, use lvgl to create a button and please test if the touch area is on the button and or next to it.
I tried this also. On the first refresh the touch area seems placed correctly over the button. I can see it also in Serial when outputting x and y from the Touch driver I2C. On next refreshes, as you can see in the video, there is some kind of offset happening. In that case the touch is displaced and below the button some millimiters.
More than an issue with the touch for me it seems the partial update that is not happening correctly. The first rendering is always fine and when there is full refresh usually too, the widgets demo in slide mode, works great and I can see all including Charts being rendered properly on this fast parallel epaper. The problem seems to be when I use partial update.
Shall I try to make a rounder callback that forces always a full screen refresh to see if that is the problem?
Please try this too: Create a button and in its click event place the button to a different position. It should also trigger partial refresh but a more simple and easier to debug one. Does it work this way?
Please try this too: Create a button and in its click event place the button to a different position
Hello tried this and made a short video:
Updating the width is fine. Now if I try to change position it already messes up the framebuffer. That seems to be the issue. Initial drawing is fine.
Touch is working correctly. But redrawing elements that change position is a problem.
Awesome. I think now I realize what is going on. Printing x,y and area width/height on flush. Let’s say I make a button and make it just 10 px down:
lv_obj_set_pos(btn, 0, 10);
The button get’s printed correctly at first. Then I click on it, this first test just making it bigger, and it get’s printed again but this time at 0,0 (Is like if px_cb callback would draw it at 0,0 don’t understand why) Anyways the print to Serial reveals this:
epdiy_flush 2 x:0 y:10 w:960 h:42
Right x,y coordinates and right area since the button takes the whole width. But the buffer is filled from 0 to 42, instead of the 10 to 52 expected pixels. 2nd test doing a lv_obj_set_pos(btn, 0, 100); on the button callback:
epdiy_flush 4 x:0 y:98 w:960 h:46
Flush showing again right area to refresh. But it does not refresh anything the EPDiy library since the buffer in that area didn’t change.
Doing refreshes without LVGL and sending just squares with EPDiy and partial refresh correctly refreshes this areas.
I’m offering you to send a full pfledged Lilygo T5 E-Paper with touch for free to any address you desire if you feel like trying this out. I think it will be awesome to have a fast epaper where it’s possible to use LVGL and I will love to contribute to the project somehow.
cb_px callback debugging. Checking the first line outputting every x & y (%2==0) so it prints half, it reveals:
0 y0 c255 2 y0 c255 4 y0 c255 6 y0 c255 8 y0 c255 10 y0 c255 12 y0 c255 14 y0 c255 16 y0 c255 18 y0 c255 20 y0 c255 22 y0 c255 24 y0 c255 26 y0 c255 28 y0 c255 -> First lines up to Y10 they are color 255 (white) that is ok.
But then the top black line of the button is missing. And the whole button seems to be printed in the same place as before, skipping that 10 px offset. Very strange.
You use framebuffer but you should use the buf parameter. buf is relative to the current are being redrawn. So y = 0 means the first line of buf in flush_cb y will be 10 meaning to copy the buffer to y = 10 of framebuffer.
Very good find. But still there is something I don’t get, because framebuffer is really the global EPDiy buffer that is later send by parallel to the epaper. So if I use buf there, it will not update the framebuffer. Maybe if you can elaborate just some lines more I will get it:
//How can I update this below to use *buf
uint8_t *buf_ptr = &framebuffer[(int16_t)y * buf_w / 2 +(int16_t) x / 2];
if (x % 2) {
*buf_ptr = (*buf_ptr & 0x0F) | (epd_color & 0xF0);
} else {
*buf_ptr = (*buf_ptr & 0xF0) | (epd_color >> 4);
}
Basically what I don’t get is that LVGL does not know that buf is associated to framebuffer. This is part that I need to solve.
But it’s not a uint8_t* pointer right?
I tried but so far I’m getting a hardware reset. Maybe is there any existing driver that is doing this already so I can take a look?
I tried il3820.c that seems to be another epaper but is done differently there.
This is a function by the EPDiy component that copies a buffer into the big framebuffer. To debug it I also tried just to set each pixel that comes as 0 in the buf, just as test:
I will have to sit down with all this info and debug via Serial what is coming in buf from one side to the other. But so far you helped me a lot to understand how it is.
I just wish there was a simpler way to simply set a pixel in the buffer without having to do this from one function to the other. But I know is a complex thing to do!
If you set a rounder to full screen or in v8 you can set disp_drv.full_refresh = 1. THis way LVGL will always redraw to whole screen and you can use frambuffer as LVGL’s draw buffer so you don’t have to copy anything in flush_cb.