top of page
Writer's pictureRamesh G

1.28 inch GC9A01 Round LCD with ESP32 and LVGL UI Part3

Updated: Oct 24


Here to learn to create a 240x240 pixel GC9A01 Round LCD display using an ESP32 with the LVGL library and Bodmer's TFT_eSPI library, enabling interactive UIs for your projects. The LVGL Light and Versatile Graphics Library) is a popular free and open-source embedded graphics library to create UIs for Embedded boards.

In this Setting up LVGL (Light and Versatile Graphics Library) on an ESP32 with a TFT 1.28 inch GC9A01 Round LCD display is a great way to create interactive user interfaces for your projects. Here’s a step-by-step guide to help you get started.


Demo:







Components Required

ESP-32 Module (38Pin)

1.28 Inch Round Display Module GC9A01 7P 240X240 SPI

10K Potentiometer

Jumper Wires


Circuit Diagram

GC9A01 7P 240X240 SPI

This is a 1.28 Inch Round Display Module GC9A01 7P 240X240 SPI . This module is composed of a TFT LCD Panel, driver ICs, FPC and a Backlight unit. It uses a full-color LCD screen with a circular appearance and is suitable for making watches, clocks, or measuring instruments. It can also connect with ESP32, Raspberry Pi, or Arduino.

Such displays support different communication protocols providing flexibility for integration into various applications. With vibrant colors and excellent clarity, these display modules are suitable for a wide array of projects, from consumer electronics to industrial controls.


Features :

  • High-Resolution Options

  • Vibrant Colors and Clarity

  • Compact and Lightweight

  • Reliable Performance

  • Customization Potential




Specifications:

  • Display Type: TFT

  • Resolution: 240 x 240

  • Screen Size: (inch) 1.28

  • No. of Pins: 7

  • Communication Protocol: SPI

  • IC Chip: GC9A01

  • Outside Diameter: (OD) mm 38

  • Operating Temperature: (°C) -20 to +70

  • Storage Temperature: (C) -30 to 80

  • Weight (g): 20g

Pin Configuration:

  1. GND : LCD Power ground

  2. VCC : LCD power supply is positive (3.3V/5V)

  3. SCL : LCD SPI bus clock signal

  4. SDA : LCD SPI bus write data signal

  5. RES : LCD reset control signal(Low level reset,The module has a reset circuit, and this pin can not be connected)

  6. DC : LCD register / data selection control signal (Low level: register, high level: data)

  7. CS : LCD chip select control signal (low level enable)



Hardware Requirements

  1. ESP32 Board: Any variant should work, but make sure it has enough GPIO pins.

  2. TFT LCD Touchscreen: Common models include ILI9488

  3. Connecting Wires: Jumper wires for connections.

  4. Breadboard (optional): For easier connections.


Software Requirements

  1. Arduino IDE: Make sure you have the latest version.

    Select “File>Preferences>settings>Additional Boards Manager URLs” to fill the link.

    Here are the steps to install the ESP32 board in Arduino IDE: 


    1. Open the Arduino IDE  

    2. Select File and then Preferences 

    3. Find the Additional Board Manager URLs field and activate the text box 

    4. Add the URL to the field 

    5. Click OK to save the changes 

       

     https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_dev_index.json,

    https://arduino.esp8266.com/stable/package_esp8266com_index.json,

    https://espressif.github.io/arduino-esp32/package_esp32_index.json



  2. LVGL Library: Available through the Library Manager in the Arduino IDE.


Configuring LVGL

  1. LVGL Configuration: You may need to configure LVGL for your specific display and touch screen. Create a lv_conf.h file or modify the existing one in the LVGL library folder:

    • Set LVGL_DISPLAY_HOR_RES and LVGL_DISPLAY_VER_RES to match your display's resolution.

    • Configure the display and touch input settings based on your library (e.g., TFT_eSPI settings).


  2. TFT_eSPI Configuration:

    A feature rich Arduino IDE compatible graphics and fonts library for 32-bit processors. The library is targeted at 32-bit processors, it has been performance optimised for RP2040, STM32, ESP8266 and ESP32 types, other 32-bit processors may be used but will use the slower generic Arduino interface calls. The library can be loaded using the Arduino IDE's Library Manager. Direct Memory Access (DMA) can be used with the ESP32, RP2040 and STM32 processors with SPI interface displays to improve rendering performance. DMA with a parallel interface (8 and 16-bit) is only supported with the RP2040.

     Go to the TFT_eSPI library folder and open the User_Setup.h file to configure the pins according to your wiring.


TFT Pin             ESP32 Pin

VCC                     3.3V

GND                    GND

CS                       GPIO 5

RESET                GPIO 2

DC/RS                GPIO 17

SDI(MOSI)          GPIO 23

SCK                    GPIO 18



Arduino Code

Here’s a basic example to initialize the display and create a simple button using LVGL:


Example 1.

#########################################################################

#include <lvgl.h>

#include <TFT_eSPI.h>

#include <ui.h>


/*Don't forget to set Sketchbook location in File/Preferences to the path of your UI project (the parent foder of this INO file)*/


/*Change to your screen resolution*/

static const uint16_t screenWidth  = 240;

static const uint16_t screenHeight = 240;


static lv_disp_draw_buf_t draw_buf;

static lv_color_t buf[ screenWidth * screenHeight / 10 ];


TFT_eSPI tft = TFT_eSPI(screenWidth, screenHeight); /* TFT instance */


#if LV_USE_LOG != 0

/* Serial debugging */

void my_print(const char * buf)

{

    Serial.printf(buf);

    Serial.flush();

}


/* Display flushing */

void my_disp_flush( lv_disp_drv_t disp, const lv_area_t area, lv_color_t *color_p )

{

    uint32_t w = ( area->x2 - area->x1 + 1 );

    uint32_t h = ( area->y2 - area->y1 + 1 );


    tft.startWrite();

    tft.setAddrWindow( area->x1, area->y1, w, h );

    tft.pushColors( ( uint16_t  )&color_p->full, w h, true );

    tft.endWrite();


    lv_disp_flush_ready( disp );

}


/*Read the touchpad*/

void my_touchpad_read( lv_indev_drv_t  indev_driver, lv_indev_data_t  data )

{

    uint16_t touchX = 0, touchY = 0;


    bool touched = false;//tft.getTouch( &touchX, &touchY, 600 );


    if( !touched )

    {

        data->state = LV_INDEV_STATE_REL;

    }

    else

    {

        data->state = LV_INDEV_STATE_PR;


        /*Set the coordinates*/

        data->point.x = touchX;

        data->point.y = touchY;


        Serial.print( "Data x " );

        Serial.println( touchX );


        Serial.print( "Data y " );

        Serial.println( touchY );

    }

}


void update_pitch(lv_obj_t ui_img_pitch_scale, lv_obj_t ui_Label_pitch, int pitch_value, int pitch_rotation)

{

    // Calculate the rotation angle in degrees for pitch

    int rotation_angle = pitch_rotation / 10; // Each 100 units corresponds to 10 degrees

    lv_img_set_angle(ui_img_pitch_scale, rotation_angle * 10); // LVGL uses 0.1 degree units


    // Calculate the Y position

    int y_position = pitch_value * 2; // Each 10 pixels corresponds to 5 units

    lv_obj_set_y(ui_img_pitch_scale, y_position);


    // Update the pitch label with the current pitch value

    char buf[16];

    snprintf(buf, sizeof(buf), "%d", pitch_value);

    lv_label_set_text(ui_Label_pitch, buf);

}


void update_roll(lv_obj_t ui_img_roll_scale, lv_obj_t ui_Label_roll, int roll_value)

{

    // Calculate the rotation angle in degrees

    int rotation_angle = roll_value; // Each unit corresponds to 1 degree

    lv_img_set_angle(ui_img_roll_scale, rotation_angle * 10); // LVGL uses 0.1 degree units


    // Display positive degree on the right and negative degree on the left

    int display_angle = -roll_value; // Invert the roll value for display


    // Update the roll label with the current rotation angle in degrees

    char buf[16];

    snprintf(buf, sizeof(buf), "%d", display_angle);

    lv_label_set_text(ui_Label_roll, buf);

}


void update_pitch_and_roll(lv_obj_t ui_img_pitch_scale, lv_obj_t ui_img_roll_scale, lv_obj_t ui_Label_pitch, lv_obj_t ui_Label_roll, int pitch_value, int pitch_rotation, int roll_value)

{

    update_pitch(ui_img_pitch_scale, ui_Label_pitch, pitch_value, pitch_rotation);

    update_roll(ui_img_roll_scale, ui_Label_roll, roll_value);

}


void mock_data(int &pitch_value, int &pitch_rotation, int &roll_value, int speed_factor)

{

    static bool increasing_pitch = true;

    static bool increasing_pitch_rotation = true;

    static bool increasing_roll = true;


    // Update pitch

    if (increasing_pitch)

    {

        pitch_value += speed_factor;

        if (pitch_value >= 20) { // 20 units is the max pitch value

            increasing_pitch = false;

        }

    }

    else

    {

        pitch_value -= speed_factor;

        if (pitch_value <= -20) { // -20 units is the min pitch value

            increasing_pitch = true;

        }

    }


    // Update pitch rotation

    if (increasing_pitch_rotation)

    {

        pitch_rotation += 10 * speed_factor;

        if (pitch_rotation >= 900) { // 900 units is the max pitch rotation

            increasing_pitch_rotation = false;

        }

    }

    else

    {

        pitch_rotation -= 10 * speed_factor;

        if (pitch_rotation <= -900) { // -900 units is the min pitch rotation

            increasing_pitch_rotation = true;

        }

    }


    // Update roll

    if (increasing_roll)

    {

        roll_value -= speed_factor; // Decrease roll value for right rotation

        if (roll_value <= -90) { // -90 degrees is the max right roll value

            increasing_roll = false;

        }

    }

    else

    {

        roll_value += speed_factor; // Increase roll value for left rotation

        if (roll_value >= 90) { // 90 degrees is the max left roll value

            increasing_roll = true;

        }

    }

}


void setup()

{

    Serial.begin( 115200 ); /* prepare for possible serial debug */


    String LVGL_Arduino = "Hello Arduino! ";

    LVGL_Arduino += String('V') + lv_version_major() + "." + lv_version_minor() + "." + lv_version_patch();


    Serial.println( LVGL_Arduino );

    Serial.println( "I am LVGL_Arduino" );


    lv_init();


#if LV_USE_LOG != 0

    lv_log_register_print_cb( my_print ); /* register print function for debugging */


    tft.begin();          /* TFT init */

    tft.setRotation( 3 ); /* Landscape orientation, flipped */


    lv_disp_draw_buf_init( &draw_buf, buf, NULL, screenWidth * screenHeight / 10 );


    /*Initialize the display*/

    static lv_disp_drv_t disp_drv;

    lv_disp_drv_init( &disp_drv );

    /*Change the following line to your display resolution*/

    disp_drv.hor_res = screenWidth;

    disp_drv.ver_res = screenHeight;

    disp_drv.flush_cb = my_disp_flush;

    disp_drv.draw_buf = &draw_buf;

    lv_disp_drv_register( &disp_drv );


    /*Initialize the (dummy) input device driver*/

    static lv_indev_drv_t indev_drv;

    lv_indev_drv_init( &indev_drv );

    indev_drv.type = LV_INDEV_TYPE_POINTER;

    indev_drv.read_cb = my_touchpad_read;

    lv_indev_drv_register( &indev_drv );



    ui_init();


    Serial.println( "Setup done" );

    // Initialize with level pitch, pitch rotation, and no roll

    int pitch_value = 0;

    int pitch_rotation = 0;

    int roll_value = 0;


    update_pitch_and_roll(ui_img_pitch_scale, ui_img_roll_scale, ui_Label_pitch, ui_Label_roll, pitch_value, pitch_rotation, roll_value);

}


void loop()

{

    lv_timer_handler(); /* let the GUI do its work */

    delay(5);

// Example updates for testing

    static int pitch_value = 0;

    static int pitch_rotation = 0;

    static int roll_value = 0;


    // Simulate pitch and roll changes

    int speed_factor = 1; // Adjust this value to control speed of mock data generation

    mock_data(pitch_value, pitch_rotation, roll_value, speed_factor);


    update_pitch_and_roll(ui_img_pitch_scale, ui_img_roll_scale, ui_Label_pitch, ui_Label_roll, pitch_value, pitch_rotation, roll_value);

}


#########################################################################





Next Example:


Final Steps

  1. Upload the code to your ESP32 using the Arduino IDE.

  2. Open the Serial Monitor to check for any debug messages.


Tips

  • Adjust the pin assignments based on your wiring.

  • Explore LVGL's extensive documentation for more UI elements and functionalities.

  • Use LVGL's built-in tools to design and customize your interfaces.

This should give you a solid start on using LVGL with an ESP32 and a TFT LCD Happy coding!


41 views0 comments

Comments


bottom of page