@bdbarnett Yes, I have already compiled micropython 1.21 with lvgl from @kdschlosser repository. The firmware has two bus drivers for i8080 and SPI. Is there a display driver for working with lvgl via the I80Bus? I can check it on wt32 sc-01 plus (esp32s3 with SPIRAM)
I have that board too, and @kdschosserās i80 driver works with it. You still need the display specific MicroPython parts to instantiate and use it. Iām cleaning up my code now. Iāll try to have it posted tomorrow night. With Christmas coming up, I donāt know exactly when Iāll get it up there, but Iāll hurry.
@bdbarnett I will be very happy about this
@bdbarnett you probably forgot about me?)
No sir. There are a lot of moving parts here. I should have the configs up tomorrow. However, you wonāt be able to use them just yet. @kdschlosserās drivers are working, but heās still hammering out some issues with the LVGL bindings that arenāt driver related. Please be patient, especially since itās holiday season.
I spent the last 8 hours or so going over the gen_mpy script in order to generate the data that is needed to leverage the LVGL documentation to build a stub file and generate documentation that is specific to the MicroPython binding. I have made really good progress with it. I have to tackle exposing the attributes and functions for non object public structures. The only thing that was provided in the original script was the name of the structure after it has been mangled by the gen_mpy script.
I found a really large flaw in the script. I pasted the code below and you will understand the problem.
I had mentioned on several occasions the inconsistency of the API with regards to the methods. It fell upon deaf ears and never got any traction. I believe this is the cause.
def is_method_of(func_name, obj_name):
return func_name.lower().startswith('{prefix}_{obj}_'.format(prefix=module_prefix, obj=obj_name).lower())
In the binding lv_image_t gets turned into the following
class image(obj):
...
The test that is done to see if an LVGL function should get paired to the class is it check to see if the function name (minus the ālv_ā) begins with the class name.
Now that doesnāt seem like it would cause an issue right?
Here are some functions that end up getting paired to that class that shouldnāt be.
lv_image_decoder_get_info
lv_image_header_init
I discover this once I manages to get the JSON output shrunk down from 80mb in size to 800k in size and removed all of the duplicate functions added to every single class that gets generated. Each class had over 400 functions in it and the majority of the functions were duplicates of what is in the obj
class even tho the obj
class is the parent class of the classes that contained the duplicate entries. I added a single element to the JSON data that specifies the parent class because that is what needs to be known when building the stub file and documentation.
Once I got all those cleaned up the number of functions specific to the different subclasses of obj
shrunk to only a small handful. It was easy to see this was happening once I loaded the data into a JSON viewer to inspect it for correctness.
The gen_mpy script iterates over the functions and collects the functions where the name ends in ācreateā. It then strips off the ālv_ā and the ācreate" to come up with the name of the object. It then tests that the first parameter has a type name of "lv{name}_tā and if it does the generated name gets stored. That generated name is only used against the function names to determine if the function is a method of a class. There is no check done on the first parameter type of the function to make sure it is where it belongs. That is what I am going to have to add. If the first parameter is not the correct type then it is not a method of that class.
OK so the lv.init
problem has been sorted out. There is another issue and I am not sure if you have had the problem. it deals with the callback that is used when lv_flush_ready is called. it seems that a recursion error happens. Can you test that for me and see if that happens for you as well?
I can, but only on Tuesday.
@kdschlosser @Alexandr Itās working! I posted the configs here.
Thatās awesome news about gen_mpy.py. Iām excited to have MicroPython specific documentation for LVGL!!! Thank you for you work!
@kdschlosser @bdbarnett Itās working!
Initialization is successful! Test case driver without lvgl works well. In the test example with LVGL I get the error:
This error get only soft reboot! Hard reboot work is well and showing 9 buttons!
Iām glad itās working for you. It requires a hard reboot between initializing the display with either board_config or lv_config because a soft reboot doesnāt free up the display bus. Initializing the display calls
display_bus.init
Thatās what is failing for you because it is already initialized.
Is your touchscreen working too?
Yes, touchscreen working.
@bdbarnett There is a problem with touch_ratation 0ā¦7. The get_touched function also needs to perform the _swap_xy check after the _invert_x and _invert_y checks.
if self._touch_rotation is not None:
if self._invert_x:
x = self._max_x - x
if self._invert_y:
y = self._max_y - y
if self._swap_xy:
x, y = y, x
I havenāt tested that fully and suspected it might need tweaking. Can you tell me what issue youāre having?
The way it is written, all 3 checks happen on every touch point. There arenāt any elseās and the 3 ifs are at the same indention level. I think that part is correct, but if itās not doing what you need, let me know the details so I can try to duplicate it.
@bdbarnett The problem was
in rotating an image from portrait to landscape. I thought the problem was just touch_rotation, but the problem is deeper.
In the ST7796 driver width=320 and height=480, I changed the rotation=-2 (LANDSCAPE) property and the image was rotated, but I still have to change the DisplayDriver constructor, because self._disp_drv = lv.display_create(self.display.width, self.display.height).
In general, itās difficult to explain. To rotate the image in this implementation you need to correct several places
I think I see what youāre saying. Currently, when you change the rotation in board_config.py, it isnāt reflected in lv_config.py. I can fix that later today. Thanks for the feedback!
Btw, Iām restructuring a bit so board_config.py and lv_config.py can be combined into a single file if you want to, but you wonāt have to. Itās important to me to be able to use the board_config.py both with and without LVGL.
If the image is actually rotating then you do not need to do anything with the display driver in LVGL. the hardware rotation is working as it should be. If the touch is not aligning properly with what is seen no the display then you need to remap the touch input so it is correct.
this is something that I believe should actually be done in the indev driver of LVGL.
dynamic rotation of the display is not really a cut and dry thing with LVGL and I suppose this is because of not all displays handling it in the same manner. You have verbage differences that also complicate it.
while one display might consider 480 x 320 to be rotation of zero another might consider 320 x 480 to be a rotation of zero and then you have the touch panel that is being used could be reversed from what the display is.
Using portrait, landscape, reverse portrait and reverse landscape is not an ideal way of describing display rotation because there are assumptions being made about the display and the attached hardware.
using rotation_0, rotation_90, rotation_180 and rotation_270 is a better way of describing the rotation because it is not specific to what the actual format of the display is. The other thing that mucks it up is how the user passes in the width and height because ti is unknown if a driver for the display or the driver for the touch internally alters the width and height.
I think that the width and height of the display that gets fed in should always remain the same. meaning the user should not be changing them. the width and height should be what the displays width and height is at zero rotation and if the rotation gets changed then the width and height would internally be changed. This is what I did with the touch drivers that I use. I have a remap that I wrote that handles altering the numbers.
ft6336.zip (6.8 KB)
I attached an example of the touch driver that I wrote for a project I was working on. The touch driver collects the same width and height that was passed to the display driver. The thing you will notice is that the width and height never change. that is a constant. What can change is the orientation. so the width and height should always be set to whatever the default is for the display. What I mean by that is if you donāt set the MADCTL upon display initialization the factory orientation is what defines the width and height.
Those numbers should remain a constant through LVGL. They should never change. LVGL internally should have a setting to change the rotation. the only thing that LVGL would do is internally flip flop the width and height that was passed when the display was created. This is an internal change that would take place and the public width and height would remain exactly how it was set when the display was created. This is only done so LVGL writes the data to the display buffer properly.
The code I wrote for the indev driver is something I feel should be built into LVGL. There should be a single entry point for changing the rotation and that should be handled by LVGL. LVGL should internally alter the coordinates for the touch to accommodate the orientation that is being used. There should be a callback that can get set so if the user changes the orientation the display driver would be able to be notified of the orientation change so it could set the display hardware accordingly.
I would have this be optional by using a macro in the config file for LVGL. would also be a nice thing if LVGL has a widget for handling the touch calibrationā¦
Let me touch base on the whole portrait and landscape being used as the verbs for display orientation.
landscape = width > height
portrait = height > width
what happens with a display that is 320 x 320??
what happens with a round display?
How hard would it be to completely dismiss the concept of horizontal and vertical orientation all together?
Why does everything have to be thought of as being rectangular?
I have not seen this done and it would be a really wild concept. Say I am wearing a smart watch and I pick up my arm to look at the watch. wouldnāt it be nice if what was display was always locked to vertical regardless of what my arm position is. if I am holding my arm at a 45Ā° angle (left arm) and an analog clock was being displayed noon would be pointed up or at the 12:00 position like it should be instead of at the 10:30 position like what is currently being done. How about being able to interact with it in that position?.. what is the need to lock the screen orientation into 4 positions?.. This would be a feature that would need to be turned on for obvious reasons. It would be nice to be able to pass a 0 to 360 value into a function to set the orientation and rotating what is on the display would be handled internally by LVGL and LVGL would also take care of altering the touch coordinates as needed.
In the watch use case LVGL already has the code built into it to handle altering the touch coordinates. The same math that is used to handle rotation of an object would be used to handle the rotation for the touch coordinates.
What do you think @kisvegabor
@Alexandr Hang tight. I almost have the fix finished and will post shortly.
The fix is posted. No need to update the display_driver or touch_driver, but be sure to download the other 4 (busdisplay.py, lv_driver_framework.py, lv_config.py and board_config.py.) Touch rotation stay in sync with the display rotation now. Also added lots of changes @kdschlosser made to his display_driver_framework.
Hey @kdschlosser, the last we talked was before Christmas. Iāve tested a few boards with both SPI and I80 buses, and all work when configured in blocking mode. Since your last change, coupled with changes in the MicroPython code, it now starts to work in non-blocking mode, including drawing the full display and handling 2 or 3 touch events, and then locks up.
I like the changes you made to display_driver_framework.py regarding buffer allocation, and I added those to busdisplay.py and lv_driver_framework.py.