lovyan03 / LovyanGFX

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

Problem with ESP32_S3 and ILI9488 16 bit-parallel display #540

Closed Neothai closed 2 months ago

Neothai commented 2 months ago

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

Environment ( 実行環境 )

Problem Description ( 問題の内容 )

I encountered an issue with an ILI9488 3.5 inch TFT display with an ESP32-S3 with LVGL version 9. I'm guessing the issue is caused by incomplete data sent in these lines of code.

void dispFlush(lv_display_t *disp, const lv_area_t *area, uint8_t * px_map){
  uint32_t w = ( area->x2 - area->x1 + 1 );
  uint32_t h = ( area->y2 - area->y1 + 1 );

  display.startWrite();
//=======================================================//
  display.setAddrWindow( area->x1, area->y1, w, h );     <---
  display.writePixels((lgfx::rgb565_t *)&px_map, w * h); <---
//=======================================================//
  display.endWrite();

  lv_display_flush_ready(disp);   
}

480x360px

https://github.com/lovyan03/LovyanGFX/assets/123863242/de9e84b7-35cd-421e-913c-470e7c6ea06e

How to solve this problem? Thank you very much!

Here's the full code

// basicSystemSetting.h File
#include <LovyanGFX.hpp>

#define TFT_HOR_RES   480
#define TFT_VER_RES   320

class LGFX : public lgfx::LGFX_Device
{
    lgfx::Panel_ILI9488 _panel_instance;
    lgfx::Bus_Parallel16 _bus_instance;
    lgfx::Touch_GT911 _touch_instance;

    public:
      LGFX(void){
      {
        auto cfg = _bus_instance.config();

        cfg.freq_write  = 40000000;
        cfg.pin_wr      = 48;
        cfg.pin_rd      = 11;
        cfg.pin_rs      = 47;

        cfg.pin_d0      = 1;
        cfg.pin_d1      = 2;
        cfg.pin_d2      = 12;
        cfg.pin_d3      = 4;
        cfg.pin_d4      = 5;
        cfg.pin_d5      = 6;
        cfg.pin_d6      = 7;
        cfg.pin_d7      = 10;
        cfg.pin_d8      = 14;
        cfg.pin_d9      = 15;
        cfg.pin_d10     = 16;
        cfg.pin_d11     = 17;
        cfg.pin_d12     = 18;
        cfg.pin_d13     = 21;
        cfg.pin_d14     = 38;
        cfg.pin_d15     = 42;

        _bus_instance.config(cfg);
        _panel_instance.bus(&_bus_instance);
      }
      {
        auto cfg = _panel_instance.config();    

        cfg.pin_cs           = -1;  // (-1 = disable)
        cfg.pin_rst          = 13;  // (-1 = disable)
        cfg.pin_busy         = -1;  // (-1 = disable)

        cfg.panel_width      = TFT_VER_RES;  
        cfg.panel_height     = TFT_HOR_RES;  
        cfg.offset_x         = 0;  
        cfg.offset_y         = 0;  
        cfg.offset_rotation  = 1;  

        cfg.dummy_read_pixel = 8; 
        cfg.dummy_read_bits  = 1;  
        cfg.readable         = true;      
        cfg.invert           = false;       
        cfg.rgb_order        = false;    
        cfg.dlen_16bit       = true;
        cfg.memory_width     = TFT_VER_RES;
        cfg.memory_height    = TFT_HOR_RES;
        cfg.bus_shared       = false;

        _panel_instance.config(cfg);
      }
      { 
        auto cfg = _touch_instance.config();

        cfg.x_max      = TFT_VER_RES;  
        cfg.y_max      = TFT_HOR_RES;  
        cfg.pin_int    = -1;   
        cfg.bus_shared = true; 
        cfg.offset_rotation = 0;

        cfg.i2c_port = 1; //(0 or 1)
        cfg.i2c_addr = 0x14;
        cfg.pin_sda  = 8;
        cfg.pin_scl  = 9;
        cfg.freq = 100000;

        _touch_instance.config(cfg);
        _panel_instance.setTouch(&_touch_instance);  
      }
      setPanel(&_panel_instance); 
    }    
  };

  LGFX display;

#define DRAW_BUF_SIZE (TFT_HOR_RES * TFT_VER_RES / 4 * (LV_COLOR_DEPTH / 8))
uint8_t draw_buf[DRAW_BUF_SIZE];

lv_display_t * disp;

void dispFlush(lv_display_t *disp, const lv_area_t *area, uint8_t * px_map){
  uint32_t w = ( area->x2 - area->x1 + 1 );
  uint32_t h = ( area->y2 - area->y1 + 1 );

  display.startWrite();
  display.setAddrWindow( area->x1, area->y1, w, h );
  display.writePixels((lgfx::rgb565_t *)&px_map, w * h);
  display.endWrite();

  lv_display_flush_ready(disp);   
}

void touchPadRead(lv_indev_t * indev, lv_indev_data_t * data){
 uint16_t touchX, touchY;
    bool touched;
    touched = display.getTouch( &touchX, &touchY);

    if(!touched){data->state = LV_INDEV_STATE_REL;}
    else{data->state = LV_INDEV_STATE_PR;
        data->point.x = touchX;
        data->point.y = touchY;
    }
}

void lvglDisplayConfig(){
  lv_init();
  display.init(); delay(100);
  display.fillScreen(TFT_GREEN); delay(100); // OK
  display.fillScreen(TFT_RED); delay(100);   // OK
  display.fillScreen(TFT_BLUE); delay(100);  // OK
  display.fillScreen(TFT_BLACK);             // OK

  disp = lv_display_create(TFT_HOR_RES, TFT_VER_RES);
  lv_display_set_flush_cb(disp, dispFlush);
  lv_display_set_buffers(disp, draw_buf, NULL, DRAW_BUF_SIZE, LV_DISPLAY_RENDER_MODE_PARTIAL);

  lv_indev_t * indev = lv_indev_create();
  lv_indev_set_type(indev, LV_INDEV_TYPE_POINTER); /*Touchpad should have POINTER type*/
  lv_indev_set_read_cb(indev, touchPadRead);
}

Main Code

#include <lvgl.h>
#include "basicSystemSetting.h"
#include <demos/lv_demos.h>

void setup(){
  Serial.begin(115200); 
  lvglDisplayConfig();
  lv_demo_widgets();
}
unsigned long lvgl_tick_millis;

void loop(){
  lv_timer_handler(); /* let the UI do its work */

  unsigned long tick_millis = millis() - lvgl_tick_millis;
  lvgl_tick_millis = millis();  lv_tick_inc(tick_millis);
  delay(5);
}
lovyan03 commented 2 months ago

40MHz is too fast.

Neothai commented 2 months ago

I have tried reducing the speed to 10MHz but the problem is still not solved.

cfg.freq_write  = 10000000;

Is there still any part of the code that I need to improve?

lovyan03 commented 2 months ago

Is the LovyanGFX sample program working correctly?

lovyan03 commented 2 months ago

ILI9488 width = 320 height = 480

Neothai commented 2 months ago

This example works. But there are some pixels on the display that are slightly distorted.

#include <LovyanGFX.hpp>

class LGFX : public lgfx::LGFX_Device
{

lgfx::Panel_ILI9488     _panel_instance;
lgfx::Bus_Parallel16 _bus_instance;
lgfx::Touch_GT911  _touch_instance;

public:
  LGFX(void)
  {
    {
      auto cfg = _bus_instance.config();

      cfg.freq_write = 44000000;
      cfg.pin_wr = 48;
      cfg.pin_rd = 11;
      cfg.pin_rs = 47;

      cfg.pin_d0 = 1;
      cfg.pin_d1 = 2;
      cfg.pin_d2 = 12;
      cfg.pin_d3 = 4;
      cfg.pin_d4 = 5;
      cfg.pin_d5 = 6;
      cfg.pin_d6 = 7;
      cfg.pin_d7 = 10;
      cfg.pin_d8 = 14;
      cfg.pin_d9 = 15;
      cfg.pin_d10 = 16;
      cfg.pin_d11 = 17;
      cfg.pin_d12 = 18;
      cfg.pin_d13 = 21;
      cfg.pin_d14 = 38;
      cfg.pin_d15 = 42;
      _bus_instance.config(cfg);
      _panel_instance.bus(&_bus_instance);
    }
    { 
      auto cfg = _panel_instance.config();    

      cfg.pin_cs           =    -1;  // CSが接続されているピン番号   (-1 = disable)
      cfg.pin_rst          =    13;  // RSTが接続されているピン番号  (-1 = disable)
      cfg.pin_busy         =    -1;  // BUSYが接続されているピン番号 (-1 = disable)

      cfg.panel_width      =   320;  // 実際に表示可能な幅
      cfg.panel_height     =   480;  // 実際に表示可能な高さ
      cfg.offset_x         =     0;  // パネルのX方向オフセット量
      cfg.offset_y         =     0;  // パネルのY方向オフセット量
      cfg.offset_rotation  =     1;  // 回転方向の値のオフセット 0~7 (4~7は上下反転)
      //cfg.dummy_read_pixel =     8;  // ピクセル読出し前のダミーリードのビット数
      //cfg.dummy_read_bits  =     1;  // ピクセル以外のデータ読出し前のダミーリードのビット数
      cfg.readable         =  true;  // データ読出しが可能な場合 trueに設定
      cfg.invert           = false;  // パネルの明暗が反転してしまう場合 trueに設定
      cfg.rgb_order        = false;  // パネルの赤と青が入れ替わってしまう場合 trueに設定
      cfg.dlen_16bit       =  true;  // 16bitパラレルやSPIでデータ長を16bit単位で送信するパネルの場合 trueに設定
      cfg.bus_shared       = false;  // SDカードとバスを共有している場合 trueに設定(drawJpgFile等でバス制御を行います)

      _panel_instance.config(cfg);
    }
    { 
      auto cfg = _touch_instance.config();

      cfg.x_max      = 320;  // タッチスクリーンから得られる最大のX値(生の値)
      cfg.y_max      = 480;  // タッチスクリーンから得られる最大のY値(生の値)
      cfg.pin_int    = -1;   // INTが接続されているピン番号
      cfg.bus_shared = true; // 画面と共通のバスを使用している場合 trueを設定
      cfg.offset_rotation = 0;// 表示とタッチの向きのが一致しない場合の調整 0~7の値で設定

      cfg.i2c_port = 1;      // 使用するI2Cを選択 (0 or 1)
      cfg.i2c_addr = 0x14;   // I2Cデバイスアドレス番号
      cfg.pin_sda  = 8;     // SDAが接続されているピン番号
      cfg.pin_scl  = 9;     // SCLが接続されているピン番号
      cfg.freq = 100000;     // I2Cクロックを設定

      _touch_instance.config(cfg);
      _panel_instance.setTouch(&_touch_instance); 
    }
    setPanel(&_panel_instance);
  }
};
LGFX display;

void setup(void){
  display.init();
  Serial.begin(115200);
/*
  display.setTextSize((std::max(display.width(), display.height()) + 255) >> 8);

  if (display.touch()){
    if (display.width() < display.height()) display.setRotation(display.getRotation() ^ 1);

    display.setTextDatum(textdatum_t::middle_center);
    display.drawString("touch the arrow marker.", display.width()>>1, display.height() >> 1);
    display.setTextDatum(textdatum_t::top_left);

    std::uint16_t fg = TFT_WHITE;
    std::uint16_t bg = TFT_BLACK;
    if (display.isEPD()) std::swap(fg, bg);
    display.calibrateTouch(nullptr, fg, bg, std::max(display.width(), display.height()) >> 3);
  }
*/
  display.fillScreen(TFT_BLACK);
}

uint32_t count = ~0;
void loop(void){
  display.startWrite();
  display.setRotation(++count & 7);
  display.setColorDepth((count & 8) ? 16 : 24);

  display.setTextColor(TFT_WHITE);
  display.drawNumber(display.getRotation(), 16, 0);

  display.setTextColor(0xFF0000U);
  display.drawString("R", 30, 16);
  display.setTextColor(0x00FF00U);
  display.drawString("G", 40, 16);
  display.setTextColor(0x0000FFU);
  display.drawString("B", 50, 16);

  display.drawRect(30,30,display.width()-60,display.height()-60,count*7);
  display.drawFastHLine(0, 0, 10);

  display.endWrite();

  int32_t x, y;
  if (display.getTouch(&x, &y)) {
    delay(1);
    Serial.println(String(x));
    Serial.println(String(y));
    display.fillRect(x-2, y-2, 5, 5, count*7);
  }
}

https://github.com/lovyan03/LovyanGFX/assets/123863242/6f7ddb1e-902d-4b2f-b6b2-2d2260858902

Neothai commented 2 months ago

After 10-20 minutes, the display started to distort a little more. errorimg1 errorimg2

lovyan03 commented 2 months ago

cfg.freq_write = 44000000;

????????????????

lovyan03 commented 2 months ago

why cs pin is -1?

Neothai commented 2 months ago

why cs pin is -1?

I disabled the cs pin through software to connect the cs pin to external gnd instead because the ESP32-S3's GPIO was insufficient.

Neothai commented 2 months ago

Have you tested LovyanGFX for compatibility with the latest version (v9) of LVGL? Because I just recently came across a discussion with the topic "LVGL v9.0 to work with LovyanGFX and ILI9488 screen". They seem to have a similar problem to me.

lovyan03 commented 2 months ago

通常これらのグリッチは物理的な通信品質が悪いために発生する。 通信速度が速すぎたり配線の状態が悪いのだと思います。

lovyan03 commented 2 months ago

私はあなたのコードに不備があると思います。

  display.writePixels((lgfx::rgb565_t *)&px_map, w * h);

px_map はポインタ型です。 &px_mapと書いた場合はポインタ型変数のポインタを指し示します。 px_mapと書けば良いでしょう。

つまり以下のようにです。

  display.writePixels((lgfx::rgb565_t *)px_map, w * h);

ちなみにその書き方では速度が十分に出ません。 以下のサンプルを参考に見てください。

https://github.com/lovyan03/LovyanGFX/blob/master/examples/Advanced/LVGL_PlatformIO/