I have an existing STM32 system, L562 processor, FreeRTOS based, Existing graphics system in C++, drivers support S7735R chipset (160 * 128) and lots more.
I want to try LVGL, but the instructions to install seem to wave their hands and say “then a miracle occurs”. So some questions.
Does LVGL provide low level drivers, startup, write to chip, read from chip for the ST7735 (or other chips, I have a few)?
Since I have low level routines (SPI) that write to the chip, with attention paid to the A0 line, (and they work), should I try to figure out where LVGL could call these routines and then redirect them to mine?
The infrastructure is:
Code to initialize low level drivers per STM32IDE rules.
C++ wrappers to play nice with FreeRTOS
Drivers to enable polling, IRQ, or DMA interface to the drivers (some needs work, and some don’t make sense due to driver configuration. Think I2C, serial, SPI drivers.
low level driver support to initialize a chip.
Graphics routines that write to a 32 bit display image.
graphics chip specific routines to take a virtual image (32 bit) and transfer it in various formats (display hardware specific) to the display. For the ST7735, you get the choice of going RGB565, for instance.
What I’m lacking is the high level widgets routines, which I can do, but perhaps an existing product is better.
I’ve looked through the “how to start up” and the instructions and explanations don’t seem to be at a level I am comfortable with (for instance, display flags in the display init routines.)
I know a bit of this, what I don’t know is how you expect it to be done.
LVGL does not replace your low-level drivers. It sits on top of them.
Normally you keep all your existing infrastructure:
STM32 init (clocks, GPIO, SPI, DMA)
FreeRTOS integration
panel init code (ST7735 commands)
routines that send RGB565 pixels over SPI
LVGL simply renders graphics into a draw buffer, then calls a flush callback that you provide. In that callback you send the pixels to the display using your existing driver.
Typical integration looks like:
Initialize hardware as you already do.
Call lv_init().
Create the display (lv_display_create(160,128)).
Provide a draw buffer.
Implement flush_cb that calls your ST7735 write routine.
Run lv_timer_handler() periodically.
So if your SPI/ST7735 write path already works, the easiest approach is to reuse it inside LVGL’s flush callback and let LVGL handle widgets, layout, and rendering.
OK, I got misled by the presence of an ST7735R driver, which implied to me that the system provided its own drivers. At this rate, I might as well use my own.
My system renders to a 32 bit graphics image regardless of what the display resolution is. Since that’s a virtual image, I bypass displays that cannot be read (and there are lots). Then a specific driver copies areas of that to the actual physical display.
With that implemented, the driver for ST7735 handles most of the rest, including flush_cb and etc… The user supposedly needs to call lv_st7735_create and assign buffers to the display with lv_display_set_buffers, eventually calling also lv_st7735_set_gap in case the displays writes aren’t indexed at 0 and is necessary some offset when setting Column/Page write address.
It may be necessary to change the init_cmd_list on the top of ST7735 file, or use the lv_lcd_generic_mipi_* interface, and use that interface to send/control the display, since the ST7735 driver is just a wrap on top of lv_lcd_generic_mipi_*.
Never used this approach, and don’t know of any project that uses this approach to serve as an example. Having already the Display working is probably easier to implement these things “manually”, since the drivers are not “ready to use” to any Display, there are always some specifics for each display (Init commands, Gap, Inversion, etc…) that needs to be called to properlly setup the display, LVGL just gives a “nice” API to do that.
I’ve tried some of that, and I’ve found the usual problems.
In an STM32 project (and any other ones), the general procedure starts off with "Just add the sources to the project.
While helpful, I’ve always found that there are some unstated assumptions.
I’ve got an entire ecosystem with drivers, graphics, #ifdefs, display drivers, serial drivers, etc. It’s installed by adding the source to the project by using project/properties and adding the entire folder to the project. Within that project, everything is relative to how the source files are installed.
I think that LVGL is perhaps doing the same thing. However, “COPY THE SOURCE FILES” has several solutions.
Just exactly where in your STM32 project is the directory to be installed, LVGL, right, but what’s the
next directory down, in the repository, it’s SRC, then where do all the files go? Is LVGL under the root directory, then lvgl under that, with all the .src files stuffed into lvgl? With config files in LVGL? Do I guess on which config files to use?
Problem that I’m having is that I install the program, I get internals in the program that can’t be found.
LVGL is not alone in this, I find that there are many programs that make the “install it like this” and don’t really specify “this”.
With CMAKE is a bit different, but similar, with specifics related to cMake…
This “recipe” works for me, the second “include” directory in the settings most likely isn’t necessary as long we use `#include “lvgl/lvgl.h” in the C Code…
The folder location can be wherever you prefer to have it, it it’s a STM32 CubeMx Project, probably inside “Middlewares” or eventually “Drivers”, or a root folder called “lvgl”… user choice as long the include paths are then “correct”, especially the ones required for lvgl to find lv_conf.h. Overview - LVGL 9.6 documentation
When using Eclipse on Windows (Not sure if this applies to STM32CubeIDE) is necessary to adjust some stuff because of “too long path on the linker stage, due to high number of c files in LVGL”.