Implement SquareLine/LVGL project to ESP32-2424S012 module, GA9A01 / CST816D drivers

Description

I bought from China a ESP32-2424S012 module. The screen part is working fine it display what I have created with SquareLine Studio, but I have nothing from the touchpad. I think that the touchpad doesn’t communicate properly with LVGL library, because the read function does not seems to be called ever.

Thank you in advance for your help!

What MCU/Processor/Board and compiler are you using?

I am using the ESP32-2424S012 module with GC9A01 display and CST816D touchpad.
Coded with Arduino IDE

What LVGL version are you using?

8.3.10

What do you want to achieve?

I wish to create a template code for this module allowing the use of any ui from SquareLine Studio.

What have you tried so far?

I tested the touchpad with a very simple Arduino’s sketch, and it is returning properly every touch with the good coordinates.

TouchPad’s test code:

#include "Arduino.h"
#include "CST816D.h"

#define I2C_SDA 4
#define I2C_SCL 5
#define TP_INT 0
#define TP_RST 1

CST816D touch(I2C_SDA, I2C_SCL, TP_RST, TP_INT);

void setup()
{
   USBSerial.begin( 115200 );
   touch.begin();
   USBSerial.println( "I am LVGL_Arduino" );
 }

 bool FingerNum;
 uint8_t gesture;
 uint16_t touchX, touchY;

 void loop()
 {
   FingerNum = touch.getTouch(&touchX, &touchY, &gesture);
   if (FingerNum)
   {
        USBSerial.print("Data x ");
        USBSerial.println(touchX);

        USBSerial.print("Data y ");
        USBSerial.println(touchY);

        USBSerial.print("Gesture ");
        USBSerial.println(gesture);
   }
   delay(100);
 }

I put println in the my_touchpad_read() function but it seems that the function is never been called.

void my_touchpad_read(lv_indev_drv_t *indev_driver, lv_indev_data_t *data)
{
  USBSerial.println( "read !" );
  bool touched;
  uint8_t gesture;
  uint16_t touchX, touchY;

  touched = touch.getTouch(&touchX, &touchY, &gesture);

  if (!touched)
  {
    USBSerial.print("Not Touched");
    data->state = LV_INDEV_STATE_REL;
  }
  else
  {
    data->state = LV_INDEV_STATE_PR;

    data->point.x = touchX;
    data->point.y = touchY;

    USBSerial.print("Data x ");
    USBSerial.println(touchX);

    USBSerial.print("Data y ");
    USBSerial.println(touchY);
    }
}

Code to reproduce

#include <lvgl.h>
#include <TFT_eSPI.h>
#include "ui.h"
#include "CST816D.h"

#define TFT_BLK 3
#define I2C_SDA 4
#define I2C_SCL 5
#define TP_INT 0
#define TP_RST 1

CST816D touch(I2C_SDA, I2C_SCL, TP_RST, TP_INT);

/*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
/* USBSerial debugging */
void my_print(const char * buf)
{
    USBSerial.printf(buf);
    USBSerial.flush();
}
#endif

/* 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)
{
  USBSerial.println( "read !" );
  bool touched;
  uint8_t gesture;
  uint16_t touchX, touchY;

  touched = touch.getTouch(&touchX, &touchY, &gesture);

  if (!touched)
  {
    USBSerial.print("Not Touched");
    data->state = LV_INDEV_STATE_REL;
  }
  else
  {
    data->state = LV_INDEV_STATE_PR;

    data->point.x = touchX;
    data->point.y = touchY;

    USBSerial.print("Data x ");
    USBSerial.println(touchX);

    USBSerial.print("Data y ");
    USBSerial.println(touchY);
    }
}

void setup()
{
    pinMode(TFT_BLK, OUTPUT);
    analogWrite(TFT_BLK, 10);

    touch.begin();
    USBSerial.begin( 115200 ); /* prepare for possible USBSerial debug */

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

    USBSerial.println( LVGL_Arduino );
    USBSerial.println( "I am LVGL_Arduino" );

    lv_init();

#if LV_USE_LOG != 0
    lv_log_register_print_cb( my_print ); /* register print function for debugging */
#endif

    tft.begin();          /* TFT init */
    tft.setRotation( 0 ); /* 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 );

    USBSerial.println( "hello 01" );
    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();
    USBSerial.println( "Setup done" );
}

void loop()
{
    lv_timer_handler(); /* let the GUI do its work */
    delay(5);
    //USBSerial.println( "loop!" );
}

Screenshot and/or video

Return of the Serial Monitor:

Hello Arduino! V8.3.10
I am LVGL_Arduino
hello 01
Setup done
Hello Arduino! V8.3.10
I am LVGL_Arduino
hello 01
Setup done

Hello, try defining the lv_indev globally at the top of your file. Still needs to be static. I assume it does assign it but only local to the setup() function.

Hi Tinus,

You mean this line ?
static lv_indev_drv_t indev_drv;

I had just tried it. No change :confused:

That’s odd, I must be missing something. Here is some code I used for the setup, which does work… Spot the differences:

//DISPLAY DRIVER
static lv_disp_drv_t displayDriver;

//TOUCH DRIVER
static lv_indev_drv_t touchDriver;
static void touch_read_cb(lv_indev_drv_t * drv, lv_indev_data_t*data);
touch_data_t touch_data;

volatile uint16_t lineCount = 0;

/* Application Thread entry function */
/* pvParameters contains TaskHandle_t */
void app_thread_entry(void *pvParameters)
{
    FSP_PARAMETER_NOT_USED (pvParameters);

    set_active_frame_buffer(0);

    lv_init();


    if (init_displaydriver_dma(g_transfer_dma, fb_background[0], &displayDriver, &drawBuffer,
            buf1, buf2, DISP_VER_RES, DISP_HOR_RES, BUF_HOR_LINES) == 0)
    {
        /*INIT TOUCH DRIVER*/
        lv_indev_drv_init(&touchDriver);
        touchDriver.type = LV_INDEV_TYPE_POINTER;
        touchDriver.read_cb = touch_read_cb;
        lv_indev_drv_register(&touchDriver);

        //SETUP TIMER RELATED FUNCTIONALITY
        xTimerChangePeriod(g_timer_lvgl, pdMS_TO_TICKS(TICK_MS_TIME), 0 );
        xTimerStart(g_timer_lvgl, 0);

        //START SCREEN
        R_GLCDC_Open(&g_display0_ctrl, &g_display0_cfg);
        R_GLCDC_Start(&g_display0_ctrl);

        ui_init();

        while (1)
        {
            lv_task_handler();

            vTaskDelay (pdMS_TO_TICKS(1));
        }
    }
}

Ignore the if (init_displaydriver_dma)... part, that is my own function used for enabling DMA on my device.

I see not differences either :disappointed_relieved:

I tried to move static lv_indev_drv_t indev_drv and static lv_disp_drv_t disp_drv globally but no difference.

FYI there is someone using the same module with the same problem, the display is working fine but not the touchpad. The difference is that the author of this post is using Tasmota environment instead of Arduino IDE + SquareLine.

Hmmm, well, the only thing I am not seeing in your code is a timer anywhere.
You need to use a timer that calls lv_tick_inc() every x milliseconds. Set up a project — LVGL documentation

I can only suggest adding that (if you haven’t already) and changing lv_timer_handler() to lv_task_handler(). I would suggest changing the delay() there to 1 - 3 milliseconds.

It is working !! Thanks you so much !

I had juste modify the loop function like you said, even if I don’t know if it is the best implementation for that.

void loop()
{
    lv_task_handler();
    lv_tick_inc(5);
    delay(5);
}
2 Likes

Hi ZigDuDim! Were you able to get the display working with a SquareLine UI and LVGL,TFT_eSPI? I don’t see a screenshot.

I’ve created a UI via SquareLine/LVGL on the ESP32C3-2424S012, but all my attempts to configure TFT_eSPI either cause a crash or do not display anything. I’ve done some serial debugging, and the very first “aft_Write_8(c)” call in TFT_eSPI::write command appears to fail. So I’m assuming my configuration is wrong.

I defined the following pins in Setup200_GC9A01.h:

// For ESP32C3-2424S012 (ESP32-C3-MINI-1U + GC9801)
#define TFT_MISO -1
#define TFT_MOSI 7
#define TFT_SCLK 6
#define TFT_CS 10 // Chip select control pin
#define TFT_DC 2 // Data Command control pin
#define TFT_RST -1 // Reset pin (could connect to Arduino RESET pin)
#define TFT_BL 3 // LED back-light

Yours is the only post I can find that appears to get a SquareLine UI to work on this board with TFT_eSPI. All other examples I can find use LovyanGFX instead.

Can you please share your TFT_eSPI configuration changes for the ESP32C3-2424S012?

Many thanks!

Hi Louis!

Yes I am using the TFT_eSPI. The pins provided in the “official” documentation are correct. But here my implementation in User_Setup.h from the TFT_eSPI’s library:

#define TFT_MOSI    7
#define TFT_SCLK    6
#define TFT_CS      10
#define TFT_DC      -1
#define TFT_RST     -1
#define TFT_BL      3
#define TFT_MISO    -1

The only thing that I had to find out myself is that the backlight is not managed by the library. You have to turn the backlight yourself by using analogWrite.

Good luck :wink:

1 Like

Thanks so much for such a quick reply! I’m really surprised to see that you have TFT_DC == -1. All other sources I’ve found have set it to 2. And thanks for the tip on the backlight.

Unfortunately, it doesn’t seem to make much any difference for me. My sketch still never makes it past the first tft.init() call.

Out of curiosity, are you using Arduino 1.x or 2.x? And which TFT_eSPI versions?

Thanks again!

I am using Arduino 2.2.1, TFT_eSPI 2.5.0.

Have you tried uploading basic sketch example from the TFT_eSPI ?

Thank you! Yes. I have tried both Colour_Test and Read_User_Setup from this list. I’ve also tried several examples from the lvgl library. The code always hangs when calling TFT_eSPI::init() (i.e., tft.init() ). I’ve tried multiple versions of the TFT_eSPI library, but I haven’t gone back as far as 2.5.0.

To be clear, each time I change versions of TFT_eSPI library, I only modify User_Setup.h (comment out the default ILI9341 driver, uncomment the GC9A01 driver, and add the pin definitions you provided). In the sketch setup my only change is to call Serial.begin(…) in setup() and Serial.println(…) before and after the tft.init() call. The first Serial.println() works. The second does not. I’ve tried more complex outputs, but nothing after the tft.init() call generates output. I have (in previous attempts) added similar Serial.print(…) calls throughout TFT_eSPI::init(…) code, but they stop generating output after the writecommand(TFT_SWRST); call.

So I assume something in the various versions (LVGL, TFT_eSPI, ESP32C3 core, Arduino) is incompatible.

After installing v.2.5.0 I now have compile errors in TFT_eSPI_ESP32_C3.h. So I’ll try reverting to an older version of my ESP32 cores, to see if that will work with the older v.2.5.0 version of TFT_eSPI.

FYI, I’ve tried this with both Arduino 1.8.39 and 2.2.1, but the results are the same.

Thanks for your continued responses. One last question. Can you see which versions of the ESP32 board from Espressif you are using?

Just FYI, reverting esp32 by Espressif back to 2.0.14 and TFT_eSPI to 2.0.5. Solved the problem of hanging in tft.init(). Now the Colour_Test code runs, and all my debugging serial output appears in the serial monitor.

Unfortunately, the screen is still blank (and no backlight). But hey, that’s a completely different problem.

Thank you so much @ZigDuDim for your posts and responses!

Sometime when I compile my sketch, the process is failling. And when I change the version of LVGL library, the problem magically disappear. When I am in 8.3.7 and it failed, I change to 8.3.10, and vice and versa … I have not search the reason why, mainly because the process of changing the version take about 10sec, so it barely bother me…

If you can not run the tests code, I suggest that you dig into it before trying to import anything from square studio. It is simpler to debug, that how I solved my backlight issues.

Regarding the ESP library that is what I am using:

I know how it is to feeling completely alone facing a problem. So I understand how relief you can feel to find out someone with the same problem, who is answering to you. I don’t mind helping out :wink:

How is not the right time. but I will upload all my project to you including the libraries, to help you out later.

1 Like

Thanks as always! Since this appears to be a versioning issue this is very helpful. I’m still not getting things to work, but after banging on this for a week, at least now I have hope.

I look forward to learning from your project. Thanks again!

For anyone reading this thread, I did get my project working, thanks to the above from @ZigDuDim, who even offered to send me his working project. Fortunately, I figured out a few things about the ESP32-2424S012, TFT_eSPI and SquareLine Studio. Even though this board contains an ESP32-C3 and a round display (I think from Waveshare) driven by GC9A01, all the examples I’ve seen online use a separate ESP32 dev board connected to a discrete display. This combined unit is different. The MCU is actually an ESP32-C3-Mini-1U, with a much smaller number of GPIO pins, lack of DMA for TFT and so on. Here are some things I learned that need to be addressed to make this thing work:

  1. This board does not work with the recent versions (2.5.34, 2.533) of TFT_eSPI. Not until I rolled back to 2.5.0 did I ever get any output on my board.

  2. As @ZigDuDim says, the backlight is not SPI, and thus not controlled via TFT_eSPI. It must be controlled via an analogWrite() call. Also, don’t set it too bright. 10 is plenty. I tried it as high as 255, but anything over 150 seems to make the display freak out. Glad these things are tough.

  3. The setup of TFT_eSPI is very finicky, and some parameters, like TFT_HEIGHT and TFT_WIDTH do have to be set to 240x240 in User_setup.h for the board to work. Even though they default to 240x320, and some videos show it working.

  4. In my case, these are the pin definitions that work for me in TFT’s User_setup.h. There are some others set by default for NodeMCU boards. Comment those out.

#define TFT_MOSI 7 // In some display driver board, it might be written as "SDA" and so on.
#define TFT_SCLK 6
#define TFT_CS   10  // Chip select control pin
#define TFT_DC   2  // Data Command control pin
#define TFT_RST  -1  // Reset pin (could connect to Arduino RESET pin)
// #define TFT_BL  3  // LED back-light - Use analogWrite 
#define TFT_MISO -1

@ZigDuDim says his setup works with TFT_DC defined as -1. So your mileage may vary. Hopefully, this will help someone avoid the days this took me to get right.

FWIW, I still have issues with transparency in PNG images in the LVGL UI. But I can always work around that.

1 Like

hello ZigDuDim where find the library CST816D because on arduino ide there is only CST816S

Hi
I’m tried setup follow you showing data, TFT display not show results.

  • Comport connect
  • Arduino 2.2.1
  • TFT_eSPI 2.5.0
  • LVGL 8.3.10
  • esp32 by Espressif 2.0.11 I don’t have 2.0.13

I’m coppy code from you output showing

  • Compilation error: CST816D.h: No such file or directory
    and I trie test from examples code upload complate but TFT display do not show.

If you need any detail please tell me
Thank.

Hi,

The easiest way to find the library is to go on the aliexpress page of the product, usually there is a link to a zip file called 1.28inch_ESP32-2424S012.zip. The library is inside.