lovyan03 / LovyanGFX

SPI LCD graphics library for ESP32 (ESP-IDF/ArduinoESP32) / ESP8266 (ArduinoESP8266) / SAMD51(Seeed ArduinoSAMD51)
Other
1.17k stars 207 forks source link

Cannot make it work with Sunton ESP3248S035 with Capacitive touch (GT911) #366

Closed astorun closed 1 year ago

astorun commented 1 year ago

Hi there,

I am trying to run the LovyanGFX with Sunton ESP3248S035 with Capacitive touch support using GT911 driver. Display works fine but I cannot make it work with the touch drivers. Could you check if there is something wrong with the code?

According to documentation touch screen pins are like this: INT: 21 RST:25 SCL:32 SDA:33

I cannot find any information about driver address of GT911 but I am not sure if it is required.

Code I am using:

/////////////////////////////////////////////////////////////////
/*
  ESP32 | LVGL8 | Ep 0. GFX Setup (ft. LovyanGFX)
  Video Tutorial: https://youtu.be/IPCvQ4o_WP8
  Created by Eric N. (ThatProject)
*/
/////////////////////////////////////////////////////////////////

#include <lvgl.h>
#define LGFX_USE_V1
#include <LovyanGFX.hpp>
#include "ui.h"
#include <driver/i2c.h>

class LGFX : public lgfx::LGFX_Device
{
lgfx::Panel_ST7796      _panel_instance;
lgfx::Bus_SPI           _bus_instance;   // SPI
lgfx::Light_PWM         _light_instance;
lgfx::Touch_GT911       _touch_instance;

public:
  LGFX(void)
  {
    {
      auto cfg = _bus_instance.config();
      cfg.spi_host = HSPI_HOST;     // (VSPI_HOST or HSPI_HOST)
      cfg.spi_mode = 0;             // SPI (0 ~ 3)
      cfg.freq_write = 80000000;    // SPI (80MHz)
      cfg.freq_read  = 20000000;    // 
      cfg.spi_3wire  = false;       //
      cfg.use_lock   = true;        //
      cfg.dma_channel = 1;          // Set the DMA channel (1 or 2. 0=disable)
      cfg.pin_sclk = 14;            // SPI SCLK
      cfg.pin_mosi = 13;            // SPI MOSI
      cfg.pin_miso = 12;            // SPI MISO (-1 = disable)
      cfg.pin_dc   = 2;             // SPI (-1 = disable) Data Command control pin
      _bus_instance.config(cfg);    //
      _panel_instance.setBus(&_bus_instance);
    }

    {
      auto cfg = _panel_instance.config();
      cfg.pin_cs           =    15;  // CS    (-1 = disable)
      cfg.pin_rst          =    -1;  // RST   (-1 = disable)
      cfg.pin_busy         =    -1;  // BUSY  (-1 = disable)
      cfg.memory_width     =   320;
      cfg.memory_height    =   480;
      cfg.panel_width      =   320;
      cfg.panel_height     =   480;
      cfg.offset_x         =     0;
      cfg.offset_y         =     0;
      cfg.offset_rotation  =     0;
      cfg.dummy_read_pixel =     8;
      cfg.dummy_read_bits  =     1;
      cfg.readable         =  true;
      cfg.invert           = false;
      cfg.rgb_order        = false;
      cfg.dlen_16bit       = false;
      cfg.bus_shared       =  true;

      _panel_instance.config(cfg);
    }

    {
      auto cfg = _light_instance.config();

      cfg.pin_bl = 27;
      cfg.invert = false;
      cfg.freq   = 44100;
      cfg.pwm_channel = 7;

      _light_instance.config(cfg);
      _panel_instance.setLight(&_light_instance);
    }

    {
      auto cfg = _touch_instance.config();
      cfg.x_min      = 0;
      cfg.x_max      = 320;
      cfg.y_min      = 0;
      cfg.y_max      = 480;
      cfg.bus_shared = false;
      cfg.offset_rotation = 0;

      cfg.i2c_port   = 1;

      cfg.pin_int    = 21;
      cfg.pin_sda    = 33;
      cfg.pin_scl    = 32;
      cfg.pin_rst    = 25;

      cfg.freq       = 400000;
      _touch_instance.config(cfg);
      _panel_instance.setTouch(&_touch_instance);
    }

    setPanel(&_panel_instance);

  }
};

LGFX tft;

//Change to your screen resolution
static const uint32_t screenWidth  = 480;
static const uint32_t screenHeight = 320;
static lv_disp_draw_buf_t draw_buf;

/*Static or global buffer(s). The second buffer is optional*/
static lv_color_t buf_1[screenWidth * 10];
//static lv_color_t buf_2[screenWidth * 10];

//Display flushing 
void 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.writePixels((lgfx::rgb565_t *)&color_p->full, w * h);
   tft.endWrite();

   lv_disp_flush_ready( disp );

}

//Read the touchpad
void touchpad_read( lv_indev_drv_t * indev_driver, lv_indev_data_t * data )
{
   uint16_t touchX, touchY;
   bool touched = tft.getTouch( &touchX, &touchY);
   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;

   }
}

void display_setup_init()
{
  tft.begin();        
  tft.setRotation(1);

  std::uint16_t fg = TFT_WHITE;
  std::uint16_t bg = TFT_BLACK;
  if (tft.isEPD()) std::swap(fg, bg);
  uint16_t calibrationData[8];
  tft.calibrateTouch(calibrationData, fg, bg, std::max(tft.width(), tft.height()) >> 3);

  for(int i=0; i<8; i++){
    Serial.print(calibrationData[i]);
    Serial.print(", ");
  }

  lv_init();

  /*Initialize `disp_buf` with the buffer(s). With only one buffer use NULL instead buf_2 */
  lv_disp_draw_buf_init(&draw_buf, buf_1, NULL, screenWidth * 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 = disp_flush;
  disp_drv.draw_buf = &draw_buf;
  lv_disp_drv_register( &disp_drv );

  //Initialize the input device driver
  static lv_indev_drv_t indev_drv;
  lv_indev_drv_init(&indev_drv);                                 //Basic initialization
  indev_drv.type = LV_INDEV_TYPE_POINTER;                        //Touch pad is a pointer-like device
  indev_drv.read_cb = touchpad_read;                             //Set your driver function
  lv_indev_t * disp_indev = lv_indev_drv_register(&indev_drv);   //Register the driver in LVGL and save the created input device object

  tft.setBrightness(255);
  //ui_init();
}

void display_init()
{
    lv_timer_handler();
}

Carefully written requests are more likely to be given priority. 丁寧に記述された要望は優先して対応される可能性が高くなります。

Device Name (デバイスの名称・型番等)

Sunton 3.5" 320*480 Smart Display Screen 3.5inch LCD TFT Module - Capacitive touch version

URL of Device Specifications document (仕様書等のURL)

http://www.jczn1688.com/zlxz?spm=a2g0o.detail.1000023.1.1d4528faY71ytG Download password: jczn1688

URL of the store where we can purchase (商品を購入できるURL)

https://www.aliexpress.us/item/3256804446638703.html?spm=a2g0o.order_list.order_list_main.21.550b18020VEe0G&gatewayAdapt=glo2usa&_randl_shipto=US

astorun commented 1 year ago

I can also confirm that touch driver works with TAMC GT911 library for arduino but not with LovyanGFX GT911 driver.

lovyan03 commented 1 year ago

The INT pin is not functional on that board. Strictly speaking, there is a wiring pattern on the board, but R25 is not mounted and not conducting.

image

//  cfg.pin_int    = 21; // bad setting
    cfg.pin_int    = -1; // good setting

it is very painful to be forced to debug hardware defects.

astorun commented 1 year ago

I just tried with setting the cfg.pin_int = -1; but still it does not work.

It works with TAMC library for some reason with proper pin setup. However I also get this wire error on serial monitor when used with TAMC library. [E][Wire.cpp:513] requestFrom(): i2cRead returned Error 263

However if I add a delay around 500ms on setup function with the following lines of code it works without any errors.

void touchpad_setup() { 
    //Serial.println("TAMC_GT911 Example: Ready");
    pinMode(TOUCH_SCL, OUTPUT);
    pinMode(TOUCH_SDA, OUTPUT);
    pinMode(TOUCH_RST, OUTPUT);
    digitalWrite(TOUCH_SCL, HIGH);
    digitalWrite(TOUCH_SDA, HIGH);
    digitalWrite(TOUCH_RST, HIGH);
    digitalWrite(TOUCH_SCL, LOW);
    digitalWrite(TOUCH_SDA, LOW);
    digitalWrite(TOUCH_RST, LOW);
    delay(500);
    tp.begin();
    tp.setRotation(ROTATION_RIGHT);
}

Seems like it needs some time to clear and initialize the i2c bus during boot?. Maybe it is something you might want to explore since those displays are very popular now and selling like hotcakes.

I am not an expert on programming but this is just my guess.

lovyan03 commented 1 year ago

The code for LVGL and other application parts is in the way. Please provide minimal code that is buildable and reproducible. Don't force us to work to decipher the code.

lovyan03 commented 1 year ago

Try this example setup and see

https://lang-ship.com/blog/work/esp32-3248s035/#toc9

astorun commented 1 year ago

The code for LVGL and other application parts is in the way. Please provide minimal code that is buildable and reproducible. Don't force us to work to decipher the code.

Sorry for the confusion. I assumed LVGL is a standard way to operate the LovyanGFX since everybody uses it like that nowadays. Friendly suggestion: You should consider adding more examples, built- in display support and use case scenarios with different libraries, especially LVGL, since it is a very popular library to implement GUI and LovyanGFX is the fastest option to use with it.

Moreover the code you provided works great! Thanks for the help!