Skip to content

LVGL Designer

Introduction

The LVGL Designer API, accessible via MikroSDK.Graphics.LVGL, offers a comprehensive and flexible solution for building advanced graphical user interfaces (GUIs) on microcontroller platforms. The API is built on top of the LVGL (Light and Versatile Graphics Library), which is widely recognized for its efficiency and versatility in rendering high-quality, responsive graphical elements on resource-constrained devices.

This API enables developers to create dynamic, visually appealing interfaces with minimal effort, abstracting the complexities of direct hardware-level graphics handling. It supports a wide range of graphical components, such as buttons, sliders, and charts, and allows for seamless customization and theme application, making it ideal for creating professional-grade interfaces in embedded applications.

The LVGL Designer simplifies interaction with the LVGL library through NECTO Studio, integrating essential features like widget management, event handling, and display control. Additionally, it automates the configuration of input devices (e.g., touchscreens) and timers, ensuring the GUI remains responsive and functional.

This library is indispensable for any project requiring user interaction via display, ranging from simple menu systems to sophisticated, real-time graphical dashboards.

API Name

  • LVGL

Location of Files and Directories

Prerequisites

  • Library Manager:

    • LVGL, LVGL.Common and GraphicLibrary libraries are automatically selected in the Library Manager inside NECTO Studio once a developer selected LVGL Designer as a project type.
  • Headers:

    • All required headers are automatically selected and included by NECTO Studio when you choose LVGL Designer type of application.
    • Alternatively, you can manually include the lvgl.h header to access LVGL functionalities.
  • CMakeLists:

    • You do not have to perform anything, configuration (CMake) file is already taken care of automatically while you performed the first task in this Prerequisites!
    • You can ensure that your CMakeLists.txt includes the necessary configurations to link against the LVGL library.

Code Examples

  • How to Start Writing GUI-based Applications in NECTO IDE?
/* Project name:
 *   How to Start Writing GUI-based Applications in NECTO IDE?
 * Copyright:
 *   (c) MIKROE, 2024.
 * Description:
 *   This code provides a basic starting point for developing a GUI-based
 *   application using the LVGL library in NECTO IDE. The application initializes
 *   the LVGL library, configures display and input devices, and demonstrates
 *   how to display a simple screen. The LVGL task handler runs in a loop to
 *   keep the GUI responsive.
 *
 * Library dependencies:
 *   - lvgl (Light and Versatile Graphics Library)
 *   - display_lvgl (MikroSDK integration for LVGL)
 *   - lv_port_indev (Input device handler)
 *   - 1ms_Timer (For tick-based timing in LVGL)
 *   - screens (Screen management for the GUI)
 *
 * How to test this code example:
 *   1. Open [NECTO Studio](https://www.mikroe.com/necto) IDE.
 *   2. Create new `LVGL Designer ` type of a project.
 *   3. Copy and paste this code into the main source file.
 *   4. Build the project, open [Planet Debug](https://www.mikroe.com/planet-debug)
 *      feature within NECTO IDE [press `CTRL + 6`], and flash it to a supported
 *      [Dev board](https://www.mikroe.com/development-boards-v8) which has
 *      [TFT display](https://www.mikroe.com/accessories/tft-displays?type*=discon,discon)
 *      attached to it or choose [Mikromedia](https://www.mikroe.com/mikromedia)
 *      device which has built-in display.
 *   5. Upon startup, the main screen will be displayed (white screen by default).
 *   6. The LVGL task handler ensures smooth updates to the GUI.
 * BONUS:
 *      While in this project, navigate to `Design` icon on the left-hand
 *      side of NECTO (the main vertical toolbar on the left),
 *      insert GUI components (Box, Button, Slider,...),
 *      save the GUI modifications and flash the project again!
 */

/**
 * Any initialization code needed for MCU to function properly.
 * Do not remove this line or clock might not be set correctly.
 */
#ifdef PREINIT_SUPPORTED
#include "preinit.h"  // Pre-initialization for specific MCUs.
#endif

#ifdef __GNUC__
#include "delays.h"   // Delay functions for time-sensitive operations.
#endif

#include "display_lvgl.h"    // LVGL display driver.
#include "lv_port_indev.h"   // LVGL input device port initialization.
#include "1ms_Timer.h"       // Timer to handle 1ms tick events for LVGL.
#include "screens.h"         // GUI screen management for the application.

void board_init()
{
    lv_init();                 // Initialize the LVGL library.
    lv_port_disp_init();        // Initialize the display port (connects LVGL to the display).
    lv_port_indev_init();       // Initialize the input devices (e.g., touch input).
    timerInit();                // Configure 1ms interrupt for LVGL tick handling.
}

void application_init()
{
    board_init();               // Call the board initialization function.
    init_screens();             // Initialize all available screens.
    show_main_screen();         // Display the main screen of the application.

    // Begin application-specific GUI code

    // Application-specific GUI initialization ends here
}

int main(void)
{
    /* Do not remove this line or clock might not be set correctly. */
    #ifdef PREINIT_SUPPORTED
    preinit();  // Pre-initialization for clock setup.
    #endif

    application_init();  // Initialize the application components and display the main screen.

    /////////////////////////////LVGL specific timing routine (DO NOT DELETE)/////////////////////////
    while (1)
    {
        lv_task_handler();  // Process LVGL tasks to keep the GUI responsive.
        Delay_ms(5);        // Wait for 5 milliseconds between task executions.
    }
    /////////////////////////////////////////////////////////////////////////////////////////////////
}

/**
 * 1ms timer interrupt routine for LVGL tick management.
 * This ISR increments the tick and processes input.
 */
static volatile uint32_t msCount = 0;
INTERRUPT_ROUTINE
{
    msCount++;  // Increment the millisecond counter.

    if (5 == msCount) {
        msCount = 0;          // Reset the counter every 5ms.
        lv_tick_inc(5);       // Notify LVGL that 5ms have passed.
        process_tp();         // Process touch input (if applicable).
    }
    CLEAR_FLAG;  // Clear the interrupt flag (necessary for most MCUs).
}
  • NECTO's "LVGL Designer"-based "Hello world" label example
/**
 * Project name:
 *   NECTO's "LVGL Designer"-based "Hello world" label example
 *
 * Copyright:
 *   (c) [LVGL](https://lvgl.io/).
 *
 * Description:
 *   This code demonstrates how to create a "Hello world" label
 *   using LVGL on an embedded system. The label is aligned to the
 *   center of the screen and the background color is changed for
 *   better visibility.
 *   [Original code example](https://docs.lvgl.io/master/examples.html#a-very-simple-hello-world-label)
 *
 * Library dependencies:
 *   - Make sure `GraphicLibrary`, `LVGL` and `LVGL.Common` libraries are enabled in NECTO's
 *     Library Manager to ensure a successful build.
 *
 * How to test this code example:
 *   1. Open [NECTO Studio](https://www.mikroe.com/necto) IDE.
 *   2. Create new `LVGL Designer ` type of a project.
 *   3. Copy and paste this code into the main source file.
 *   4. Build the project, open [Planet Debug](https://www.mikroe.com/planet-debug)
 *      feature within NECTO IDE [press `CTRL + 6`], and flash it to a supported
 *      [Dev board](https://www.mikroe.com/development-boards-v8) which has
 *      [TFT display](https://www.mikroe.com/accessories/tft-displays?type*=discon,discon)
 *      attached to it or choose [Mikromedia](https://www.mikroe.com/mikromedia)
 *      device which has built-in display.
 *   5. Upon startup, the "Hello World" label will be displayed (with colored - blue color - background).
 *
 * NOTE: This example demonstrates manual label generation; for automatic label generation,
 *       you should navigate to `Design` on the left-hand side navigation bar, anc choose
 *       `Label` built-in component (right-hand navigation bar in `Design` interface)
 */

/**
 * MCU-specific initialization.
 * Do not remove this line or clock settings might not be correct.
 */
#ifdef PREINIT_SUPPORTED
#include "preinit.h"  // Pre-initialization for specific MCUs.
#endif

#ifdef __GNUC__
#include "delays.h"   // Delay functions for timing operations.
#endif

#include "display_lvgl.h"    // LVGL display driver.
#include "lv_port_indev.h"   // Input device initialization.
#include "1ms_Timer.h"       // 1ms timer for LVGL tick handling.
#include "screens.h"         // Screen management for the GUI.

/**
 * Function to create a "Hello world" label.
 */
void lv_example_get_started_1(void)
{
    /* Change the background color of the active screen */
    lv_obj_set_style_bg_color(lvgl_main_screen_ui.main_screen, lv_color_hex(0x003a57), LV_PART_MAIN);

    /* Create a white label, set the text, and center it */
    lv_obj_t * label = lv_label_create(lvgl_main_screen_ui.main_screen);
    lv_label_set_text(label, "Hello world");
    lv_obj_set_style_text_color(lvgl_main_screen_ui.main_screen, lv_color_hex(0xffffff), LV_PART_MAIN);
    lv_obj_align(label, LV_ALIGN_CENTER, 0, 0);
}

/**
 * Function to initialize board components like display and input devices.
 */
void board_init()
{
    lv_init();                  // Initialize the LVGL library.
    lv_port_disp_init();         // Initialize the display port.
    lv_port_indev_init();        // Initialize the input devices (e.g., touch input).
    timerInit();                 // Setup 1ms tick timer for LVGL.
}

/**
 * Application initialization. Configures screens and displays the main screen.
 */
void application_init()
{
    board_init();                // Call board initialization.
    init_screens();              // Initialize all available screens.
    show_main_screen();          // Show the main screen of the application.

    // Begin application-specific GUI code

    // Application-specific GUI initialization ends here
}

int main(void)
{
    /* Ensure the MCU clock is set correctly */
    #ifdef PREINIT_SUPPORTED
    preinit();  // Pre-initialization for MCU clock setup.
    #endif

    application_init();           // Initialize application and show the main screen.
    lv_example_get_started_1();   // Create the "Hello World" label.

    /////////////////////////// LVGL Task Handler Loop ///////////////////////////
    while (1)
    {
        lv_task_handler();        // Process LVGL tasks for a responsive GUI.
        Delay_ms(5);              // Wait for 5 milliseconds between task executions.
    }
    /////////////////////////////////////////////////////////////////////////////
}

/**
 * 1ms timer interrupt routine for LVGL tick management.
 * This ISR increments the tick and processes input.
 */
static volatile uint32_t msCount = 0;
INTERRUPT_ROUTINE
{
    msCount++;  // Increment the millisecond counter.

    if (5 == msCount) {
        msCount = 0;             // Reset counter every 5ms.
        lv_tick_inc(5);          // Inform LVGL that 5ms have passed.
        process_tp();            // Process touch input if applicable.
    }
    CLEAR_FLAG;  // Clear the interrupt flag (necessary for most MCUs).
}
  • NECTO's "LVGL Designer"-based Button with a Label and React on Click Event example
/**
 * Project name:
 *   NECTO's "LVGL Designer"-based Button with a Label and React on Click Event example
 *
 * Copyright:
 *   (c) [LVGL](https://lvgl.io/).
 *
 * Description:
 *   This example demonstrates how to create a button with a label and
 *   update the label text when the button is clicked using LVGL. The
 *   label text is updated to display the number of clicks.
 *   [Original code example](https://docs.lvgl.io/master/examples.html#a-button-with-a-label-and-react-on-click-event)
 *
 * Library dependencies:
 *   - Make sure `GraphicLibrary`, `LVGL` and `LVGL.Common` libraries are enabled in NECTO's
 *     Library Manager to ensure a successful build.
 *
 * How to test this code example:
 *   1. Open [NECTO Studio](https://www.mikroe.com/necto) IDE.
 *   2. Create new `LVGL Designer ` type of a project.
 *   3. Copy and paste this code into the main source file.
 *   4. Build the project, open [Planet Debug](https://www.mikroe.com/planet-debug)
 *      feature within NECTO IDE [press `CTRL + 6`], and flash it to a supported
 *      [Dev board](https://www.mikroe.com/development-boards-v8) which has
 *      [TFT display](https://www.mikroe.com/accessories/tft-displays?type*=discon,discon)
 *      attached to it or choose [Mikromedia](https://www.mikroe.com/mikromedia)
 *      device which has built-in display.
 *   5. Upon startup, the button with label will be displayed; press and observe click event.
 *
 * NOTE: This example demonstrates manual button generation; for automatic button generation,
 *       you should navigate to `Design` on the left-hand side navigation bar, and choose
 *       `Button` built-in component (right-hand navigation bar in `Design` interface)
 */

/**
 * MCU-specific initialization.
 * Do not remove this line or clock settings might not be correct.
 */
#ifdef PREINIT_SUPPORTED
#include "preinit.h"  // Pre-initialization for specific MCUs.
#endif

#ifdef __GNUC__
#include "delays.h"   // Delay functions for timing operations.
#endif

#include "display_lvgl.h"    // LVGL display driver.
#include "lv_port_indev.h"   // Input device initialization.
#include "1ms_Timer.h"       // 1ms timer for LVGL tick handling.
#include "screens.h"         // Screen management for the GUI.

/**
 * Event handler for button click events.
 * Updates the label text with the number of clicks.
 */
static void btn_event_cb(lv_event_t * e)
{
    lv_event_code_t btn_event = lv_event_get_code(e);
    lv_obj_t * btn = lv_event_get_target(e);

    if(btn_event == LV_EVENT_CLICKED) {
        static uint8_t cnt = 0;
        cnt++;

        /* Get the first child of the button which is the label and update its text */
        lv_obj_t * label = lv_obj_get_child(btn, 0);
        lv_label_set_text_fmt(label, "Button: %d", cnt);
    }
}

/**
 * Function to create a button with a label and assign a click event callback.
 */
void lv_example_get_started_2(void)
{
    lv_obj_t * btn = lv_btn_create(lvgl_main_screen_ui.main_screen);  /* Add a button to the current screen */
    lv_obj_set_pos(btn, 100, 100);                                    /* Set the button's position */
    lv_obj_set_size(btn, 120, 50);                                    /* Set the button's size */
    lv_obj_add_event_cb(btn, btn_event_cb, LV_EVENT_ALL, NULL);       /* Assign the event callback to the button */

    lv_obj_t * label = lv_label_create(btn);                          /* Add a label to the button */
    lv_label_set_text(label, "Button");                               /* Set the label's initial text */
    lv_obj_center(label);                                             /* Center the label on the button */
}

/**
 * Function to initialize board components like display and input devices.
 */
void board_init()
{
    lv_init();                  // Initialize the LVGL library.
    lv_port_disp_init();         // Initialize the display port.
    lv_port_indev_init();        // Initialize the input devices (e.g., touch input).
    timerInit();                 // Setup 1ms tick timer for LVGL.
}

/**
 * Application initialization. Configures screens and displays the main screen.
 */
void application_init()
{
    board_init();                // Call board initialization.
    init_screens();              // Initialize all available screens.
    show_main_screen();          // Show the main screen of the application.

    // Begin application-specific GUI code
    lv_example_get_started_2();  // Create the button and label, and assign click event.
    // Application-specific GUI initialization ends here
}

int main(void)
{
    /* Ensure the MCU clock is set correctly */
    #ifdef PREINIT_SUPPORTED
    preinit();  // Pre-initialization for MCU clock setup.
    #endif

    application_init();           // Initialize application and show the main screen.

    /////////////////////////// LVGL Task Handler Loop ///////////////////////////
    while (1)
    {
        lv_task_handler();        // Process LVGL tasks for a responsive GUI.
        Delay_ms(5);              // Wait for 5 milliseconds between task executions.
    }
    /////////////////////////////////////////////////////////////////////////////
}

/**
 * 1ms timer interrupt routine for LVGL tick management.
 * This ISR increments the tick and processes input.
 */
static volatile uint32_t msCount = 0;
INTERRUPT_ROUTINE
{
    msCount++;  // Increment the millisecond counter.

    if (5 == msCount) {
        msCount = 0;             // Reset counter every 5ms.
        lv_tick_inc(5);          // Inform LVGL that 5ms have passed.
        process_tp();            // Process touch input if applicable.
    }
    CLEAR_FLAG;  // Clear the interrupt flag (necessary for most MCUs).
}
  • A label and buton with React on Click Event example
/**
 * Project name:
 *   A label and buton with `React on Click` Event example
 *
 * Copyright:
 *   (c) [LVGL](https://lvgl.io/).
 *
 * Description:
 *   A label is created on the screen that initially displays "Hello, World!".
 *   A button is added beneath the label, and when clicked, the label text changes to "Button Pressed!".
 *
 * Library dependencies:
 *   - Make sure `GraphicLibrary`, `LVGL` and `LVGL.Common` libraries are enabled in NECTO's
 *     Library Manager to ensure a successful build.
 *
 * How to test this code example:
 *   1. Open [NECTO Studio](https://www.mikroe.com/necto) IDE.
 *   2. Create new `LVGL Designer ` type of a project.
 *   3. Copy and paste this code into the main source file.
 *   4. Build the project, open [Planet Debug](https://www.mikroe.com/planet-debug)
 *      feature within NECTO IDE [press `CTRL + 6`], and flash it to a supported
 *      [Dev board](https://www.mikroe.com/development-boards-v8) which has
 *      [TFT display](https://www.mikroe.com/accessories/tft-displays?type*=discon,discon)
 *      attached to it or choose [Mikromedia](https://www.mikroe.com/mikromedia)
 *      device which has built-in display.
 *   5. Upon startup, the button with label will be displayed; press and observe click event.
 *
 * NOTE: This example demonstrates manual label and button generation; for automatic
 *       label and button generation, you should navigate to `Design` on the left-hand
 *       side navigation bar, and choose `Label` and `Button` built-in components
 *       (right-hand navigation bar in `Design` interface)
 */


/**
 * Any initialization code needed for MCU to function properly.
 * Do not remove this line or clock might not be set correctly.
 */
#ifdef PREINIT_SUPPORTED
#include "preinit.h"
#endif

#ifdef __GNUC__
#include "delays.h"
#endif

#include "display_lvgl.h"
#include "lv_port_indev.h"
#include "1ms_Timer.h"
#include "screens.h"

static lv_obj_t *label;

/**
 * Event callback for button press
 */
static void btn_event_cb(lv_event_t *event) {
    lv_obj_t *btn = lv_event_get_target(event);  // Get button object
    if (lv_event_get_code(event) == LV_EVENT_CLICKED) {
        lv_label_set_text(label, "Button Pressed!");  // Update label text
    }
}

/**
 * Label and Button creation
 */
void lv_example_create_label_and_button( void ) {
    // Create a label
    label = lv_label_create(lv_scr_act());        // Create label on active screen
    lv_label_set_text(label, "Hello, World!");    // Set initial text
    lv_obj_align(label, LV_ALIGN_CENTER, 0, -40); // Align label to center (with Y offset)

    // Create a button
    lv_obj_t *btn = lv_btn_create(lv_scr_act());  // Create button on active screen
    lv_obj_align(btn, LV_ALIGN_CENTER, 0, 40);    // Align button below the label
    lv_obj_add_event_cb(btn, btn_event_cb, LV_EVENT_CLICKED, NULL);  // Attach event callback

    // Add a label on top of the button
    lv_obj_t *btn_label = lv_label_create(btn);   // Create label inside the button
    lv_label_set_text(btn_label, "Click Me!");    // Set text on button
}

void board_init()
{
    lv_init();
    lv_port_disp_init();
    lv_port_indev_init();
    // Configure 1ms interrupt.
    timerInit();
}

void application_init()
{
    //Initialize driver
    board_init();
    //Initialize all available screens
    init_screens();
    //Show main screen. If you want any other screen to show call its show function
    show_main_screen();

    // Begin application-specific GUI code
    lv_example_create_label_and_button();
    // Application-specific GUI initialization ends here
}

int main(void)
{
    /* Do not remove this line or clock might not be set correctly. */
    #ifdef PREINIT_SUPPORTED
    preinit();
    #endif

    //Call all initialization methods
    application_init();

    /////////////////////////////LVGL specific timing routine (DO NOT DELETE)/////////////////////////
    while (1)
    {
        lv_task_handler();
        Delay_ms(5);
    }
    /////////////////////////////////////////////////////////////////////////////////////////////////
}

static volatile uint32_t msCount = 0;
INTERRUPT_ROUTINE
{
    msCount++;

    if (5 == msCount) {
        msCount = 0;
        lv_tick_inc(5);
        process_tp();
    }
    CLEAR_FLAG;
}