Open bland328 opened 2 months ago
I would tinker with the frequency some set it to 13Mhz and also try it at 12Mhz. That's what the problem looks like to me....
I am guessing I fixed the last compile problem yes?
another thing you have going on is this..
while True:
lslider.set_value(urandom.randint(0, 100), lv.ANIM.OFF)
rslider.set_value(urandom.randint(0, 100), lv.ANIM.OFF)
time.sleep_ms(1)
lv.tick_inc(1)
lv.task_handler()
if you have the refresh rate in LVGL set to 33 milliseconds then you are going all of the crazy changes when things are not getting updated on the display.
Try this instead
slider_1_inc = 1
slider_2_inc = -1
slider_1_value = 0
slider_2_value = 100
while True:
lslider.set_value(slider_1_value, lv.ANIM.OFF)
rslider.set_value(slider_2_value, lv.ANIM.OFF)
slider_1_value += slider_1_inc
if slider_1_value in (0, 100):
slider_1_inc = -slider_1_inc
slider_2_value += slider_2_inc
if slider_2_value in (0, 100):
slider_2_inc = -slider_2_inc
lv.refr_now(lv.display_get_default())
time.sleep_ms(10)
lv.tick_inc(10)
lv.task_handler()
I have been looking at that animation you posted and from what I am seeing is you need to have the frequency set to 12Mhz.
Yes, the build is great now, thank you very much.
12MHz doesn't work at all--all frequencies I've tried below 12.2MHz throw the screen into some sort of demo mode that slowly cycles forever through full-screen black, white, red, green, and blue.
I settled on 12.5MHz after seeing that this project defines the frequency for this specific board as (12.5*1000000)
, and hoping they knew something I didn't.
For the record, I haven't changed #define LV_DEF_REFR_PERIOD 33
in lv_conf.h
.
Lastly, the code you provided doesn't appear to affect the glitching:
do me a favor and render a single horizontal bar across the display. I am curious to see how that looks.
Are you compiling with the board set to ESP32_GENERIC_S3 and the bopard variant set to SPIRAM_OCT???
also try using just a single frame buffer and see how it does.
I have a display here that is 800 x 480 using an ESP32 and I am not getting that behavior. It's gotta be something with the vertical refresh or the horizontal refresh that is causing it.
There is it. You have a setting that's not right.
pclk_active_low
in the bus should be set to `True'
So the clock isn't going to work properly and that would result in a flicker.
There is it. You have a setting that's not right.
Thanks for catching the missing pclk_active_low=True
, but sadly, it didn't change anything.
Are you compiling with the board set to ESP32_GENERIC_S3 and the bopard variant set to SPIRAM_OCT???
Yes, I'm building with ESP32_GENERIC_S3
and SPIRAM_OCT
.
do me a favor and render a single horizontal bar across the display.
I hope this is what you wanted to see. I let it run for quite a while, and didn't spot any glitches:
also try using just a single frame buffer and see how it does.
With _BUF2 = None
, the effect is similar, but worse; the left slider also glitches, and the glitches are exaggerated:
OK so take the vertical example and make the sliders smaller in size. Like 50 x 300 and see is the glitching stops.
I am trying to isolate if this is an LVGL problem or a display/driver problem. Another test is to make 2 bars that are 700 x 50.
so let me give you a little bit of a skinny as to what I believe is happening. MicroPython has a large amount of boiler plate code that has to run and that is going to slow things down. I think what we are seeing is because of speed related issue. RGB Displays don't have any GRam to store data. the information is getting written directly to the display. The buffers are in a constant state of being sent to the display using DMA memory. because both buffers are allocated in SPI RAM the large amount of data that is being written by LVGL is causing issues with the data being read from the memory and written to the display.
I believe I might have a solution to this problem.
OK so take the vertical example and make the sliders smaller in size.
I tried that very thing (though not 50 x 300) just before reading your reply, and the results are interesting--no glitching, except when updating the upper-right corner:
Another test is to make 2 bars that are 700 x 50
Did exactly that, and saw no glitches.
I think what we are seeing is because of speed related issue. RGB Displays don't have any GRam...I believe I might have a solution to this problem.
That's great! And I'm happy to test whatever you'd care to send my way, naturally.
EDIT: I just tried the two 50 x 300 sliders you suggested, and see no glitches at all.
But, if I change that to 50 x 480, I get near-constant glitching in the upper right:
EDIT 2: In case you haven't already seen it, this thread discussing ESP32-S3, PSRAM throughput issues and bounce buffers may be applicable.
OK I changed a few things so hopefully it should work better. Give it a try...
the issue with using bounce buffers is the really large amount of work that needs to be done by the CPU to copy buffers.
I am thinking the tearing you are getting is being caused by LVGL and calling lv_display_flush_ready. That gets called when the buffer has finished being written. When using DMA memory the writing of the buffer is not using the CPU it is being done via a DMA transfer. That means the CPU is able to go along it's merry way. So while one buffer is being emptied the other one can be filled. If the filling takes less time than the emptying that flag doesn't get set to allow LVGL to flush the second buffer. So what happens is the one core on the processor goes into a spinning wheels state because LVGL uses a while loop until the flush ready function gets called. This is where the hangup is. the flush ready gets called from inside Python code, so in order to make that call it has to be done outside of an ISR. so now the ISR has to contend with switching into the main thread that is spinning wheels. It has to try and sneak the function call in there between a loop in the LVGL code. That is where I believe the tearing is coming from.
So what I did is call the python function right after the color gets written to the display so it doesn't happen inside of an ISR context any more. I use a couple of semaphores to control when the data actually gets passed off to be written. the semaphores don't cause a spinning wheel so the core doesn't peg out to 10% usage.
I am hoping that this is what was causing your issue. I feel pretty good about this being the solution. I really do hope it is otherwise I am at a loss for what could be causing the problem.
how are you capturing the output??? are you recording the video using your phone?
If you are and the rig is 100% stationary and not movinbg at al then I am going to really say that is is going to be an hsync and/or vsync setting that is off. The reason why is because look closely at the videos. The entire GUI is moving in what looks like a figure 8 pattern.
Take a look at
these 2 frames. Clock on them in order to blow them up so you can see what I am talking about.
Look at the red rectangle I drew and look at how far away it is from the edges In one capture the left side has a large amount of black and i the other it is a whole lot skinnier.
I am almost 100% sure that the frequency is off a little bit. I would adjust it up or down by 100 at a time and watch the display for that shifting. You should be able to dial it in closer. If you cannot do it wit the frequency then you will need to adjust the hsync and vsync settings. Start with one of them and make a wild change to see what it does. so you have an idea if that setting would be able to correct it.
IDK if you have your github set to the dark theme or not. If you do then you 100% have to click on each image to see what I am talking about.
how are you capturing the output??? ... If you are and the rig is 100% stationary ....
Sorry for the mislead, but It is 100% handheld, so the drifting is me. In person, the image doesn't drift at all. If I shoot any more video, I'll come up with a stationary rig.
OK I changed a few things so hopefully it should work better. Give it a try...
I made a fresh clone, and getting these errors:
/Users/brian/code/esp-idf/lvgl_micropython/ext_mod/lcd_bus/esp32_src/rgb_bus.c: In function 'rgb_bus_trans_done_cb':
/Users/brian/code/esp-idf/lvgl_micropython/ext_mod/lcd_bus/esp32_src/rgb_bus.c:55:5: error: parameter 'callbacks' is initialized
55 | esp_lcd_rgb_panel_event_callbacks_t callbacks = { .on_vsync = rgb_bus_trans_done_cb };
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/Users/brian/code/esp-idf/lvgl_micropython/ext_mod/lcd_bus/esp32_src/rgb_bus.c:67:5: error: expected '=', ',', ';', 'asm' or '__attribute__' before '{' token
67 | {
| ^
/Users/brian/code/esp-idf/lvgl_micropython/ext_mod/lcd_bus/esp32_src/rgb_bus.c:226:5: error: expected '=', ',', ';', 'asm' or '__attribute__' before '{' token
226 | {
| ^
/Users/brian/code/esp-idf/lvgl_micropython/ext_mod/lcd_bus/esp32_src/rgb_bus.c:234:5: error: expected '=', ',', ';', 'asm' or '__attribute__' before '{' token
234 | {
| ^
/Users/brian/code/esp-idf/lvgl_micropython/ext_mod/lcd_bus/esp32_src/rgb_bus.c:243:5: error: expected '=', ',', ';', 'asm' or '__attribute__' before '{' token
243 | {
| ^
/Users/brian/code/esp-idf/lvgl_micropython/ext_mod/lcd_bus/esp32_src/rgb_bus.c:252:5: error: expected '=', ',', ';', 'asm' or '__attribute__' before '{' token
252 | {
| ^
/Users/brian/code/esp-idf/lvgl_micropython/ext_mod/lcd_bus/esp32_src/rgb_bus.c:276:5: error: expected '=', ',', ';', 'asm' or '__attribute__' before '{' token
276 | {
| ^
/Users/brian/code/esp-idf/lvgl_micropython/ext_mod/lcd_bus/esp32_src/rgb_bus.c:354:5: error: expected '=', ',', ';', 'asm' or '__attribute__' before '{' token
354 | {
| ^
/Users/brian/code/esp-idf/lvgl_micropython/ext_mod/lcd_bus/esp32_src/rgb_bus.c:440:5: error: expected '=', ',', ';', 'asm' or '__attribute__' before '{' token
440 | {
| ^
/Users/brian/code/esp-idf/lvgl_micropython/ext_mod/lcd_bus/esp32_src/rgb_bus.c:447:5: error: expected '=', ',', ';', 'asm' or '__attribute__' before '{' token
447 | {
| ^
/Users/brian/code/esp-idf/lvgl_micropython/ext_mod/lcd_bus/esp32_src/rgb_bus.c:484:5: error: expected '=', ',', ';', 'asm' or '__attribute__' before '{' token
484 | {
| ^
/Users/brian/code/esp-idf/lvgl_micropython/ext_mod/lcd_bus/esp32_src/rgb_bus.c:501:5: error: parameter 'mp_lcd_rgb_bus_type' is initialized
501 | MP_DEFINE_CONST_OBJ_TYPE(
| ^~~~~~~~~~~~~~~~~~~~~~~~
In file included from /Users/brian/code/esp-idf/lvgl_micropython/ext_mod/lcd_bus/lcd_types.h:7,
from /Users/brian/code/esp-idf/lvgl_micropython/ext_mod/lcd_bus/esp32_src/rgb_bus.c:6:
/Users/brian/code/esp-idf/lvgl_micropython/ext_mod/lcd_bus/esp32_src/rgb_bus.c:505:19: error: 'mp_lcd_rgb_bus_make_new' undeclared (first use in this function); did you mean 'mp_lcd_rgb_bus_type'?
505 | make_new, mp_lcd_rgb_bus_make_new,
| ^~~~~~~~~~~~~~~~~~~~~~~
/Users/brian/code/esp-idf/lvgl_micropython/lib/micropython/py/obj.h:785:44: note: in definition of macro 'MP_DEFINE_CONST_OBJ_TYPE_EXPAND'
785 | #define MP_DEFINE_CONST_OBJ_TYPE_EXPAND(x) x
| ^
/Users/brian/code/esp-idf/lvgl_micropython/lib/micropython/py/obj.h:789:179: note: in expansion of macro 'MP_DEFINE_CONST_OBJ_TYPE_NARGS_2'
789 | #define MP_DEFINE_CONST_OBJ_TYPE_NARGS(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, N, ...) MP_DEFINE_CONST_OBJ_TYPE_NARGS_##N
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/Users/brian/code/esp-idf/lvgl_micropython/ext_mod/lcd_bus/esp32_src/rgb_bus.c:501:5: note: in expansion of macro 'MP_DEFINE_CONST_OBJ_TYPE'
501 | MP_DEFINE_CONST_OBJ_TYPE(
| ^~~~~~~~~~~~~~~~~~~~~~~~
/Users/brian/code/esp-idf/lvgl_micropython/ext_mod/lcd_bus/esp32_src/rgb_bus.c:505:19: note: each undeclared identifier is reported only once for each function it appears in
505 | make_new, mp_lcd_rgb_bus_make_new,
| ^~~~~~~~~~~~~~~~~~~~~~~
/Users/brian/code/esp-idf/lvgl_micropython/lib/micropython/py/obj.h:785:44: note: in definition of macro 'MP_DEFINE_CONST_OBJ_TYPE_EXPAND'
785 | #define MP_DEFINE_CONST_OBJ_TYPE_EXPAND(x) x
| ^
/Users/brian/code/esp-idf/lvgl_micropython/lib/micropython/py/obj.h:789:179: note: in expansion of macro 'MP_DEFINE_CONST_OBJ_TYPE_NARGS_2'
789 | #define MP_DEFINE_CONST_OBJ_TYPE_NARGS(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, N, ...) MP_DEFINE_CONST_OBJ_TYPE_NARGS_##N
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/Users/brian/code/esp-idf/lvgl_micropython/ext_mod/lcd_bus/esp32_src/rgb_bus.c:501:5: note: in expansion of macro 'MP_DEFINE_CONST_OBJ_TYPE'
501 | MP_DEFINE_CONST_OBJ_TYPE(
| ^~~~~~~~~~~~~~~~~~~~~~~~
/Users/brian/code/esp-idf/lvgl_micropython/lib/micropython/py/obj.h:759:243: error: non-static initialization of a flexible array member
759 | #define MP_DEFINE_CONST_OBJ_TYPE_NARGS_2(_struct_type, _typename, _name, _flags, f1, v1, f2, v2) const _struct_type _typename = { .base = { &mp_type_type }, .name = _name, .flags = _flags, .slot_index_##f1 = 1, .slot_index_##f2 = 2, .slots = { v1, v2, } }
| ^
/Users/brian/code/esp-idf/lvgl_micropython/lib/micropython/py/obj.h:785:44: note: in definition of macro 'MP_DEFINE_CONST_OBJ_TYPE_EXPAND'
785 | #define MP_DEFINE_CONST_OBJ_TYPE_EXPAND(x) x
| ^
/Users/brian/code/esp-idf/lvgl_micropython/lib/micropython/py/obj.h:789:179: note: in expansion of macro 'MP_DEFINE_CONST_OBJ_TYPE_NARGS_2'
789 | #define MP_DEFINE_CONST_OBJ_TYPE_NARGS(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, N, ...) MP_DEFINE_CONST_OBJ_TYPE_NARGS_##N
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/Users/brian/code/esp-idf/lvgl_micropython/lib/micropython/py/obj.h:798:71: note: in expansion of macro 'MP_DEFINE_CONST_OBJ_TYPE_NARGS'
798 | #define MP_DEFINE_CONST_OBJ_TYPE(...) MP_DEFINE_CONST_OBJ_TYPE_EXPAND(MP_DEFINE_CONST_OBJ_TYPE_NARGS(__VA_ARGS__, _INV, 12, _INV, 11, _INV, 10, _INV, 9, _INV, 8, _INV, 7, _INV, 6, _INV, 5, _INV, 4, _INV, 3, _INV, 2, _INV, 1, _INV, 0)(mp_obj_type_t, __VA_ARGS__))
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/Users/brian/code/esp-idf/lvgl_micropython/ext_mod/lcd_bus/esp32_src/rgb_bus.c:501:5: note: in expansion of macro 'MP_DEFINE_CONST_OBJ_TYPE'
501 | MP_DEFINE_CONST_OBJ_TYPE(
| ^~~~~~~~~~~~~~~~~~~~~~~~
/Users/brian/code/esp-idf/lvgl_micropython/lib/micropython/py/obj.h:759:243: note: (near initialization for 'mp_lcd_rgb_bus_type')
759 | #define MP_DEFINE_CONST_OBJ_TYPE_NARGS_2(_struct_type, _typename, _name, _flags, f1, v1, f2, v2) const _struct_type _typename = { .base = { &mp_type_type }, .name = _name, .flags = _flags, .slot_index_##f1 = 1, .slot_index_##f2 = 2, .slots = { v1, v2, } }
| ^
/Users/brian/code/esp-idf/lvgl_micropython/lib/micropython/py/obj.h:785:44: note: in definition of macro 'MP_DEFINE_CONST_OBJ_TYPE_EXPAND'
785 | #define MP_DEFINE_CONST_OBJ_TYPE_EXPAND(x) x
| ^
/Users/brian/code/esp-idf/lvgl_micropython/lib/micropython/py/obj.h:789:179: note: in expansion of macro 'MP_DEFINE_CONST_OBJ_TYPE_NARGS_2'
789 | #define MP_DEFINE_CONST_OBJ_TYPE_NARGS(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, N, ...) MP_DEFINE_CONST_OBJ_TYPE_NARGS_##N
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/Users/brian/code/esp-idf/lvgl_micropython/lib/micropython/py/obj.h:798:71: note: in expansion of macro 'MP_DEFINE_CONST_OBJ_TYPE_NARGS'
798 | #define MP_DEFINE_CONST_OBJ_TYPE(...) MP_DEFINE_CONST_OBJ_TYPE_EXPAND(MP_DEFINE_CONST_OBJ_TYPE_NARGS(__VA_ARGS__, _INV, 12, _INV, 11, _INV, 10, _INV, 9, _INV, 8, _INV, 7, _INV, 6, _INV, 5, _INV, 4, _INV, 3, _INV, 2, _INV, 1, _INV, 0)(mp_obj_type_t, __VA_ARGS__))
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/Users/brian/code/esp-idf/lvgl_micropython/ext_mod/lcd_bus/esp32_src/rgb_bus.c:501:5: note: in expansion of macro 'MP_DEFINE_CONST_OBJ_TYPE'
501 | MP_DEFINE_CONST_OBJ_TYPE(
| ^~~~~~~~~~~~~~~~~~~~~~~~
/Users/brian/code/esp-idf/lvgl_micropython/ext_mod/lcd_bus/esp32_src/rgb_bus.c:54:17: error: old-style parameter declarations in prototyped function definition
54 | static bool rgb_bus_trans_done_cb(esp_lcd_panel_handle_t panel, const esp_lcd_rgb_panel_event_data_t *event_data, void *user_data)
| ^~~~~~~~~~~~~~~~~~~~~
/Users/brian/code/esp-idf/lvgl_micropython/ext_mod/lcd_bus/esp32_src/rgb_bus.c:512: error: expected '{' at end of input
/Users/brian/code/esp-idf/lvgl_micropython/ext_mod/lcd_bus/esp32_src/rgb_bus.c:501:5: error: no return statement in function returning non-void [-Werror=return-type]
501 | MP_DEFINE_CONST_OBJ_TYPE(
| ^~~~~~~~~~~~~~~~~~~~~~~~
cc1: some warnings being treated as errors
The build is working, and I have mixed results.
WIth 50x480 sliders, the glitching is now gone(!), but with 225x480 sliders it is still happening:
EDIT: Hoping it might spark something, I'll mention this ESP-IDF fork featuring esp_lcd_rgb_panel.c
changes that the creator describes like this:
I have now achieved a “non-streaming” trigger-by-code method. I turned off the VSYNC interrupts and call the lcd_rgb_panel_start_transmission function to trigger each redraw. Using this modified code, in my program I finish updating the FrameBuffer, and then trigger the LCD peripheral to redraw to the display. This eliminated the “tearing” that occurs when using the “stream_mode” with continuous refresh.
My understanding is that some updates of the RGB display are actually delayed in the case that framebuffer changes aren't yet complete, resulting in a subtly-inconsistent redraw frequency, but no glitching.
I believe the issue you are having now is because of processor power and the size of the display that is connected. the ESP32 is not really the best choice when using a display that has a resolution of 800 x 480. While it will work when not needing to make huge rendering changes it is not suited to have to redraw the entire display over and over again.
If you ran this as the loop the tearing might go away.
slider_1_inc = 1
slider_2_inc = -1
slider_1_value = 0
slider_2_value = 100
while True:
lslider.set_value(slider_1_value, lv.ANIM.OFF)
lv.refr_now(lv.display_get_default())
slider_1_value += slider_1_inc
if slider_1_value in (0, 100):
slider_1_inc = -slider_1_inc
rslider.set_value(slider_2_value, lv.ANIM.OFF)
lv.refr_now(lv.display_get_default())
slider_2_value += slider_2_inc
if slider_2_value in (0, 100):
slider_2_inc = -slider_2_inc
time.sleep_ms(10)
lv.tick_inc(10)
lv.task_handler()
you can see the delay between the 2 videos you posted. That delay is being caused by the amount of time it is taking LVGL to render. The only difference in code between those 2 videos is the size of the bar. larger widget = long to draw when changes occur.
Thanks very much for all your work chasing this!
I believe the issue you are having now is because of processor power and the size of the display that is connected.
Makes perfect sense to me. I'd love to see what would happen if screen redraws could be suspended while framebuffers are being updated, but I suppose that might result in full-screen flickering.
If you ran this as the loop the tearing might go away.
I ran it, and it does eliminate the glitching! However, it also introduces some mild full-screen flickering, and results in some occasional stuttering in the movement of the slider knobs.
I grasp why your code eliminates the glitching, and how that could in turn introduce a bit of stuttering in the movement of the knobs, but I don't quite grasp the flickering--might that be because some screen redraws are missed due to the 10ms sleep? I'm not sure I'm picturing the overall flow correctly there.
It's all about the work being done.
I might be able to eliminate the tearing if a 3rd frame buffer is introduced. I would have to play round robin with them swapping the pointers around but it is going to consume even more memory to do that.
Try this as your looping code and see if it works.
slider_1_inc = 1
slider_2_inc = -1
slider_1_value = 0
slider_2_value = 100
while True:
lslider.set_value(slider_1_value, lv.ANIM.OFF)
slider_1_value += slider_1_inc
if slider_1_value in (0, 100):
slider_1_inc = -slider_1_inc
rslider.set_value(slider_2_value, lv.ANIM.OFF)
slider_2_value += slider_2_inc
if slider_2_value in (0, 100):
slider_2_inc = -slider_2_inc
time.sleep_ms(33)
lv.tick_inc(33)
lv.task_handler()
forcing so many updates could be causing some of the issue. Maybe the tearing is coming from the call to task handler. The next bit of code I want you to test is this one...
slider_1_inc = 1
slider_2_inc = -1
slider_1_value = 0
slider_2_value = 100
import time
while True:
start_time = time.ticks_ms()
lslider.set_value(slider_1_value, lv.ANIM.OFF)
lv.refr_now(lv.display_get_default())
slider_1_value += slider_1_inc
if slider_1_value in (0, 100):
slider_1_inc = -slider_1_inc
rslider.set_value(slider_2_value, lv.ANIM.OFF)
lv.refr_now(lv.display_get_default())
slider_2_value += slider_2_inc
if slider_2_value in (0, 100):
slider_2_inc = -slider_2_inc
stop_time = time.ticks_ms()
lv.tick_inc(time.tick_diff(stop_time, start_time))
Try this as your looping code and see if it works.
That code reintroduces the glitching in the right-hand slider, the result looking like the most recent clip above.
how about the second one?
It could be the task_handler that is inducing the flicker for some reason.
That is why I want you to try the second example. The refr_now's should force the redraw.
There is one last test I want you to run if the flicker is gone with the last code block I posted.
Run this if there is no flicker.
slider_1_inc = 1
slider_2_inc = -1
slider_1_value = 0
slider_2_value = 100
import time
while True:
start_time = time.ticks_ms()
lslider.set_value(slider_1_value, lv.ANIM.OFF)
slider_1_value += slider_1_inc
if slider_1_value in (0, 100):
slider_1_inc = -slider_1_inc
rslider.set_value(slider_2_value, lv.ANIM.OFF)
slider_2_value += slider_2_inc
if slider_2_value in (0, 100):
slider_2_inc = -slider_2_inc
lv.refr_now(lv.display_get_default())
stop_time = time.ticks_ms()
lv.tick_inc(time.tick_diff(stop_time, start_time))
The next bit of code I want you to test is this one...
These results are interesting. The full-screen flicker is gone, and there's none of the ugly glitching.
The only flaw now is what I would call true "tearing" on the leading/trailing knob edges--I increased the step size to 10% so it is easier to see here:
I'll run the other code you sent shortly...
There is one last test I want you to run if the flicker is gone with the last code block I posted. Run this if there is no flicker.
With the most recent code you sent, there's still no flicker, but the severe glitching in the right-hand slider (like this) returns.
OK so next step.
Give this a try.
slider_1_inc = 1
slider_2_inc = -1
slider_1_value = 0
slider_2_value = 100
import time
update_start_time = time.ticks_ms()
start_time = time.ticks_ms()
while True:
if time.tick_diff(time.ticks_ms(), update_start_time) >= 10:
update_start_time = time.ticks_ms()
lslider.set_value(slider_1_value, lv.ANIM.OFF)
lv.refr_now(lv.display_get_default())
slider_1_value += slider_1_inc
if slider_1_value in (0, 100):
slider_1_inc = -slider_1_inc
rslider.set_value(slider_2_value, lv.ANIM.OFF)
lv.refr_now(lv.display_get_default())
slider_2_value += slider_2_inc
if slider_2_value in (0, 100):
slider_2_inc = -slider_2_inc
stop_time = time.ticks_ms()
if time.tick_diff(stop_time, start_time) < 1:
time.sleep_ms(1)
continue
lv.tick_inc(time.tick_diff(stop_time, start_time))
start_time = time.ticks_ms()
That link you gave for the RGB driver. That was before the bounce buffer ability was added to the ESPIDF. A lot of that code has been added to ESPIDF 5.0. That code is also for using a bounce buffer. The problem that is occuring are the large areas of the screen needing to be rendered in LVGL and then that area has to be copied from one buffer to the other. The organization of when things are done in LVGL is what I think is causing the hangup.
I opened an issue with LVGL to discuss it.
OK so next step. Give this a try.
Looks good, except for the occasional tearing on knob leading/trailing areas, just like this previous result (but moving just one pixel at a time, in this case).
...The organization of when things are done in LVGL is what I think is causing the hangup.
Ah, got it. Thanks very much for the explanation!
Now the most ideal thing with the RGB is to not have any sleeps or moments where the program stalls.
When dealing with RGB since there is no GRAM as soon as the buffer finishes emptying it needs to start sending the data again. It doesn't matter if the data is the same data or changed data there needs to be no stall between the 2.
I am going to see if I am able to work around the problem by using the second core to manage passing the frame buffer to be rendered to the RGB driver in the ESP_IDF. I think this will only work if there is a 3rd frame buffer involved tho.
Before I do that I am going to modify a file in LVGL and I will have you put that file into LVGL and build it again. I think that a simple reorganization of when the different tasks are performed would solve the problem.
Give this file a go. It is located in lib/lvgl/src/core
You have to remove the .txt
from the end of the file name. I would add a .bak
to the original file in case it doesn't work for ya.
I did compile and it does compile without any errors. IDK if it will work tho.
How the design worked originally is it would do all the rendering to the buffer and then flush the buffer to the display. It would sit there and wait until the buffer was finished being flushed and then it would copy the data from the buffer that was just flushed to the other buffer so the rendering could take place.
The whole point of DMA is to be able to do something while the flushing is taking place, not to sit there doing nothing.
So what I did is I moved the flush callback to being done first then I swap the buffers around and copy the data from the buffer that is being sent to the display to the other buffer. I then render to the second buffer while the first one is still being sent.
I did put a wait before flushing the buffer just in the event it does take longer to send the buffer data then it takes for LVGL to copy and render.
There is still some tweaking I can do to make it run faster so if we see an improvement I will make those changes.
It doesn't matter if the data is the same data or changed data there needs to be no stall between the 2.
Thanks for the detailed explanation. And if there is a stall, is that when the full-screen flicker occurs?
So what I did is...
Very crafty. I admire your skill and dedication.
There is still some tweaking I can do...
Excellent. I'll test the new file now.
I'm running into this build error, even after recloning and starting from scratch:
/Users/brian/code/esp-idf/lvgl_micropython/lib/lvgl/src/core/lv_refr.c: In function 'refr_obj':
/Users/brian/code/esp-idf/lvgl_micropython/lib/lvgl/src/core/lv_refr.c:999:27: error: 'lv_draw_image_dsc_t' {aka 'struct _lv_draw_image_dsc_t'} has no member named 'original_area'
999 | layer_draw_dsc.original_area = obj_draw_size;
| ^
did you delete the entire thing and clone it again?
I have to get the guys over at LVGL to make the change I am thinking will improve things. I will spend more time trying to figure it out than asking one of them to do it.
did you delete the entire thing and clone it again?
Yes. Builds fine until I inject the file you sent. I don't find any other references to original_area
in the entire repo, FYI.
I have to get the guys over at LVGL to make the change I am thinking will improve things. I will spend more time trying to figure it out than asking one of them to do it.
If there's anything I can post to bolster your request, I'm happy to.
it's ok. I tested it here locally and it didn't work. I made some more changes and compiled it a few more times and I kept on getting segfaults. I just sent a private message to the head guy over at LVGL. I added the videos you posted to show what was going on. He will know how to get rid of that wait or move it to a different area.
The error you were getting was because the file i modified and sent to you is from a earlier commit to LVGL. The file had been changed after that which is why you are getting the error.
I just sent a private message to the head guy over at LVGL. I added the videos you posted to show what was going on.
Great--fingers crossed. In the meanwhile, if you come up with anything else for me to test, I'm happy to.
The fix is in the works.
The fix is in the works.
Impressively quick! Thanks for the update.
in discussion about what else is able to be changed in order to streamline the process to speed it up. In the mean time you can delete line 386 from lib/lvgl/src/core/lv_refr.c
This should help somewhat. It has been tested that removing that does improve things.
you can delete line 386 ... It has been tested that removing that does improve things.
I made that change, but I'm not sure how to best test against it.
So far, I find that if I keep calling lv.refr_now()
after changing each slider value, nothing changed--it works fundamentally well, with just a little tearing on the leading and trailing edges of the knobs.
And if I return to calling lv.task_handler()
just once per cycle, the glitching returns and the slider knobs move so fast that most positions are never rendered, so they appear to be bouncing around randomly (that is, instead of taking 23 seconds to travel from 0-100%, they take about 1 second).
What testing approach would be most meaningful after removing line 386 from lv_refr.c
?
try this..
slider_1_inc = 1
slider_2_inc = -1
slider_1_value = 0
slider_2_value = 100
import time
while True:
time.sleep_ms(10)
start_time = time.ticks_ms()
lslider.set_value(slider_1_value, lv.ANIM.OFF)
slider_1_value += slider_1_inc
if slider_1_value in (0, 100):
slider_1_inc = -slider_1_inc
rslider.set_value(slider_2_value, lv.ANIM.OFF)
slider_2_value += slider_2_inc
if slider_2_value in (0, 100):
slider_2_inc = -slider_2_inc
stop_time = time.ticks_ms()
print('updating widget:', time.tick_diff(stop_time, start_time))
start_time = time.ticks_ms()
lv.refr_now(lv.display_get_default())
stop_time = time.ticks_ms()
print('refr time:', time.tick_diff(stop_time, start_time))
print()
lv.tick_inc(10)
post the output to me. I am interested in knowing how much time it takes to update the widgets and to refresh the display.
post the output to me. I am interested in knowing how much time it takes to update the widgets and to refresh the display.
All testing was with line 386 of lv_refr.c
commented out.
The code as you provided it glitches severely on the right, much like this previous post.
Here's the output for two trips across the screen, with glitching: widget_updates_with_glitches_01.txt
After running that, I added an additional lv.refr_now()
call before setting the value for slider 2, like this:
lv.refr_now(lv.display_get_default())
rslider.set_value(slider_2_value, lv.ANIM.OFF)
That additional lv.refr_now()
call eliminates the glitches (leaving just the gentle tearing as shown here), and results in this output:
widget_updates_without_glitches_02.txt
OK that is what I have thought. it takes 2 times longer to run.
OK that is what I have thought. it takes 2 times longer to run.
I just want to make sure you're clear that those two tests were both with line 386 of lv_refr.c
commented out--the only difference between them is my addition of another lv.refr_now()
call to cure the glitching.
Would you also like the timing output of a run with line 386 still in place? Or do you have all the information you wanted?
I'm unable to determine why display updates often flash and glitch, even though I'm (hopefully appropriately) using double buffering.
With apologies for the handheld video, there's what I'm seeing when I run the test code below. Any suggestions are greatly appreciated, as
lvgl_micropython
is otherwise working very well for me at this point.FWIW, if I animate only one of the two sliders, there's rarely (if ever) any issue.