Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Shimering effect with SSD1963 #583

Closed
tylercamp opened this issue Jun 26, 2024 · 17 comments
Closed

Shimering effect with SSD1963 #583

tylercamp opened this issue Jun 26, 2024 · 17 comments
Labels
enhancement New feature or request

Comments

@tylercamp
Copy link
Sponsor

tylercamp commented Jun 26, 2024

I'm using this display with an ESP32 adapter board (available on the same page) which has an SSD1963Q9: https://www.aliexpress.us/item/3256805880921100.html

Working sample code.zip - In LCDWIKI_KBV.cpp see Set_1963_PWM at line 726.

(Removed old irrelevant comments)

The original issue here was largely missing backlight control and confusion from an "RS" pin mislabeled as "CD", but with the goal of this GH issue being a well-functioning display, there's still a shimmering effect that happens when using LGFX but not when using the attached sample code.

(One of the original issues with backlight control was weird since LGFX init for SSD1963 does include commands to set backlight, not sure why it didn't seem to be working. Maybe a larger compatibility issue with command set?)

My LGFX_Device definition:

New LGFX config here

@tylercamp tylercamp added the enhancement New feature or request label Jun 26, 2024
@tobozo
Copy link
Collaborator

tobozo commented Jun 26, 2024

hi,

cfg.freq_write = 200000;

200 KHz seems rather slow for a parallel display, have you tried in the MHz range ?

[edit] also LightPWM isn't configured, so no backlight

@tylercamp
Copy link
Sponsor Author

tylercamp commented Jun 26, 2024

I set it to 20MHz to start with, and since I wasn't getting any output, I tried lowering it as one of the troubleshooting steps. In order to test output I had to manually and indirectly connect to a backlight pin which is normally not exposed to the ESP32

(The ESP32 connects to an adapter board which connects to the display via one of two FPC cables, the display has two FPC ports and I happened to have an FPC breakout which allowed me to manually apply 3V3 on the backlight pin for the display using the 2nd FPC port. However the FPC is raw 24-bit RGB, bypassing the SSD1963, so I can't use this long term)

The adapter board does not expose a backlight pin to the ESP32, and I didn't see a suitable alternative impl. for controlling backlight with SSD1963, so I left that commented out

The sample code I attached shows a command sent to SSD1963 for controlling backlight. Is there an alternative LGFX_Light impl. which can work with this?

@tobozo
Copy link
Collaborator

tobozo commented Jun 26, 2024

sorry I didn't read your full post before replying 😊

you can probably take the Set_1963_PWM() function from the vendor and implement it inside your LGFX custom class, this is untested code, and the function should be called after display.init():

class LGFX : public lgfx::LGFX_Device
{
  // ... ( your existing config )

    void Set_1963_PWM(uint8_t value)
    {
      uint8_t pwm=value*2.55;
      _bus_instance.writeCommand(0xBE, 8);
      _bus_instance.wait();
      _bus_instance.writeData( 0xBE, 8 );
      _bus_instance.writeData( 0x05, 8 );
      _bus_instance.writeData( pwm, 8 );
      _bus_instance.writeData( 0x01, 8 );
      _bus_instance.writeData( 0xFF, 8 )
      _bus_instance.writeData( 0x00, 8 )
      _bus_instance.writeData( 0x00, 8 );
      _bus_instance.wait();
    }
}

if this solves the issue for you then we'll think about a way to include this in the driver without affecting the other SSD1963 variants

@tylercamp
Copy link
Sponsor Author

Sounds good, I'll give that a try later!

Do you happen to know anything about that cd pin that's referenced? I'm currently seeing shimmering in the output when using LGFX and I'm wondering if that's related. I don't see that behavior when using the sample code

(The pin is just used to digitalWrite(HIGH) in the LCDWIKI_KBV ctor, but it's also referenced with CD_COMMAND/CD_DATA macros from mcu_8bit_magic.h)

New LGFX config:

    { // バス制御の設定を行います。
      auto cfg = _bus_instance.config();    // バス設定用の構造体を取得します。


// 8ビットパラレルバスの設定
      // cfg.i2s_port = I2S_NUM_0;     // 使用するI2Sポートを選択 (I2S_NUM_0 or I2S_NUM_1) (ESP32のI2S LCDモードを使用します)
      cfg.freq_write = 12000000;    // 送信クロック (最大20MHz, 80MHzを整数で割った値に丸められます)
      cfg.pin_wr = DISPLAY_SSD1963_WR;              // WR を接続しているピン番号
      cfg.pin_rd = DISPLAY_SSD1963_RD;              // RD を接続しているピン番号
      cfg.pin_rs = DISPLAY_SSD1963_RS;              // RS(D/C)を接続しているピン番号
      cfg.pin_d0 = DISPLAY_SSD1963_D0;              // D0を接続しているピン番号
      cfg.pin_d1 = DISPLAY_SSD1963_D1;              // D1を接続しているピン番号
      cfg.pin_d2 = DISPLAY_SSD1963_D2;              // D2を接続しているピン番号
      cfg.pin_d3 = DISPLAY_SSD1963_D3;              // D3を接続しているピン番号
      cfg.pin_d4 = DISPLAY_SSD1963_D4;              // D4を接続しているピン番号
      cfg.pin_d5 = DISPLAY_SSD1963_D5;              // D5を接続しているピン番号
      cfg.pin_d6 = DISPLAY_SSD1963_D6;              // D6を接続しているピン番号
      cfg.pin_d7 = DISPLAY_SSD1963_D7;              // D7を接続しているピン番号
//*/

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

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

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

      // ※ 以下の設定値はパネル毎に一般的な初期値が設定されていますので、不明な項目はコメントアウトして試してみてください。

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

      _panel_instance.config(cfg);
    }

@tobozo
Copy link
Collaborator

tobozo commented Jun 26, 2024

maybe _bus_instance.config().cfg.pin_ctrl[3] can be used for pulling CD high ? e.g. cfg.pin_ctrl = { DISPLAY_SSD1963_CD, -1, -1 }; ?

(The pin is just used to digitalWrite(HIGH) in the LCDWIKI_KBV ctor, but it's also referenced with CD_COMMAND/CD_DATA macros from mcu_8bit_magic.h)

apparently CD_COMMAND uses that DC pin too in LCDWIKI_KBV::reset(), but I don't know Panel_SSD1963 well enough to take a guess at how LGFX should handle it, maybe this needs a custom implementation of Bus_Parallel8 too

@tylercamp
Copy link
Sponsor Author

Oh whoops, looks like "CD" was a typo that made its way throughout the sample codebase:

#define CD_PIN   15  // Data Command control pin - must use a pin in the range 0-31

D/C i.e. RS pin is 15, which is mapped correctly

So it looks like all of the pins are assigned as expected, I'm just not sure why I'm getting shimmering

I tried comparing the init command bytes which are similar but different enough that I can't make a good comparison. I did notice differences in timing values, and changing xtal_clock affects the shimmering, so it's likely a timing issue

@tylercamp tylercamp changed the title Incomplete support for SSD1963? Shimering effect with SSD1963 Jun 27, 2024
@dekesone
Copy link

dekesone commented Jul 3, 2024

I have LGFX working great on the same 5" display noted by @tylercamp but have spent the last 6 hours pulling my hair out trying to get the backlight to work properly. I have the same sample code (In LCDWIKI_KBV.cpp see Set_1963_PWM at line 726) that properly adjust the backlight PWM, but for the life of me can not get it to work within LGFX,

The example function above provided by @tobozo seems to be close but does not work. I noticed a few things that I attempted to correct:
This line seems to be unnecessary: _bus_instance.writeData( 0xBE, 8 );
The writeCommand() should 16 bit length
There's a few missing ;

But nonetheless still no luck.
I have subsequently dug deeper into the Dynamic Backlight Control and the SSD1963 datasheet. It seems that after setting the PWM value, you also have to turn on DBC. Here's the pseudo code from the datasheet:

The hardware pin, PWM is the output signal from SSD1963 to the system backlight driver. So it should configure PWM module before enable DBC.
WRITE COMMAND “0xBE”
WRITE DATA “0x0E” (set PWM frequency)
WRITE DATA “0xFF” (dummy value if DBC is used)
WRITE DATA “0x09” (enable PWM controlled by DBC)
WRITE DATA “0xFF”
WRITE DATA “0x00”
WRITE DATA “0x00”
WRITE COMMAND “0xD4” (Define the threshold value)
WRITE DATA .....
WRITE COMMAND “0xD0”
WRITE DATA “0x0D” (Enable DBC with Aggressive mode

Any suggestions on how to proceed?

edit: here is the datasheet, section 9.46 outlines the PWM functionality and section 9.63 outlines DBC
https://pdf1.alldatasheet.com/datasheet-pdf/view/1179028/ETC2/SSD1963.html

@tylercamp
Copy link
Sponsor Author

@dekesone Could you provide your LGFX config?

@dekesone
Copy link

dekesone commented Jul 3, 2024

Here's what works well for me, minus the PWM backlight obviously.

gfx_conf.h.txt

@tylercamp
Copy link
Sponsor Author

@dekesone thanks for the reference, I found that I was missing this:

      cfg.panel_width = cfg.memory_width = 800;
      cfg.panel_height = cfg.memory_height = 480;

I thought I saw init of panel dimensions in the SSD1963 ctor so it seemed unnecessary, but this was the cause of the shimmering I saw.

For the PWM backlight:

I have subsequently dug deeper into the Dynamic Backlight Control and the SSD1963 datasheet. It seems that after setting the PWM value, you also have to turn on DBC. Here's the pseudo code from the datasheet: ...

The last two lines for enabling DBC are present in the SSD1963 fixed_cmds:

...
      0xD0, 1, 0x0D, // <-- here (L133)
...

... so whatever the underlying backlight issue is, it doesn't seem like it's due to missing DBC init.

@tylercamp
Copy link
Sponsor Author

tylercamp commented Jul 4, 2024

@dekesone Got it! The general commands were correct but there were underlying operations that were missing (e.g. toggling CS pin) since we were interacting with _bus_instance directly. I updated the commands to use the same functions as Panel_SSD1963::init and command_list:

  void Set_1963_PWM(uint8_t value)
  {
    startWrite();
    writeCommand16(0xBE);
    _bus_instance.flush();

    writeData( 0x05 );
    writeData( value );
    writeData( 0x01 );
    writeData( 0xFF );
    writeData( 0x00 );
    writeData( 0x00 );

    endWrite();
  }

@tylercamp
Copy link
Sponsor Author

tylercamp commented Jul 4, 2024

@tobozo Since this type of backlight control is specific to the particular Panel_LCD, I wonder if any of these minor refactors would be appropriate:

// additional class to be mixed in when appropriate and manually called by the user if needed
class IPanel_LCD_InteractiveBacklight {
   // (1) panel is capable of creating an ILight instance which references this panel for commands
   virtual ILight* createLight() = 0;
   
   // ... or ...
   
   // (2) panel directly exposes a `setBrightness`, and a new `Light_InteractivePanel` class
   //       would simply defer to this
   virtual void setBrightness(...) = 0;
};

// ... or ...

class Panel_SSD1963 {
public:
   // (3) panel defines its own `ILight` impl to be explicitly created by the user and assigned to `LGFX_Device`
   class Light : ILight { ... };
};

// ... or ...
class Panel_Device {

   // ...
   
   // (4) all panels may directly offer a `ILight`; panels like SSD1963 will always have backlight control
   //
   // if no `ILight` was specifically assigned to `LGFX_Device`, then it would defer to 
   // the panel
   virtual ILight* getLight() { return nullptr; };
   
   // ...
};

(2) seems most in line with current LGFX patterns

EDIT: I'll make a new issue rather than re-scoping this for the third time

@tylercamp
Copy link
Sponsor Author

To summarize:

The shimmering effect I saw was due to incomplete display init. Assigning panel_width/height and memory_width/height fixed this problem.

We've figured out how to manage backlight control with LGFX and some customizations, but there should be an update to LGFX to properly support this case. #586

@dekesone
Copy link

dekesone commented Jul 4, 2024

Thanks @tylercamp, great work !

@tobozo
Copy link
Collaborator

tobozo commented Jul 4, 2024

@tylercamp thanks for breaking out the different suggested solutions 👍 , I have forwarded the new issue link to lovyan03 as I honestly don't know which one is better since this is beyond my skills

however he's been very busy lately so don't expect a lightning fast answer 😉

@tylercamp
Copy link
Sponsor Author

@dekesone An update was pushed to develop branch by @lovyan03, are you able to test the update? I'm away from home and don't have a device to test with right now

@tylercamp
Copy link
Sponsor Author

@dekesone proper fix merged to 'develop' branch, call 'myLgfx->setBrightness' instead of 'myLgfx->light()->setBrightness' (which is apparently the preferred method in general but the examples get the light directly instead)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants