Content


System architecture

System architecture ith Littlev Graphics Library

Application
Your application which creates the GUI and handles the specific tasks.

LittlevGL
The graphics library itself. Your application can communicate with the library to create a GUI. It contains a HAL (Hardware Abstraction Layer) interface to register your display and input device drivers.

Driver
Besides your specific drivers it contains functions to drive your display, optionally to a GPU and to read the touch pad or buttons.


There are two typical hardware set-ups depending on the MCU has a LCD/TFT driver periphery or not. In both case a frame beffer will be required to store the current image of the screen.

MCU with TFT/LCD driver
If your MCU have a TFT/LCD driver periphery then you can connect a display directly via RGB interface. In this case the frame buffer can be in the internal RAM (if the MCU has enough RAM) or in the external RAM (if the MCU has a memory interface).

External display controller
If the MCU doesn't have TFT/LCD driver then an external display controller (E.g. SSD1963, SSD1306, ILI9341) has to be used. In this case the MCU can communicate with the display controller via Paraller port, SPI or sometimes I2C. The frame buffer usually located in the display controller which savs a lot of RAM for the MCU.


Requirements

Basically any modern microcontroller is suitable to run the Littlev Graphics Library but as a minimal hardware requirement the following considerations can be done:

  • 16, 32 or 64 bit microcontroller or processor
  • 16 MHz clock speed
  • 8 kB RAM for static data and >2 KB RAM for dynamic data (graphical objects)
  • 64 kB program memory (flash)
  • Optionally ~1/10 screen sized memory for internal buffering (at 240 × 320, 16 bit colors it means 15 kB)

The LittlevGL is designed to be highly portable and to not use any external resources:

  • No external RAM required (but supported)
  • No float numbers are used
  • No GPU needed (but supported)
  • Only a single frame buffer is required located in:
    • Internal RAM or
    • External RAM or
    • External display controller's memory

If you would like to reduce the required hardware resources you can:

  • Disable the unused object types to save RAM and ROM
  • Change the size of the graphical buffer to save RAM
  • Use simpler styles to reduce the rendering time

Project set-up

Get the library

The Littlev Graphics Library is available on GitHub: https://github.com/littlevgl/lvgl. You can clone or download the latest version of the library from here or you can use the Download page as well.

The graphics library is the lvgl directory which should be copied into your project

Config file

There is a configuration header file for LittlevGL: lv_conf.h. It sets the library's basic behavior in compile time, disable unused modules and features and adjust the size of memory buffers etc.

Copy lvgl/lv_conf_templ.h next to the lvgl directory and rename it to lv_conf.h. Open the file and delete the first #if and the last #endif to enable the content.

In the config file comments explain the meaning of the options.

Initialization

In order to use the graphics library you have to initialize it and the other components too. To order of the initialization is:

  1. Call lv_init()
  2. Initialize your drivers
  3. Register the display and input devices drivers in LittlevGL. (see below)

Porting the library

To adopt LittlevGL into your project firstly you have to provide some functions and register them in graphics library.

Display interface

To set up a diplay an lv_disp_drv_t variable has to be initialized:
lv_disp_drv_t disp_drv;
lv_disp_drv_init(&disp_drv);           /*Basic initialization*/
disp_drv. ... = ...                    /*Initialize the field here. See below.*/
disp_drv_register(&disp_drv);          /*Register the driver in LittlevGL*/

You can configure the driver for different operation modes. To learn more about the drawing modes visit Drawing and rendering.

Internal buffering (VDB)

The graphics library works with an internal buffering mechanism to create advances graphics features with only one frame buffer. The internal buffer is called VDB (Virtual Display Buffer) and its size can be adjusted in lv_conf.h with LV_VDB_SIZE. When LV_VDB_SIZE > 0 then the internal buffering is used and you have to provide a function which flushes the buffer's content to your display:

disp_drv.disp_flush = my_disp_flush;
.
.
.
void my_disp_flush(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p)
{
    /*TODO Copy 'color_p' to the specified area*/
    
    /*Call 'lv_fluh_ready()' when ready*/
    lv_flush_ready();
}

In the flush function you can use DMA or any hardware to do the flushing in the background, but when the flushing is ready you have to call lv_flush_ready();

Hardware acceleration (GPU)

First of all using GPU is totally optional. But if your MCU supports graphical acceleration then you can use it. The mem_blend and mem_fill fields of the display driver is used to interface with a GPU. The GPU related functions can be used only if internal buffering (VDB) is enabled.

disp_drv.mem_blend = my_mem_blend;  /*Blends two color arrays using opacity*/
disp_drv.mem_fill = my_mem_fill;    /*Fills an array with a color*/ 
.
.
.

void my_mem_blend(lv_color_t * dest, const lv_color_t * src, uint32_t length, lv_opa_t opa)
{
    /*TODO Copy 'src' to 'dest' but blend it with 'opa' alpha */
}

void my_mem_fill(lv_color_t * dest, uint32_t length, lv_color_t color)
{
    /*TODO Fill 'length' pixels in 'dest' with 'color'*/
}

Unbuffered drawing

It is possible to draw directly to a frame buffer when the internal buffering is dispabled (LV_VDB_SIZE = 0).
disp_drv.disp_fill = my_disp_fill;  /*Fill an area in the frame buffer*/
disp_drv.disp_map = my_disp_map;    /*Copy a color_map (e.g. image) into the frame buffer*/ 
.
.
.
void my_disp_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p)
{
    /*TODO Copy 'color_p' to the specified area*/
}

void my_disp_fill(int32_t x1, int32_t y1, int32_t x2, int32_t y2,  lv_color_t color)
{
    /*TODO Fill the specified area with 'color'*/
}

Keep in mind this way during refresh some artifacts can be visible because the layers are drawn after each other. And some high level graphics features like anti-aliasing, opacity or shadows aren't available in this configuration.

If you use an external display controller which supports accelerated filling (e.g. RA8876) then you can use this feature in disp_fill()

Input device interface

To set up an input device an lv_indev_drv_t variable has to be initialized:
lv_indev_drv_t indev_drv;
lv_indev_drv_init(&indev_drv);     /*Basic initialization*/
indev_drv.type = ...               /*See below.*/
indev_drv.read = ...               /*See below.*/
lv_indev_drv_register(&indev_drv);     /*Register the driver in LittlevGL*/

type can be LV_INDEV_TYPE_POINTER (e.g touch pad) or LV_INDEV_TYPE_KEYPAD (e.g. keyboard)
read is a function pointer which will be called periodically to report the current state of an input device. It can also buffer data and return false when no more data to be read or true when the buffer is not empty.

To learn more about input devices visit Input devices

Touch pad, mouse or any pointer

indev_drv.type = LV_INDEV_TYPE_POINTER;
indev_drv.read = my_input_read; 

The read function should look like this:

bool my_input_read(lv_indev_data_t *data) 
{
    data->point.x = touchpad_x;
    data->point.y = touchpad_y;
    data->state = LV_INDEV_EVENT_PR or LV_INDEV_EVENT_REL;
    return false;  			/*No buffering so no more data read*/
} 

Keypad or keyboard

indev_drv.type = LV_INDEV_TYPE_KEYPAD;
indev_drv.read_fp = my_input_read;  

The read function should look like this:

bool keyboard_read(lv_indev_data_t *data) 
{
    data->key = last_key();
        
    if(key_pressed()) {
        data->state = LV_INDEV_EVENT_PR;
    } else {
        data->state = LV_INDEV_EVENT_REL;
    }

    return false;   /*No buffering so no more data read*/
} 

To use a keyboard:

  • LV_OBJ_GROUP has to be enabled in lv_conf.h
  • An object group has to be created: lv_group_create() and objects have to be added: lv_group_add_obj()
  • The created group has to be assigned to an input device: lv_indev_set_group(my_indev, group1);
  • Use LV_GROUP_KEY_... to navigate among the objects in the group

Visit Touchpad-less navigation to learn more.

Tick interface

The LittlevGL uses a system tick. Call the lv_tick_inc(tick_period) function periodically and tell the call period in millisecinds. For example if called in every milliseconds:
lv_tick_inc(1)

Task handling

To handle the tasks of LittlevGL you need to call lv_task_handler() periodically in:
  • while(1) of main() function
  • timer interrupt periodically
  • an OS task periodically
The timing is not critical but is should be about 5 milliseconds

Porting example

Here you will find an example for porting: Porting tutorial.


Continue with the basics of the graphics library Basics

LittlevGL - Open-source Embedded GUI Library

LittlevGL is a free and open-source graphics library providing everything you need to create embedded GUI with easy-to-use graphical elements, beautiful visual effects and low memory footprint.

If you like LittlevGL, please
support its deveopment!


The founder of Littlev Graphics Library (LittlevGL) and related software modules is:
Gábor Kiss-Vámosi
All Rights Reserved ©  2018 Hungary