Waveshare 2.1inch ST7701S ESP-32S3 Arduino IDE

Description

Hi everyone,

I recently bought this device (https://www.waveshare.com/esp32-s3-touch-lcd-2.1.htm).

It works great with the demo files, however the LVGL library in the demo is version 8.3.3.
I’m very new to this and i’m having some trouble updating the library form 8.3.3 to 9.2.2 (latest LVGL Arduino IDE version available)

I’m using AI to give me an hand with all the breaking changes.
I also peeked at the documentation but I not doing much progress and the project fails to compile.

My goal is to get a very simple “hello world” example working after updating the LVGL lib version to 9.2.2 which was what the demo files basically did.

I’m completely lost here. Maybe someone can shine a light.

All my issues are within my initLVGL function:

LVGL_Driver.h

#pragma once

#include "lvgl.h"
#include <esp_heap_caps.h>
#include "Display_ST7701.h"
#include "Touch_CST820.h"

#define LCD_WIDTH     ESP_PANEL_LCD_WIDTH
#define LCD_HEIGHT    ESP_PANEL_LCD_HEIGHT
#define LVGL_BUF_LEN  (ESP_PANEL_LCD_WIDTH * ESP_PANEL_LCD_HEIGHT / 5)

#define LVGL_TICK_PERIOD_MS  5

extern lv_display_t disp_drv;

void debugLVGL(const char * buf);

void Lvgl_Display_LCD(lv_display_t *disp, const lv_area_t *area, lv_color_t *color_p);
void Lvgl_Touchpad_Read(lv_indev_t * indev, lv_indev_data_t * data);

void increase_lvgl_tick(void *arg);

void initLVGL(void);
void loopLVGL(void);

LVGL_Driver.cpp

void initLVGL(void) {
  lv_init();

  /* Retrieve frame buffers */
  void *buf1, *buf2;
  esp_lcd_rgb_panel_get_frame_buffer(panel_handle, 2, &buf1, &buf2);

  /* Initialize the draw buffer */
  static lv_draw_buf_t draw_buf;
  lv_draw_buf_init(&draw_buf, buf1, buf2, LV_COLOR_FORMAT_NATIVE, ESP_PANEL_LCD_WIDTH, ESP_PANEL_LCD_HEIGHT);

  /* Initialize the display driver */
  static lv_display_t disp_drv;
  lv_display_init(&disp_drv);

  /* Set the display resolution */
  lv_display_set_physical_resolution(&disp_drv, LCD_HEIGHT, LCD_WIDTH); // Note: Use physical resolution in 9.2.2
  lv_display_set_flush_cb(&disp_drv, Lvgl_Display_LCD);
  lv_display_set_full_refresh(&disp_drv, true);
  
  // In LVGL 9.2.2, draw buffers are set with this method
  lv_display_set_draw_buffers(&disp_drv, &draw_buf, NULL, 0, LV_DISPLAY_RENDER_MODE_PARTIAL);

  /* Add the display driver */
  lv_display_t *display = lv_display_add(&disp_drv);

  /* Initialize the input device driver */
  static lv_indev_t indev_drv;
  lv_indev_init(&indev_drv);
  indev_drv.type = LV_INDEV_TYPE_POINTER;
  indev_drv.read_cb = Lvgl_Touchpad_Read;

  /* Add the input device */
  lv_indev_t *indev = lv_indev_add(&indev_drv);

  /* Create simple label */
  lv_obj_t *label = lv_label_create(lv_screen_active());
  lv_label_set_text(label, "Hello Arduino and LVGL!");
  lv_obj_center(label);

  /* Setup LVGL tick timer */
  const esp_timer_create_args_t lvgl_tick_timer_args = {
      .callback = &increase_lvgl_tick,
      .name = "lvgl_tick"
  };

  esp_timer_handle_t lvgl_tick_timer = NULL;
  esp_timer_create(&lvgl_tick_timer_args, &lvgl_tick_timer);
  esp_timer_start_periodic(lvgl_tick_timer, LVGL_TICK_PERIOD_MS * 1000);
}

My errors:

Hello,

First off, how much of this did you let the AI do for you? The problem here is that I have no idea how the ESP platform works. For instance:

  /* Retrieve frame buffers */
  void *buf1, *buf2;
  esp_lcd_rgb_panel_get_frame_buffer(panel_handle, 2, &buf1, &buf2)

seems like it makes no sense, but I have no idea if that esp_lcd… function works, perhaps this does work.

I highly suggest using the docs instead!! Display (lv_display) — LVGL documentation

Anyway, the steps should be in this order:

  1. Call lv_init()
  2. Create a display driver, something like:
    lv_display_t* display = lv_display_create(DISP_HOR_RES, DISP_VER_RES);
    lv_display_set_flush_cb(display (lv_display_flush_cb_t)flush); // <- You need a flush callback. The existing 8.3 code should already have a working one!
  1. Set display buffers with lv_display_set_buffers()
  2. Setup timer handler and tick handler. Again, you can just copy this from the already working 8.3 version.
  3. Setup a screen, see this extremely simple demo: Examples — LVGL documentation for example.

I implore you not to use AI for this, most of the functions it uses here are either old (for pre V9 ) or simply never even existed! It made things up.

Kind regards.

1 Like

You are 100% correct about AI.

I had that in the back of my mind. It did help a little bit but yeah, there are a few nonsensical lines :disappointed:

The good new is… I managed to make it work :sweat:
Took me a few more ours of searching and trying different things.

I’m not 100% sure this is the correct code, but it seems to be working (at least for a basic hello world example)

Hopefully this will help someone else that come along:

EDIT: I deleted even more lines of code that weren’t doing anything at all.

LVGL_Driver.cpp

#include "indev/lv_indev.h"
#include "LVGL_Driver.h"

static uint8_t buf1[(LCD_WIDTH * LCD_HEIGHT / 10) * BYTE_PER_PIXEL + 500];
static uint8_t buf2[(LCD_WIDTH * LCD_HEIGHT / 10) * BYTE_PER_PIXEL + 500];

void flushDisplay(lv_display_t *disp, const lv_area_t *area, uint8_t *color_p) {
    LCD_addWindow(area->x1, area->y1, area->x2, area->y2, color_p);
    lv_display_flush_ready(disp);
}

void touchPadRead( lv_indev_t * indev_drv, lv_indev_data_t * data ) {
  Touch_Read_Data();

  // Display was pressed
  if (touch_data.points != 0x00) {
    data->point.x = touch_data.x;
    data->point.y = touch_data.y;
    data->state = LV_INDEV_STATE_PRESSED;

    printf("LVGL : X=%u Y=%u points=%d\r\n",  touch_data.x , touch_data.y,touch_data.points);
  } 
  // Display was released
  else { 
    data->state = LV_INDEV_STATE_RELEASED;
  }
  
  // Handle Gestures
  if (touch_data.gesture != NONE ) { }

  touch_data.x = 0;
  touch_data.y = 0;
  touch_data.points = 0;
  touch_data.gesture = NONE;
}

void initLVGL(void) {
  lv_init();
  lv_tick_set_cb(xTaskGetTickCount);
  
  lv_display_t *disp_drv = lv_display_create(LCD_WIDTH, LCD_HEIGHT);

  /* Initialize the draw buffer */
  lv_display_set_buffers(disp_drv, buf1, buf2, sizeof(buf1), LV_DISPLAY_RENDER_MODE_PARTIAL);

  /* Set the display resolution */
  lv_display_set_physical_resolution(disp_drv, LCD_HEIGHT, LCD_WIDTH);

  /* Set flush callback */
  lv_display_set_flush_cb(disp_drv, flushDisplay);

  /* Initialize the input device driver */
  lv_indev_t *indev = lv_indev_create();
  lv_indev_set_type(indev, LV_INDEV_TYPE_POINTER);
  lv_indev_set_read_cb(indev, touchPadRead);
}

void loopLVGL(void) {
  lv_timer_handler();

  vTaskDelay(pdMS_TO_TICKS(5));
}