lovyan03 / LovyanGFX

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

SSD1963 Display Issue #196

Closed JeremiahGillis closed 2 years ago

JeremiahGillis commented 2 years ago

I am using an ESP32-S2-DevKitM-1 with an SSD1963 controller and a 480x272 Display. I encounter the issue in the video below. The second part of the video is slowed down to help identify the issue.

https://user-images.githubusercontent.com/13179985/152696489-5335b128-8249-4746-b2ce-c9f14776b1ef.mp4

You can see that frame pauses and all pixels start to turn white. When the display starts to function correctly again, the block jumps forward to where is was supposed to be without any issue. This tells me that loop() is executing periodically.

I have tried different example projects and encounter the same issue. It is more prevalent on darker backgrounds. I can see that the backlight is not flickering. The voltage at the SSD1963 Controller Board does fluctuate a bit, but remains at least at 3.0 V. I have supplied 3.3V from power supply and that doesn't help. Right now the boards are connected together with 6" jumpers. This isn't ideal but should still work for testing prior to a board layout.

Here is a screenshot of the WR pin from my oscilloscope:

SSD1963 WR Pin 02062022

I can get detailed data of all the important pins with my Seleae Logic Pro if needed. I am using Ardunio IDE 2.0.0-rc3 with ESP32 Arduino 2.0.2 and LovyanGFX 0.4.12.

Does anyone know what the problem might be?

Sketch:

// v1.0.0 を有効にします(v0からの移行期間の特別措置です。これを書かない場合は旧v0系で動作します。)
#define LGFX_USE_V1

#include <LovyanGFX.hpp>

// ESP32でLovyanGFXを独自設定で利用する場合の設定例

/// 独自の設定を行うクラスを、LGFX_Deviceから派生して作成します。
class LGFX : public lgfx::LGFX_Device
{

  lgfx::Panel_SSD1963     _panel_instance;
  lgfx::Bus_Parallel8 _bus_instance;
  lgfx::Light_PWM     _light_instance;

public:
  LGFX(void)
  {
    {
      auto cfg = _bus_instance.config();    // バス設定用の構造体を取得します。

      cfg.i2s_port = I2S_NUM_0;     // 使用するI2Sポートを選択 (I2S_NUM_0 or I2S_NUM_1) (ESP32のI2S LCDモードを使用します)
      cfg.freq_write = 20000000;    // 送信クロック (最大20MHz, 80MHzを整数で割った値に丸められます)
      cfg.pin_wr =  35;              // WR を接続しているピン番号
      cfg.pin_rd =  34;              // RD を接続しているピン番号
      cfg.pin_rs = 36;              // RS(D/C)を接続しているピン番号
      cfg.pin_d0 = 1;              // D0を接続しているピン番号
      cfg.pin_d1 = 2;              // D1を接続しているピン番号
      cfg.pin_d2 = 3;              // D2を接続しているピン番号
      cfg.pin_d3 = 4;              // D3を接続しているピン番号
      cfg.pin_d4 = 5;              // D4を接続しているピン番号
      cfg.pin_d5 = 6;              // D5を接続しているピン番号
      cfg.pin_d6 = 7;              // D6を接続しているピン番号
      cfg.pin_d7 = 8;              // D7を接続しているピン番号

      _bus_instance.config(cfg);    // 設定値をバスに反映します。
      _panel_instance.setBus(&_bus_instance);      // バスをパネルにセットします。
    }

    { // 表示パネル制御の設定を行います。
      auto cfg = _panel_instance.config();    // 表示パネル設定用の構造体を取得します。

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

      // The following setting values ​​are general initial values ​​for each panel, so please comment out any unknown items and try them.

      cfg.memory_width     =   480;  // Maximum width supported by driver IC
      cfg.memory_height    =   272;  // Maximum height supported by driver IC
      cfg.panel_width      =   480;  // Actually displayable width
      cfg.panel_height     =   272;  // Actually displayable height
      cfg.offset_x         =     0;  // Amount of X-direction offset of the panel
      cfg.offset_y         =     0;  // Amount of Y-direction offset of the panel
      cfg.offset_rotation  =     0;  // Offset of values ​​in the direction of rotation 0 ~ 7 (4 ~ 7 are upside down)
      cfg.dummy_read_pixel =     8;  // Number of bits of dummy read before reading pixels
      cfg.dummy_read_bits  =     1;  // Number of bits of dummy read before reading data other than pixels
      cfg.readable         =  true;  // Set to true if data can be read
      cfg.invert           = false;  // Set to true if the light and darkness of the panel is reversed
      cfg.rgb_order        = false;  // Set to true if the red and blue of the panel are swapped
      cfg.dlen_16bit       = false;  // Set to true for panels that send data length in 16-bit units
      cfg.bus_shared       = false;  // If the bus is shared with the SD card, set to true (bus control is performed with drawJpgFile etc.)

      _panel_instance.config(cfg);
    }

//*
    { // バックライト制御の設定を行います。(必要なければ削除)
      auto cfg = _light_instance.config();    // バックライト設定用の構造体を取得します。

      cfg.pin_bl = 45;              // バックライトが接続されているピン番号
      cfg.invert = false;           // バックライトの輝度を反転させる場合 true
      cfg.freq   = 50000;           // バックライトのPWM周波数
      cfg.pwm_channel = 1;          // 使用するPWMのチャンネル番号

      _light_instance.config(cfg);
      _panel_instance.setLight(&_light_instance);  // バックライトをパネルにセットします。
    }
//*/

    setPanel(&_panel_instance); // 使用するパネルをセットします。
  }
};

// 準備したクラスのインスタンスを作成します。
LGFX display;

static LGFX_Sprite buffer;

const int lcd_height = 272;
const int lcd_width = 480;
const int box_height_weight = 150;

void setup(void)
{ 
  Serial.begin(115200);
  Serial.println("Initialization started!");

  // SPIバスとパネルの初期化を実行すると使用可能になります。
  display.init();

  display.fillScreen(TFT_BLACK);
  display.setBrightness(255);

  display.setColorDepth(8);

  buffer.setColorDepth(8);
  auto ptr = buffer.createSprite(lcd_width, lcd_height);
  if (ptr == nullptr) {
    Serial.println("Buffer sprite could not be created");
    return;
  }

  display.startWrite();
  display.setAddrWindow(0, 0, lcd_width, lcd_height);

  Serial.println("Initialization complete!");
}

uint32_t count = ~0;
void loop(void)
{
  for (int i=0; i<(lcd_width + box_height_weight);i += 8) {
    buffer.setColor(TFT_BLACK);
    buffer.fillScreen();

    buffer.setColor(TFT_BLUE);
    buffer.fillRect(-box_height_weight + i, 50, box_height_weight, box_height_weight);

    buffer.pushSprite(&display,0,0);
  }

}
JeremiahGillis commented 2 years ago

I did some investigation today. The answer is that the LCD panel driver requires different clock, HSYNC, and VSYNC settings. I think the SSD1963 was driving the LCD panel driver too fast, causing it to get lost, possibly resetting. I was able to fix this by changing some of the getInitCommands in Panel_SSD1963.hpp. I have not figured out the exact timings yet as I am waiting for the LCD panel driver datasheet.

I can create a PR once I figure everything out in case someone want to use this display and controller. In addition, I want to enable 16-bit parallel mode which requires changes to the same file.

lovyan03 commented 2 years ago

@JeremiahGillis I'm sorry for the delay in responding.

I will buy the same one and check it out. Is the one in this URL the same one?

https://www.buydisplay.com/5-inch-tft-ssd1963-lcd-module-optl-touch-screen-display-480x272-arduino

JeremiahGillis commented 2 years ago

I'm sorry for the delay in responding.

No problem. I purchased this one. However I don't think there is any need for you to spend money on it.

I was able to get this working after some experimentation. It required different timings and settings in the getInitCommands function. What was strange was that even with the correct timings, the display still didn't work correctly. It seems that the panel size in 0xB0 has to be correct. That is, it cannot be changed later on in Panel_SSD1963::init function. I did a lot of debugging and implemented setHSync and setVSync so it could be called from the sketch. I will look into this further when I get a chance and report back to see why the panel size cannot be changed later on as you intended.

Is the intention to change settings in the panel files like Panel_SSD1963.hpp? I think it would be better if the init could be passed from a sketch or C file outside the library.

One last thing for my understanding, does Parallel16 require a certain data format? For example, the SSD1963 has the data format below. Does your library work with when using 8 bits for every color as shown, requiring three cycles? Or, does it only work for 565 format, requiring one cycle?

image

Right now I am just using Parallel8 on ESP32-S2. I may change some settings in the panel driver so I can use Parallel16 for improved animation.

lovyan03 commented 2 years ago

@JeremiahGillis

Is the intention to change settings in the panel files like Panel_SSD1963.hpp? I think it would be better if the init could be passed from a sketch or C file outside the library.

I am also wondering how to implement this correctly. When LGFX was first developed, we were dealing with ILI9341, ST7735, etc., which have fixed initialization commands. Therefore, there was no need to implement variability in the initialization process.

Frankly speaking, LovyanGFX's support work for SSD1963 is incomplete.

I supported SSD1963 at the request of a user, but I do not understand the specification in detail. Also, since I only own one, I have not been able to test the support for multiple different resolutions at all. In that sense, I feel the need to purchase another SSD1963.

One last thing for my understanding, does Parallel16 require a certain data format? For example, the SSD1963 has the data format below. Does your library work with when using 8 bits for every color as shown, requiring three cycles? Or, does it only work for 565 format, requiring one

Although the LGFX is capable of supporting both RGB565 and RGB888, Panel_SSD1963 has fixed it to only RGB888. I've already forgotten the reason for this restriction. Probably because I couldn't find a way to switch the mode of SSD1963 at runtime during my previous support work. This constraint is implemented by setColorDepth_impl, so commenting out this function will allow you to change it at runtime.

gfx.setColorDepth(16); // RGB565
gfx.setColorDepth(24); // RGB888

…I'll still buy another SSD1963. I was convinced that I would need it in order to proceed with the discussion with you.

JeremiahGillis commented 2 years ago

…I'll still buy another SSD1963.

Sounds good. I'll sponsor you to help pay for it.

We can improve this driver together and complete the work. I'll post what I learn later this week. Just let me know when you get a chance to work with the hardware.

lovyan03 commented 2 years ago

@JeremiahGillis Sorry for the late reply. I Updated LovyanGFX develop branch. SSD1963 now works with ESP32-S2 Bus_Parallel16. This has been confirmed to work on a panel I have owned for some time.

And, I have obtained a 480x272 panel from BuyDisplay that is identical to the panel you own. I will begin to confirm that it works in the near future.

lovyan03 commented 2 years ago

@JeremiahGillis I just updated the develop branch again. It now automatically adjusts timing parameters based on resolution.

I have successfully gotten the EastRising panel to work. I am able to display it probably without any problems.

https://user-images.githubusercontent.com/42724151/159214662-042e9856-779c-446d-81e7-c937213316ae.MOV

JeremiahGillis commented 2 years ago

@lovyan03 Sorry for the delay, I was traveling for work. Thanks for the changes! I can confirm the changes work with my screen in both Parallel 8 and 16. Your implementation is much better for anyone who might need to change the screen timings.

I'll let you know if I find any other issues. I see that you started to make changes for ESP32-S3. Do you have an idea when you might add Parallel 8 & 16 support? I plan to move this project to an ESP32-S3 when I create a PCB.

lovyan03 commented 2 years ago

@JeremiahGillis I greatly appreciate your support for me ! I am also pleased that the library updates I have made have been helpful to you.

I would like to start work on the ESP32-S3 parallel as soon as possible, preferably within a month, but I do not yet know how long it will take to complete. I have a lot to look into because S2 and S3 have completely different DMA peripheral mechanisms.

I would like to proceed in a manner that meets your expectations.

JeremiahGillis commented 2 years ago

@lovyan03 The sooner the better for me. Obviously you have a lot going on and we are at your mercy. I appreciate everything you have done so far!

I tried to direct message you on twitter, but it says you cannot be direct messaged. When you have a moment, please view my GitHub profile, get my email address, and contact me. I would like to propose something privately.

lovyan03 commented 2 years ago

@JeremiahGillis Thank you very much ! I now follow you on Twitter. You can now send me DMs.