Hi,
I have purchased the ebook “Learn LVGL: Build GUIs for ESP32 Projects”, and am working my way through it, all fine so far.
At the same time I have been looking at the LVGL website: https://docs.lvgl.io/master.
In the documentation, under Quick Overview, it says:
” Instead of porting LVGL to embedded hardware straight away, it’s highly recommended to get started in a simulator first. LVGL is ported to many IDEs to be sure you will find your favorite one. Go to the Simulator on PC section to get ready-to-use projects that can be run on your PC. This way you can save the time of porting for now and get some experience with LVGL immediately. ”
I would very much like to try this, as I think it will speed up the process of trying out all the widgets, styles, etc.
So I have followed the instructions in the link provided: https://github.com/lvgl/lv_port_win_codeblocks.
This sets things up to run LVGL simulation in Code:Blocks, which is an IDE for C-code. Everything looks as I’d expect, and I can see files for all the many examples and demos that LVGL provides. BUT — I cannot get anything to run.
I have submitted a post on the LVGL forum asking for help, but have had no response.
So I wonder if any of you Random Nerd followers have used a simulator for LVGL, and if so, can you offer any advice on how to get it to work ? If you think you can help, I can post full details of the steps I have followed.
Many thanks, Ken.
Hi Ken.
I have tried to get the Simulator to run, but I couldn’t make it work on my computer.
So, I don’t have much advice on this matter.
Let me know if you find useful information.
Regards,
Sara
Hi Sara,
Apologies for the long delay in getting back to you.
I have spent a long time getting a Simulator to run with LVGL (and have also been away on holiday).
Anyway, I have now managed to get simulations of LVGL to run on the CodeBlocks IDE. It’s a bit complicated, but I will attempt to describe the steps. i have also copied four files at the end of the post, so it is rather long.
As I said in previous post — I have followed the instructions in the link provided: https://github.com/lvgl/lv_port_win_codeblocks.
This sets things up to run LVGL simulation in Code:Blocks IDE, and I can see files for all the many examples and demos that LVGL provides.
When I click Build then Run it launches the “lv_demo_widgets” demonstration.
In order to run a different demo, e.g. “keypad_encoder”, two things need to be done:
1. In file main.c, edit the line under Run the demo —
from char * demo_str[] = {“widgets”};
to char * demo_str[] = {“keypad_encoder”};
2. In file lv_conf.h, at approx line 952, check that it has:
#define LV_USE_DEMO_KEYPAD_AND_ENCODER 1
Build and Run will now launch the “lv_demo_keypad_encoder” demonstration.
I have decided to use keypad_encoder as a test-bench by deleting almost everything in file “lv_demo_keypad_encoder.c”, and replacing it with my own code. My version of the file with simple code for a button and label is as follows:
Start your code here [This doesn't seem to work, so I have just put all files at the end of post instead]
I have also edited the header file “lv_demo_keypad_encoder.h” as at end of post.
I’m sure it is possible to make a new demo in CodeBlocks with a meaningful name such as “my_testbench”, but I have not tried this.
So now I can play around with LVGL and see the effects immediately with a single Build and Run key (F9). The initial build takes a few moments, but after that it is very quick.
Having got the display the way I want, I can then transfer it to Arduino to test for real. I have prepared a “Template.ino” file which contains all the necessary code to drive the CYD, except for DECLARATIONS and FUNCTIONS.
The DECLARATIONS and FUNCTIONS are copied from “lv_demo_keypad_encoder.c” and pasted into “Template.ino”.
Copies of “Template.ino” before inserting code from CodeBlocks, and with my simple example pasted in, are also at end of post.
I hope all this makes sense, and that I havn’t missed anything.
Finally, I have a request for further help.
I would like to use style themes, in particular the “lv_theme_simple” which for some reason is under API. The documentation on themes is very limited and I cannot make sense of it. Do you have an example of using themes in LVGL — I always find a working example is the best starting point.
Many thanks, Ken.
COPIES OF FILES
_________________________________________________________________________________
/* File: lv_demo_keypad_encoder.c
This is the edited version of keypad encoder
to implement a simple test to run on CodeBlocks
In file main.c, edit the line under Run the demo —
from char * demo_str[] = {“widgets”};
to char * demo_str[] = {“keypad_encoder”};
In file lv_conf.h, at approx line 952, check that it has:
#define LV_USE_DEMO_KEYPAD_AND_ENCODER 1
Edit the header file: lv_demo_keypad_encoder.h
as in the copy that goes with this file.
Open file lv_demo_keypad_encoder.c
and replace everything with this file.
Click Build, then click Run.
*/
#include “lv_demo_keypad_encoder.h”
#if LV_USE_DEMO_KEYPAD_AND_ENCODER
// DECLARATIONS
static lv_style_t style1;
static lv_style_t style2;
//—————————————————————-
// FUNCTIONS
static void my_styles(void)
{
lv_style_init(&style1);
lv_style_set_radius(&style1, 10);
lv_style_set_bg_opa(&style1, 255); // 100% Opaque
lv_style_set_bg_color( &style1, lv_palette_main(LV_PALETTE_RED));
lv_style_init(&style2);
lv_style_set_radius(&style2, 30);
lv_style_set_bg_opa(&style2, 127); // 50% Opaque
lv_style_set_bg_color( &style2, lv_color_make(0,255,0)); // Green
}
// ————————————————————–
static void button_event_cb(lv_event_t * e) // Callback Function
{
lv_event_code_t code = lv_event_get_code(e);
lv_obj_t * button = (lv_obj_t*) lv_event_get_target(e);
lv_obj_t * label = (lv_obj_t*) lv_event_get_user_data(e);
if(code == LV_EVENT_CLICKED) {
static uint8_t counter = 0;
counter++;
lv_label_set_text_fmt(label, “Counter: %d”, counter);
LV_LOG_USER(“Counter: %d”, counter);
}
}
//—————————————————————-
// Core function to draw the GUI
// —————————–
// This function’s name has to be changed in Arduino
void lv_demo_keypad_encoder(void)
{
// Set screen background colour, dark grey
lv_obj_set_style_bg_color(lv_screen_active(), lv_color_make(50,50,50), LV_PART_MAIN);
my_styles(); // Call my_styles function
// Create a Button
lv_obj_t * buttonA = lv_button_create(lv_screen_active());
lv_obj_remove_style_all(buttonA); // Remove default style
lv_obj_align(buttonA, LV_ALIGN_CENTER, 0, 0); // Set position
lv_obj_set_size(buttonA, 120, 50); // Set the size
lv_obj_add_style(buttonA, &style1, 0); // Set the style
// Add a label to buttonA
lv_obj_t * button_label = lv_label_create(buttonA);
lv_label_set_text(button_label, “Click here!”); // Set the labels text
lv_obj_center(button_label);
// Add a text label below the button, set colour locally
lv_obj_t * text_label_counter = lv_label_create(lv_screen_active());
lv_obj_set_style_text_color(text_label_counter, lv_color_white(), LV_PART_MAIN);
lv_label_set_text(text_label_counter, “Counter: 0”);
lv_obj_align(text_label_counter, LV_ALIGN_BOTTOM_MID, 0, -50);
// Assign a callback to buttonA
lv_obj_add_event_cb(buttonA, button_event_cb, LV_EVENT_ALL, text_label_counter);
}
#endif
________________________________________________________________________
// @file lv_demo_keypad_encoder.h
/* In same way as with lv_demo_keypad_encoder.c
replace everything in the header file with this file
*/
#ifndef LV_DEMO_KEYPAD_ENCODER_H
#define LV_DEMO_KEYPAD_ENCODER_H
#include “../lv_demos.h”
void lv_demo_keypad_encoder(void);
#endif
_______________________________________________________________________
/* File Template.ino
====================
July2024
Required code for all sketches */
// Install libraries
#include <lvgl.h>
#include <TFT_eSPI.h>
#include <XPT2046_Touchscreen.h>
// Display width and height
#define SCREEN_WIDTH 320
#define SCREEN_HEIGHT 240
// Touchscreen pins
#define XPT2046_IRQ 36 // T_IRQ
#define XPT2046_MOSI 32 // T_DIN
#define XPT2046_MISO 39 // T_OUT
#define XPT2046_CLK 25 // T_CLK
#define XPT2046_CS 33 // T_CS
// SPI comms protocol for touchscreen
SPIClass touchscreenSPI = SPIClass(VSPI);
XPT2046_Touchscreen touchscreen(XPT2046_CS, XPT2046_IRQ);
// Touchscreen coordinates: (x, y) and pressure (z)
int x, y, z;
// Create a drawing buffer
#define DRAW_BUF_SIZE (SCREEN_WIDTH * SCREEN_HEIGHT / 10 * (LV_COLOR_DEPTH / 8))
uint32_t draw_buf[DRAW_BUF_SIZE / 4];
// —————————————————————————
// DECLARATIONS Copy and paste here from the CodeBlocks file
//——————————————————————————
// FUNCTIONS
// ========= The first two functions are always required
// If logging is enabled, it will inform the user about what is happening in the library
void log_print(lv_log_level_t level, const char* buf) {
LV_UNUSED(level);
Serial.println(buf);
Serial.flush();
} //—————————————————————————–
// Function to get the Touchscreen data
void touchscreen_read(lv_indev_t* indev, lv_indev_data_t* data) {
// Checks if Touchscreen was touched, and prints X, Y and Pressure (Z)
if (touchscreen.tirqTouched() && touchscreen.touched()) {
// Get Touchscreen points
TS_Point p = touchscreen.getPoint();
// Calibrate Touchscreen points with map function to the correct width and height
x = map(p.x, 200, 3700, 1, SCREEN_WIDTH);
y = map(p.y, 240, 3800, 1, SCREEN_HEIGHT);
z = p.z;
data->state = LV_INDEV_STATE_PRESSED;
// Set the coordinates
data->point.x = x;
data->point.y = y;
} else {
data->state = LV_INDEV_STATE_RELEASED;
}
} //—————————————————————————-
// MORE FUNCTIONS Copy and paste from the CodeBlocks file
// In the function that creates the GUI, the function name must be changed
// e.g. from: void lv_demo_keypad_encoder(void)
// to void lv_create_main_gui(void)
//——————————————————————————-
void setup() {
//============
// For debugging, print the LVGL version.
String LVGL_Arduino = String(“LVGL Library Version: “) + lv_version_major() + “.” + lv_version_minor() + “.” + lv_version_patch();
Serial.begin(115200);
Serial.println(LVGL_Arduino);
// Start LVGL
lv_init();
// Register print function for debugging
lv_log_register_print_cb(log_print);
// Start the SPI for the touchscreen and initialise the touchscreen
touchscreenSPI.begin(XPT2046_CLK, XPT2046_MISO, XPT2046_MOSI, XPT2046_CS);
touchscreen.begin(touchscreenSPI);
// Set the Touchscreen rotation in landscape mode
// Note: in some displays, the touchscreen might be upside down,
// so you might need to set the rotation to 1: touchscreen.setRotation(1);
touchscreen.setRotation(3);
// Create a display object
lv_display_t* disp;
// And initialize the TFT display using the TFT_eSPI library
disp = lv_tft_espi_create(SCREEN_WIDTH, SCREEN_HEIGHT, draw_buf, sizeof(draw_buf));
// Initialize an LVGL input device object (Touchscreen)
lv_indev_t* indev = lv_indev_create();
lv_indev_set_type(indev, LV_INDEV_TYPE_POINTER);
// Set the callback function to read Touchscreen input
lv_indev_set_read_cb(indev, touchscreen_read);
// Function to draw the GUI
lv_create_main_gui();
}
// End of Setup ———————————————————————
/* The LVGL library works asynchronously. You must call the function to draw on the
display in setup(). Then everything works with events and callbacks. The code
will always be listening for events in the background. When something happens, it
will run the callback function associated with the event. You don’t need to check for
any events in the loop(). */
void loop() {
//===========
lv_task_handler(); // let the GUI do its work
lv_tick_inc(5); // tell LVGL how much time has passed
delay(5); // let this time pass, 5 mS.
}
__________________________________________________________________________________
/* File Template.ino with code copied and pasted from lv_demo_keypad_encoder.c
===============
July2024
Required code for all sketches, plus sections copied
and pasted from the CodeBlocks file
Ready to run in Arduino IDE
*/
// Install libraries
#include <lvgl.h>
#include <TFT_eSPI.h>
#include <XPT2046_Touchscreen.h>
// Display width and height
#define SCREEN_WIDTH 320
#define SCREEN_HEIGHT 240
// Touchscreen pins
#define XPT2046_IRQ 36 // T_IRQ
#define XPT2046_MOSI 32 // T_DIN
#define XPT2046_MISO 39 // T_OUT
#define XPT2046_CLK 25 // T_CLK
#define XPT2046_CS 33 // T_CS
// SPI comms protocol for touchscreen
SPIClass touchscreenSPI = SPIClass(VSPI);
XPT2046_Touchscreen touchscreen(XPT2046_CS, XPT2046_IRQ);
// Touchscreen coordinates: (x, y) and pressure (z)
int x, y, z;
// Create a drawing buffer
#define DRAW_BUF_SIZE (SCREEN_WIDTH * SCREEN_HEIGHT / 10 * (LV_COLOR_DEPTH / 8))
uint32_t draw_buf[DRAW_BUF_SIZE / 4];
// —————————————————————————
// DECLARATIONS Copy and paste from the CodeBlocks file
static lv_style_t style1;
static lv_style_t style2;
//——————————————————————————
// FUNCTIONS
// ========= The first two functions are always required
// If logging is enabled, it will inform the user about what is happening in the library
void log_print(lv_log_level_t level, const char* buf) {
LV_UNUSED(level);
Serial.println(buf);
Serial.flush();
} //—————————————————————————–
// Function to get the Touchscreen data
void touchscreen_read(lv_indev_t* indev, lv_indev_data_t* data) {
// Checks if Touchscreen was touched, and prints X, Y and Pressure (Z)
if (touchscreen.tirqTouched() && touchscreen.touched()) {
// Get Touchscreen points
TS_Point p = touchscreen.getPoint();
// Calibrate Touchscreen points with map function to the correct width and height
x = map(p.x, 200, 3700, 1, SCREEN_WIDTH);
y = map(p.y, 240, 3800, 1, SCREEN_HEIGHT);
z = p.z;
data->state = LV_INDEV_STATE_PRESSED;
// Set the coordinates
data->point.x = x;
data->point.y = y;
} else {
data->state = LV_INDEV_STATE_RELEASED;
}
} //—————————————————————————-
// MORE FUNCTIONS
// Everything from here to line 121 is copied and pasted from the CodeBlocks file
static void my_styles(void)
{
lv_style_init(&style1);
lv_style_set_radius(&style1, 10);
lv_style_set_bg_opa(&style1, 255); // 100% Opaque
lv_style_set_bg_color( &style1, lv_palette_main(LV_PALETTE_RED));
lv_style_init(&style2);
lv_style_set_radius(&style2, 30);
lv_style_set_bg_opa(&style2, 127); // 50% Opaque
lv_style_set_bg_color( &style2, lv_color_make(0,255,0)); // Green
}
// ————————————————————–
static void button_event_cb(lv_event_t * e) // Callback Function
{
lv_event_code_t code = lv_event_get_code(e);
lv_obj_t * button = (lv_obj_t*) lv_event_get_target(e);
lv_obj_t * label = (lv_obj_t*) lv_event_get_user_data(e);
if(code == LV_EVENT_CLICKED) {
static uint8_t counter = 0;
counter++;
lv_label_set_text_fmt(label, “Counter: %d”, counter);
LV_LOG_USER(“Counter: %d”, counter);
}
}
// ——————————————————————
// FUNCTION TO CREATE THE GUI
// void lv_demo_keypad_encoder(void)
// Change function name:
void lv_create_main_gui(void)
{
// Set screen background colour, dark grey
lv_obj_set_style_bg_color(lv_screen_active(), lv_color_make(50,50,50), LV_PART_MAIN);
my_styles(); // Call my_styles function
// Create a Button
lv_obj_t * buttonA = lv_button_create(lv_screen_active());
lv_obj_remove_style_all(buttonA); // Remove default style
lv_obj_align(buttonA, LV_ALIGN_CENTER, 0, 0); // Set position
lv_obj_set_size(buttonA, 120, 50); // Set the size
lv_obj_add_style(buttonA, &style1, 0); // Set the style
// Add a label to buttonA
lv_obj_t * button_label = lv_label_create(buttonA);
lv_label_set_text(button_label, “Click here!”); // Set the label’s text
lv_obj_center(button_label);
// Add a text label below the button, set colour locally
lv_obj_t * text_label_counter = lv_label_create(lv_screen_active());
lv_obj_set_style_text_color(text_label_counter, lv_color_white(), LV_PART_MAIN);
lv_label_set_text(text_label_counter, “Counter: 0”);
lv_obj_align(text_label_counter, LV_ALIGN_BOTTOM_MID, 0, -50);
// Assign a callback to buttonA
lv_obj_add_event_cb(buttonA, button_event_cb, LV_EVENT_ALL, text_label_counter);
}
// End of copy from CodeBlocks file
//——————————————————————————-
void setup() {
//============
// For debugging, print the LVGL version.
String LVGL_Arduino = String(“LVGL Library Version: “) + lv_version_major() + “.” + lv_version_minor() + “.” + lv_version_patch();
Serial.begin(115200);
Serial.println(LVGL_Arduino);
// Start LVGL
lv_init();
// Register print function for debugging
lv_log_register_print_cb(log_print);
// Start the SPI for the touchscreen and initialise the touchscreen
touchscreenSPI.begin(XPT2046_CLK, XPT2046_MISO, XPT2046_MOSI, XPT2046_CS);
touchscreen.begin(touchscreenSPI);
// Set the Touchscreen rotation in landscape mode
// Note: in some displays, the touchscreen might be upside down,
// so you might need to set the rotation to 1: touchscreen.setRotation(1);
touchscreen.setRotation(3);
// Create a display object
lv_display_t* disp;
// And initialize the TFT display using the TFT_eSPI library
disp = lv_tft_espi_create(SCREEN_WIDTH, SCREEN_HEIGHT, draw_buf, sizeof(draw_buf));
// Initialize an LVGL input device object (Touchscreen)
lv_indev_t* indev = lv_indev_create();
lv_indev_set_type(indev, LV_INDEV_TYPE_POINTER);
// Set the callback function to read Touchscreen input
lv_indev_set_read_cb(indev, touchscreen_read);
// Function to draw the GUI
lv_create_main_gui();
} // End of Setup
/* The LVGL library works asynchronously. You must call the function to draw on the
display in setup(). Then everything works with events and callbacks. The code
will always be listening for events in the background. When something happens, it
will run the callback function associated with the event. You don’t need to check for
any events in the loop(). */
void loop() {
lv_task_handler(); // let the GUI do its work
lv_tick_inc(5); // tell LVGL how much time has passed
delay(5); // let this time pass
}
__________________________________________________________________________________
Hi.
Can you share the files using github or google drive?
That would be a better way to make sure the files don’t get messed up with formatting.
I haven’t tried themes with VS Code yet.
Which example were you trying to run~?
Regards,
Sara
Hi,
My apologies about files.
I will have another try at putting one of them in this post the proper way.
Start your code here
/* File: lv_demo_keypad_encoder.c
This is the edited version of keypad encoder
to implement a simple test to run on CodeBlocks
In file main.c, edit the line under Run the demo —
from char * demo_str[] = {“widgets”};
to char * demo_str[] = {“keypad_encoder”};
In file lv_conf.h, at approx line 952, check that it has:
#define LV_USE_DEMO_KEYPAD_AND_ENCODER 1
Edit the header file: lv_demo_keypad_encoder.h
as in the copy that goes with this file.
Open file lv_demo_keypad_encoder.c
and replace everything with this file.
Click Build, then click Run.
*/
#include “lv_demo_keypad_encoder.h”
#if LV_USE_DEMO_KEYPAD_AND_ENCODER
// DECLARATIONS
static lv_style_t style1;
static lv_style_t style2;
//—————————————————————-
// FUNCTIONS
static void my_styles(void)
{
lv_style_init(&style1);
lv_style_set_radius(&style1, 10);
lv_style_set_bg_opa(&style1, 255); // 100% Opaque
lv_style_set_bg_color( &style1, lv_palette_main(LV_PALETTE_RED));
lv_style_init(&style2);
lv_style_set_radius(&style2, 30);
lv_style_set_bg_opa(&style2, 127); // 50% Opaque
lv_style_set_bg_color( &style2, lv_color_make(0,255,0)); // Green
}
// ————————————————————–
static void button_event_cb(lv_event_t * e) // Callback Function
{
lv_event_code_t code = lv_event_get_code(e);
lv_obj_t * button = (lv_obj_t*) lv_event_get_target(e);
lv_obj_t * label = (lv_obj_t*) lv_event_get_user_data(e);
if(code == LV_EVENT_CLICKED) {
static uint8_t counter = 0;
counter++;
lv_label_set_text_fmt(label, “Counter: %d”, counter);
LV_LOG_USER(“Counter: %d”, counter);
}
}
//—————————————————————-
// Core function to draw the GUI
// —————————–
// This function’s name has to be changed in Arduino
void lv_demo_keypad_encoder(void)
{
// Set screen background colour, dark grey
lv_obj_set_style_bg_color(lv_screen_active(), lv_color_make(50,50,50), LV_PART_MAIN);
my_styles(); // Call my_styles function
// Create a Button
lv_obj_t * buttonA = lv_button_create(lv_screen_active());
lv_obj_remove_style_all(buttonA); // Remove default style
lv_obj_align(buttonA, LV_ALIGN_CENTER, 0, 0); // Set position
lv_obj_set_size(buttonA, 120, 50); // Set the size
lv_obj_add_style(buttonA, &style1, 0); // Set the style
// Add a label to buttonA
lv_obj_t * button_label = lv_label_create(buttonA);
lv_label_set_text(button_label, “Click here!”); // Set the labels text
lv_obj_center(button_label);
// Add a text label below the button, set colour locally
lv_obj_t * text_label_counter = lv_label_create(lv_screen_active());
lv_obj_set_style_text_color(text_label_counter, lv_color_white(), LV_PART_MAIN);
lv_label_set_text(text_label_counter, “Counter: 0”);
lv_obj_align(text_label_counter, LV_ALIGN_BOTTOM_MID, 0, -50);
// Assign a callback to buttonA
lv_obj_add_event_cb(buttonA, button_event_cb, LV_EVENT_ALL, text_label_counter);
}
#endif
So that’s one file, but I’m not sure how to exit from “code” mode.
Hi again,
Well, that did not work!
Trouble is, I can’t see what happens until I submit it.
Anyway, I’ve never used github or google drive to share files, so I’ll see if I can work out how to do that.
Regarding themes, the problem is that I cannot find an example to run. I hoped you at Random Nerd might have an example.
Thanks, Ken.
Hello again,
I have uploaded a folder with the files to Google Drive, and made them accessible.
The link is: https://drive.google.com/drive/folders/1Ebv4Y46Kdo95R8JjLJl0brbVgJxTgJlN?usp=sharing
I hope it works. Please let me know.
Ken.
Hi.
Thanks for sharing.
I’m not very familiar with themes at the moment.
But, I found this documentation that might help you get started: https://docs.lvgl.io/master/overview/style.html#themes
I hope this helps.
Regards,
Sara