-
Notifications
You must be signed in to change notification settings - Fork 295
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
willing to give a lift #1
Comments
Hi @zladay Glad to see that you are interested in contributing to the project. Every help is welcome! 🙂 @C47D, the maintainer of lv_port_esp32, is also into this topic. We are still in the planning phase, finding the right API, layers, etc. Do you already have any ideas? |
Hi @zladay, The initial work is already done on the lv_port_esp32 repo, we will copy the lvgl_esp32_drivers directory into here, so users can use the drivers without needing to use the whole lv_port_esp32 project (we are also working on the lvgl and lv_examples repo to make them easier to use with ESP-IDF framework and other frameworks that use Kconfig). Support for those drivers will be gradually added into the lvgl_drivers repo, this repo requires work. Hopefully I can start working in this repo this weekend, I'm currently trying to fix a bug in the IL3820 display controller. Any ideas let us know. Regards |
I am aware of the drivers you mention. I started working with an original version of @kisvegabor's ESP32 demo. (There was only ili9341 and xpt2046 support at that time).
|
@zladay |
Sure. |
I can upload the existing code here and you take over with your improvements, I'm sure there's a lot to be done with the existing code on the lv_port_esp32 display and touch (indev) code. |
I have already set up a repository with my drivers. In order to demonstrate the new approach, I need to come up with a new demo program, too. I have also set up a repository for this. I have been using a pretty old version of lvgl and an lvgl example. The "Write List Chart" one. I decided to include lvgl and lv_examples as submodules in this repo. It is now done. In this process, I switched to the master branch of both of these lvgl parts. At this moment, my ancient main.c does not compile with this. I have just recently realised that my favourite "Write Chart List" is gone. I need to find another demo program. (Any suggestions?) I had to fight the build system a bit, but it works now. Nothing serious, I am on track. It has, however, delayed my attempt to clean up and reorganise the driver code. I am asking for a little patience still. |
I have just changed the demo to lv_widgets_demo. Demo compiles and works on first try with the latest lvgl, wow. ili9341 (320x240) and xpt2046. Touch works, too. Demo and drivers are committed to the Github repos. |
Hi,
Maybe we can use your architecture as a base and add the old drivers on top of that, updating any necessary code, we have to remember this repo will be used as submodule on the The Do you have your repos available somewhere? OFFTPIC: |
Also, are we going to compare both approaches? I haven't measured how busy the SPI master is in the current approach. |
As I wrote earlier, the lv_example problem is solved. This widget demo is scrolling through the TFT right now. (I am missing the "Write List Chart" BTW, that looked much nicer :) |
You have a lot of questions :) I am trying to answer all, however. |
"Maybe we can use your architecture as a base and add the old drivers on top of that"
|
We typically prefer to use communication mediums that can be searched more easily (i.e. GitHub issues and the forum). It helps reduce the number of duplicate questions. EDIT: I forgot to mention that the forum actually behaves very similarly to a real-time chat system; I'm pretty sure you get notified almost instantly if browser notifications are enabled. |
What do I mean by reorganisation? |
Performance measurements? |
"Do you have your repos available somewhere?" |
There is one catch with the TFT drivers.
The RGB 666 seems to be Satanic for lvgl (not just because of its name). It takes 24 bits on the SPI. 1 octet per channel. The 2 LSBs are ignored (do not care). This goes well with 24bit color depth (some resolution is lost, only 262k colors instead of 16.7M). Unfortunately, however, this does not go well with lvgl. Lvgl dropped support for 24 bit color depth. |
Chat Personally I'm happy with forum/github. I got a lot of emails and notifications from these platforms. On top of these a chat - that requires real-time presence - would be too much for me. Besides - as @embeddedt mentioned - the issues and forum topics can be easily linked to answering questions quickly. TFT + monchrome Architecture design
So I see these abstraction layers:
What do you think? |
Chat@C47D proposed this. I will leave this to him to answer. TFT + monochromeI am aware of this. I never said that the drivers can not be written for MC OLEDs (especially because those are already written). I just said that drivers tend to be complicated because of the sub-byte addressing.
Lvgl does support 32 bit depth (RGB 8888). This is incompatible with RGB 666, so (down) conversion is required. It is just slightly better than up converting from RGB 565, since it is offering only 2 bits extra color resolution at a cost having 2x bigger buffer sent from lvgl compared to the RGB 565 case. Architecture designI fully agree on your objectives in theory, but there are some problems in practice. Work with or without OSI am not sure if we understand the same for "with OS". I suppose that it means that the development framework contains a scheduler with task handling and synchronization primitives (e.g. FreeRTOS). Support for multiple transport interfaces (I2C, parallel, etc.)I fully agree on this, but current code supports SPI only. Transport layer can be detached and a multiplexer can be built in to use multiple different types of interfaces. As I said, I have not done it yet. Simply because I did not want to jump that long right now. Support for vendor-specific drivers (e.g. ST)I do not really get it. All the drivers are vendor specific (Sitronix, Illitec, Solomon Systech, Xptek). The only difference in the mentioned ST case is that the display driver hw is within the MCU (but the touch controller is external, it is STMPE). The GRAM can be reached via an internal high speed parallel bus. This is technically (as far as the drivers are concerned) not too different from the situation when an external controller is connected via a parallel interface. Abstraction layersMy architecture is similar to what you wrote. As I said, it is missing the transport multiplexing layer yet. I want to make it available before it happens, because I am interested in the opinion and suggestions of the people showing up here as early as possible. It is not perfect, but I hope that it is going te be a good starting point and we could develop it further. Anyways, I think I need to stop talking too much. It takes away time from reorganization of the code. I am progressing with that. I will keep you updated. |
RGB 666 and RGB888 are really not supported and I don't see an easy way to do it because the current formats can be natively addressed in every case (1,2 or 4 byte color types). Let's postpone it a little.
"Impossible" is not entirely true. You can convert the colors to the desired format in the If support for e.g. ST framebuffers fit well into the design then all good fro my side :) |
Just a small clarification for the RGB problem. The workaround you mention makes the concurrent use of a monochrome and a color TFT possible indeed. It is not impossible, you are right, but this is so ugly, that I was not even considering this as a "possibility". |
I suggested the chat because it's more real time, only intended for developers, not for general use. But thinking again about it, we should make the discussion public so anyone can add suggestions.
We need to remember that the drivers supported by the lv_port_esp32 are planned to be ported to lv_drivers. Which are going to be used in bare metal and RTOS projects.
SPI and I2C are currently supported because that's the interface of the displays we have available, I can't do any parallel because I have no display to test it and sometimes is slower to wait for test results. Sure we can do an abstraction layer so it doesn't matter what SPI, I2C, parallel or custom interface is used.
I think we shouldn't do everything, users should init the SPI, or any peripheral they are using. They should set some callbacks (functions that takes an array and send it over whatever interface they are using), we only need to arrange that array of bytes with the color data. As @zladay suggested, we can make a generic ILI9x driver and make the initialization and rotation code driver dependent. |
If you use 32 bit color depth for LVGL you can make the conversation in the color buffer as well without allocating a new temporary buffer. Seemingly we are on the same page. 🙂 |
Let me resolve the contradiction here. I2C is practical (or available at all) at small, mostly monochrome displays. I have already written SSD1306 (and SH1107 which is almost the same) drivers for an other platform (mbed, if I remember correctly). I have experience with that even on I2C. So, I can tell you that I am not afraid of them. |
I am not sure that I know what "drivers supported by the lv_port_esp32 are planned to be ported to lv_drivers" means. I am also not sure if your comment was intended to support or dispute my thoughts. If it is RTOS, it is obviously not a "without OS" scenario. |
I do have some TFTs with parallel interface, but I do not want to work with them now, because
|
I disagree strongly. (It is a pretty long story why.) |
It is almost ready now. I am currently fighting with the rotation story. It is not simple if you want to give a general solution. There are a couple of mines there. I am sorting this out at this moment. I hope that you are going to be able to see the results soon. |
Maybe I do not fully understand how RGB 8888 (32 bit color depth) works, but I am afraid that your above solution does not work. RGB 8888 mode populates the flush buffer with 32 bits/pixel. Four bytes for pixel one, then four bytes for pixel two and so on. |
I could, of course, reorganize this, but I do not want to. I fully agree on the opinion that it is not well structured, but there is a reason why it is how it is. |
I see. However, the code size is not an issue as the unused components can be disabled via menuconfig. What about one folder with names like "platforms" with files like "esp32.c" and later "stm32f4.c" etc. BTW, in the filename of "stsd_common.c" what does "stsd" mean? |
How? |
This is just my personal opinion: I would like to propose some things:
What do you think @zladay? @kisvegabor : |
I am neither trying to argue against taking the public demo code here, nor trying to argue for it. You say that there are "users waiting for this". Maybe. The fact is, that there are only 4 participants on this issue and this is the only one opened for this repo. I do not hear crowds banging on the door demanding for code here.
I am trying to be honest. I am feeling very little motivation to add support for the monochrome displays. I consider developing the driver architecture (although it is fully functional, but has not been finished yet) as a much higher priority. Why do I want to defer the addition of monochrome display support? I think that the primary target of lvgl is the color displays with touch indev capability. The monochrome modules are not just lacking the color depth, but they are usually very low resolution and have no indev built in. There are technical problems with them, too. They need sub-byte pixel addressing. This needs to be figured out how we can handle that. (I am expecting @embeddedt replying to this that we can use rounder_cb.) BTW, I have nothing against any of the three bullet points above. Maybe with one addition. The new driver architecture code should not be made public now. Contributors are, however, welcome. I can give access to my private repo to anyone who is serious about it. I do not yet want to handle user requests with regards to the drivers. Neither want I hear rants that there are fundamental changes sometimes and that broke her app code. I would roll this out when it is reasonably thought after and tested not only by myself, but some other people also.
This was not addressed to me, but if @kisvegabor allows, I am trying to answer this. |
I was thinking about the question of @C47D with regard to multiple displays. lv_disp_t * _lv_refr_get_disp_refreshing(void) It seems to be obvious from this prototype that the answer for the above question is yes. |
The library is built with a single-threaded model in mind, so only one set of objects can be processed at a time. Hence there is no major advantage to refreshing multiple displays. Theoretically it would be possible to cache the buffers and render them in parallel but the assumption is that there normally isn't enough available RAM on the device to make this worthwhile. |
Being it single-threaded does not preclude processing multiple set of objects "at a time".
This is again something I do not understand. AFAIK, lvgl works the following way.
This means that buffers are separately allocated to the display instances. They do not share a single (set of) buffer(s). If "the assumption is that there normally isn't enough available RAM on the device to make this worthwhile", why is there the possibility to define as many displays (together with their memory footprint) as I wish? This is the current "refresh finished" function. It is adapted from @kisvegabor's original demo: void refresh_finished(void *notif_id)
{
lv_disp_t *disp = _lv_refr_get_disp_refreshing();
lv_disp_flush_ready(&disp->driver);
} A particular display needs to be notified (penultimate line) via its driver. It is ok. It would be normal if this was the only thing I needed to do. (I could guess the lvgl display instance, since it is in a one-to-one type relation to the driver display instance). Why do I need to call _lv_refr_get_disp_refreshing()? |
@zladay #if CONFIG_LVGL_TFT_DISPLAY_CONTROLLER_ILI9341
... all the codes here ...
#endif
What you say is theoretically possible but imagine what would happen in the practice:
So there will be a 15 ms delay between rendering the 2 areas of display 1 which looks very ugly e.g. in case of a scrolling animation. BTW, you can use the same disp_buf for multiple displays. I never tried it but it should work. If the buffer is occupied for any reason (indicated by the @C47D |
Drivers reorganizationTouch controllers as plug-insAs planned earlier, touch "subsystem" now supports a plug-in architecture similarly to the {display} - {display-transport} relation. Support code for a particular hardware (e.g. XPT2046) needs to implement a touch controller object with the appropriate interface. This controller "driver" has very little functionality. Apart from the object housekeeping stuff, its only task is to provide raw X, Y data read from the controller. Any other touch related function (coord space translation, orientation handling, etc.) is in an object where the touch controller "drivers" plug in to. If there is a need of support for a new touch controller, only a new implementation of this touch controller "driver" is required. Object hierarchy, modularityCurrent object hierarchy looks like this:
I want to take a step further and merge the two object "trees". Apart from that, I am about to detach backlight handling from the display driver, since it does not belong to there. The resulting object hierarchy should look like this:
{device} is a new object. It is meant to encapsulate everything a physical device (display panel) contains. It is the single root of the (planned) object tree. It has a couple of advantages over the earlier approaches. It is a unified interface towards the hardware. For example, if orientation needs to be set (or changed later), it is enough to specify it at one place and one place only. Either in the device interface configuration (when creating the object) or with a later call on the object. Display orientation change is reflected in screen layout and in touch coordinate translation simultaneously. Another advantage is that this architecture is modular. Modules (objects) are completely independent. If they implement the appropriate docking interface, they can be used in this system. If someone wants to implement support for a new touch controller e.g., she can use an existing object implementation as a template. She does not need to understand coordinate space translation or orientation handling, not to talk about display controllers. This approach is also very flexible since the different components are completely detached. Any combination of those is giving a working device. If someone wants to set the intensity (or the color) of the back light, she can implement a new back light controller for that. App developers can choose from any implemented back light controllers or they can roll their own. Drivers - lvgl boundaryOnly the leaf nodes are closely tied to the development framework (ESP-IDF in this case) in the above object tree. {device} and {display controller} do not contain platform specific code. There is a possibility that lvgl core (or how to call that?) could just swallow them. And yes, including the display "drivers". Framework or platform independencyAs I said above, non-leaf objects are not closely tied to the particular framework. They are, however, not fully independent. There are two areas where they are still bound to the framework:
Error handlingAs far as error handling is concerned, I still do not know what the best approach would be to achieve framework independency. General OS stuffGeneral OS stuff is different. I think I have a workable solution for that. This is to implement an OS abstraction layer. This is what I have already proposed. The implementation of this abstraction layer (AL) is not only for the drivers, tough. The whole lvgl could and should use it. If it is properly implemented, lvgl core (or how to call it?) could be refactored in order to become multi-threaded safely. Multi-core MCUs are appearing on the market. It is happening not just on the high end, since even the dirt cheap ESP32 chips have dual cores in most cases. If lvgl stays single threaded, she is not going to be able to use half or more (depending on the number of cores) of CPU resources. Code modularity, reusable code blocksAs lvgl is growing in functionality, it might easily get stuck in the mud with its monolithic architecture. As I am trying to demonstrate with the drivers, an object oriented approach should be followed instead. (BTW, for God's sake, #define is not an interface!) As seen here, object oriented code (even with inheritance) can be written in plain C also. This is, however, begging for C++ instead. The drivers would be architecturally the same in C++, but the whole thing would be more straightforward, concise and easier to read. And this does not apply to the drivers only. It applies to the OS AL and everything. I would appreciate your comments. @kisvegabor |
First, I did not understand what you are referring to here. And after a couple of minutes of thinking, I came to the conclusion that this is the response to the question how we could include/exclude unnecessary modules from the image (instead of using what the framework offers for this purpose).
I think this is an arbitrarily fictitious scenario. It is not based on inevitable and necessary conditions. This is also rather hazy. "large area", "redrawn in two parts". How large? Does not it fit the RAM in one piece? Lengthy rendering? What MCU, what screen size? I am sorry, but it does not make too much sense to me. Let us suppose that your example is real. (It is rather arbitrarily taken, but can be real.) In that example the responsiveness of the second screen suffers. Is that a better scenario than the first being a bit flattering? Even that flattering can be prevented (at the cost of delayed service for the other display). This is easy. Rendering of the next screen of the second display does not start before the rendering of the whole series of screens finishes on the first. If I understand you correctly, this is exactly what happens. (Otherwise you can not prevent flattering on the first.) But this has nothing to do with the question "why can multiple screens not be in "being refreshed" state simultaneously"? I hope that I could describe why I still do not understand why only one display can be in "being refreshed" state at a given moment? Why is _lv_refr_get_disp_refreshing() necessary? It does not solve the problem you are describing in your example (but rendering rescheduling does, but that is completely unrelated). Now, let us see the opposite scenario. It is not the CPU, but the bus transport throughput that is the bottleneck. Let there be two displays on separate SPI buses. At least one of them is (or both are) slow (only works on low clock rate). The rendering of the second display is ready (while the first one is still being refreshed). Refresh of the second can not start until the first finishes, since there can be only one in "being refreshed" state at the given moment. This blocks everything. Rendering is blocked, too. (In a double buffer scenario it happens a bit later, but it does.) Is it good? Let me summarize this: we have something that does not help in the example you gave, but can potentially lead to a screeching slowdown in mine. It does not make any sense to me.
I do not want to do this. The only reason I mentioned this was that memory footprint would not increase substantially with multiple displays only if they shared buffers. This is not the case.@embeddedt said that the system is designed this way, because there is not enough memory. OK. But, if this is the case, why are multiple displays supported? This is inconsistent.
@C47D |
@zladay
We also try to be flexible in this regard as well. All you need to do is using a mutex around LVGL related functions. It's some work from the user but very flexible.
We don't want to grow to the infinity with features. In fact, we are planning to clean up features for v8. We need to clearly see what are the boundaries of LVGL. The goal is to make it as lean as possible.
C surely will remain the main language for embedded for some years. If C++ will be more popular for user code (e.g. Arduino) probably it's still worth keeping the core features in C for performance reasons. The Linux kernel is also in C although a CPU-based system has "unlimited resource" resources compared to an MCU. Multi-display handling The case is different if the display transports are independent (e.g. on different SPI). In this case, LVGL can render one screen while an independent display is refreshed. It also can lag if rendering takes longer the refreshing the other display. But it's a much clearer situation. If the user can indicate which displays have independent transport then LVGL really can make some parallelism.
@C47D made a great job in adding and testing drivers, answering issues, reviewing PRs, fixing bugs and so on. Big thank you for this from me and from the people you have helped! We all know that everything can be improved but we have limited time and resources so sometimes we need to live with compromises. The best we can do is creating a welcoming place where people are happy to come in their free time to work on stuff they like. Speaking publicly about a private repo is certainly not welcoming stuff. You say the license allows us the share it but I feel unethical to disclose a private repo. So @zladay in order to use your code please send a pull request to this repo. It's another important step to get closer to your code. Regarding the support and maintenance: it really means a lot of extra work. We can't expect anybody to take this. However, we are here with LVGL and its community for years and we will live with the project for long. Therefore, any code we accept should look and work in a way are willing to support and maintain. So I understand if you are not interested in support but you should take the word of people who will do the support. We need to clarify what is the goal of the individuals. From my side: I devote most of my capacity to the core LVGL and can not deal with the drivers on a daily basis. As I mentioned above my checkpoint are:
If these are met, I'm happy. |
@zladay |
Drivers reorganization - full object treeAs planned before, I have completed the reorganization of the driver architecture. New code is committed and pushed to GitHub.
This is a snippet from main.c showing the driver initialization sequence: // initialize SPI bus using ESP-IDF, display and TC are on the same bus
// only one bus initialization is required
ESP_ERROR_CHECK(spi_bus_initialize(BOARD_SPI_HOST, &sbc, 1));
// device (TFT module) build starts here
// create all necessary parts
// create the device object
ESP_ERROR_CHECK(device_create(&d_msp3218, &d));
// create display controller object
ESP_ERROR_CHECK(ili9341_create(&dc_msp3218, &dc));
// create display specific SPI transport object
ESP_ERROR_CHECK(disp_transport_spi_create(&dts_gen, &dct));
// create touch controller object
ESP_ERROR_CHECK(xpt2046_create(&tc_xpt2046, &tc));
// create back light controller object
ESP_ERROR_CHECK(backlight_onoff_create(&bc_onoff, &bc));
// start the assembly of the parts
// add device specific SPI transport to the display object
disp_generic_handle_t c = dc->controller;
c->add_transport(c, dct);
// add display controller to the device
d->add_display(d, dc);
// add touch controller to the device
d->add_touch(d, tc);
// add back light controller to the device
d->add_backlight(d, bc);
// device is fully assembled, reset it
ESP_ERROR_CHECK(d->reset(d));
lv_init();
lv_disp_buf_init(&disp_buf, buf1, buf2, DISP_BUF_SIZE);
lv_disp_drv_t disp_drv;
lv_disp_drv_init(&disp_drv);
disp_drv.flush_cb = flush;
disp_drv.buffer = &disp_buf;
lv_disp_drv_register(&disp_drv);
// tell device whom to notify when refresh is finished (flush completed)
d->notify(d, lv_disp_flush_ready, &disp_drv);
// device initialization is now complete
lv_indev_drv_t indev_drv;
lv_indev_drv_init(&indev_drv);
indev_drv.read_cb = read_touch;
indev_drv.type = LV_INDEV_TYPE_POINTER;
lv_indev_drv_register(&indev_drv); The device object is meant to encapsulate everything found on a display panel. This has a couple of benefits over the former scattered approach. One such example is the orientation handling. It needs to be specified at one location. It looks like this: d->orientation(d, 3); d is the handle of the {device} object. This single call on that object changes the orientation of the display and the TC simultaneously to 270 deg CW relative to the base orientation. In the previous version, the two were separate, two different calls were needed (one on display and one on TC) for the same effect. I would really appreciate some form of feedback to this. I do not even mind, if someone tried this on real hardware. I would then see if it is worth a pull request. Framework independence (platform agnosticism)Peripheral related (platform specific) code is only found in the leaves.
As previously suggested, the "OS related" problem can be solved by implementing an OS abstraction layer (OSAL). Next stepsIf we want to extend this reference implementation to other frameworks, we need to implement OSAL and EHAL. This two components shall not only be used by the drivers, but LVGL core, too. IMHO, these two things (especially OSAL) are very critical from performance and stability perspectives. These should not be left to the application developers. There is a high chance that they would screw it up and put the blame on LVGL. |
@zladay Could you comment on what @kisvegabor wrote above? |
|
@zladay I'm ok with OSAL and EHAL too on driver level. It might be possible to add OSAL to LVGL but it's quite complicated and needs serious and long consideration. Simply it's not on the roadmap now. We should discuss it later.
Short answer: C++ is not accepted. We meant to comment on this
|
Ok. The comment is then already given. As far as the forum is concerned: I have registered to the forum at lvgl.io. |
Can you give some platform examples where C++ is not available? On the other hand: |
"Someone" is now limited to Carlos and me. Anyway if you could attach a zipped project, I'd try it on an ILI9341 display. Regarding the C++ topic: Microchip has very weak support for C++. See here. It seems for PIC32 C++ is already free but there is no C++ compiler for 16 bit PICs (already capable of driving a display). |
If I understand correctly, he would like to know the required work to have the drivers (display and indev) available in the I suggested them to take a look at this issue because I think the new architecture can achieve this, separate the driver code from the mcu/platform code. |
Fix contrast and display mode initialisation
I am into Sitronix ST7735 style (e.g. ili9341, ili9488 and the like) TFT controllers. I am also working with different TCs (STMPE811, XPT2046 etc.)
I am interested in a more ESP-IDF-ish driver infrastructure with a streamlined lvgl interface.
Willing to share ideas, designs and code examples.
Looking for some guidance since this is an empty space now.
The text was updated successfully, but these errors were encountered: