lovyan03/LovyanGFX

Support for panel-controlled backlights

Closed this issue · 8 comments

(Moved from #583 )

Some panels, i.e. SSD1963, come with built-in backlight control which require device-specific commands to manage.

Currently there isn't any ILight implementation which supports this.


For SSD1963 specifically, these commands are needed for backlight control:

  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();
  }

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

Hello, @tylercamp , @tobozo

Apologies for the late reply.
Here are my thoughts:

  void Panel_SSD1963::setBrightness(uint8_t brightness)  //override
  {
    if (_light) { Panel_LCD::setBrightness(brightness); }
    else {
      uint8_t cmds[] = { 0xBE, 6, 0x05, brightness, 0x01, 0xFF, 0x00, 0x00, 0xFF, 0xFF };
      command_list(cmds);
    }
  }

I've updated the develop branch, so please try it out.
If Light is not configured, the SSD1963 built-in PWM control should work automatically.

@lovyan03 Nice! I didn't notice the panel had a setBrightness on it directly

I'm away from home and don't have a device to test with, dekesone may be able to test in the meantime (I'll comment on the original issue and tag him)

@lovyan03 This almost works, it's just missing a call to start/endWrite, I've opened a PR here #599

Merged

I'm not able to get this to work. I'm not instantiating an instance of the Light_PWM, but now get no response from the display. @tylercamp can you share your config?

On a side note, is anyone using PLatformIO ? If I change my platformio.ini file to reference the develop branch of LGFX
lib_deps = lovyan03/LovyanGFX #develop
it will not build. But if I download the develop branch from Github and extract it into the solution (and change my #include, it will build successfully.

@dekesone I'm also using PlatformIO and am referencing my own fork currently, but lovyan repo should work too since it's been merged:

lib_deps =
  https://github.com/tylercamp/LovyanGFX#develop

(I also tried changing to lovyan repo with https://github.com/lovyan03/LovyanGFX#develop just in case, and that also worked for me)

My LGFX config:

class LGFX : public lgfx::LGFX_Device
{
  lgfx::Panel_SSD1963     _panel_instance;
  lgfx::Bus_Parallel8  _bus_instance;

  lgfx::Touch_FT5x06           _touch_instance;
public:

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

      cfg.pin_wr = DISPLAY_SSD1963_WR;
      cfg.pin_rd = DISPLAY_SSD1963_RD;
      cfg.pin_rs = DISPLAY_SSD1963_RS;
      cfg.pin_d0 = DISPLAY_SSD1963_D0;
      cfg.pin_d1 = DISPLAY_SSD1963_D1;
      cfg.pin_d2 = DISPLAY_SSD1963_D2;
      cfg.pin_d3 = DISPLAY_SSD1963_D3;
      cfg.pin_d4 = DISPLAY_SSD1963_D4;
      cfg.pin_d5 = DISPLAY_SSD1963_D5;
      cfg.pin_d6 = DISPLAY_SSD1963_D6;
      cfg.pin_d7 = DISPLAY_SSD1963_D7;

      _bus_instance.config(cfg);
      _panel_instance.setBus(&_bus_instance);
    }

    {
      auto cfg = _panel_instance.config();

      cfg.pin_cs           =    DISPLAY_SSD1963_CS;
      cfg.pin_rst          =    DISPLAY_SSD1963_RST;
      cfg.pin_busy         =    35; 

      cfg.panel_width = cfg.memory_width = 800;
      cfg.panel_height = cfg.memory_height = 480;
      cfg.offset_x         =     0;
      cfg.offset_y         =     0; 
      cfg.offset_rotation  =     0;
      cfg.rgb_order        = true;
      cfg.dlen_16bit       = false;

      _panel_instance.config(cfg);
    }

    {
      auto cfg = _touch_instance.config();

      cfg.x_min      = 0;
      cfg.x_max      = 839;
      cfg.y_min      = 0;
      cfg.y_max      = 479;
      cfg.pin_int    = TOUCH_INT;
      cfg.bus_shared = true;
      cfg.offset_rotation = 0;
      cfg.pin_rst    = TOUCH_RST;
      
      cfg.i2c_port = 1;
      cfg.i2c_addr = 0x38; 
      cfg.pin_sda  = TOUCH_SDA;
      cfg.pin_scl  = TOUCH_SCL;
      cfg.freq = 400000;

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

    setPanel(&_panel_instance);
  }
};

To change the brightness I just call display->setBrightness. For my test I did it immediately after display init, since updating brightness in main loop needs to avoid calling LGFX functions in parallel (I'm using LVGL with multithreaded render and pushImageDMA using a call on dedicated thread)

display = new LGFX();
display->init();
display->clear(0);
display->setBrightness(10);

(Set very low for testing just so it's easier to see diff. in brightness)

Everything's working fine now, and I can confirm the PWM control now works as expected. Thanks!

(for some reason, using the lib_deps reference to lovyan03/LovyanGFX#develop still does not work, even though the code is downloaded on build. But explicitly using the full github url lib_deps = https://github.com/lovyan03/LovyanGFX#develop works correctly.