From 4e21cf232cdc82c4041391a9838e72899189219e Mon Sep 17 00:00:00 2001 From: mverch67 Date: Sat, 25 Jan 2025 14:46:57 +0100 Subject: [PATCH 1/4] lvgl driver initial draft --- .../graphics/{driver => LGFX}/LGFXDriver.h | 3 + include/graphics/LGFX/LGFX_GENERIC.h | 1 + include/graphics/LVGL/LVGLConfig.h | 210 ++++++++++++++++++ include/graphics/LVGL/LVGLDriver.h | 129 +++++++++++ include/graphics/LVGL/LVGL_ST7789_Driver.h | 19 ++ include/graphics/LVGL/LVGL_T_DECK.h | 35 +++ include/graphics/driver/DisplayDeviceDriver.h | 30 +++ include/graphics/driver/DisplayDriverConfig.h | 2 + include/graphics/driver/EINKDriver.h | 23 ++ include/graphics/driver/TFTDriver.h | 4 + include/lv_conf.h | 8 + source/graphics/LVGL/LVGL_T_DECK.cpp | 50 +++++ .../graphics/driver/DisplayDriverFactory.cpp | 157 ++++--------- 13 files changed, 558 insertions(+), 113 deletions(-) rename include/graphics/{driver => LGFX}/LGFXDriver.h (99%) create mode 100644 include/graphics/LVGL/LVGLConfig.h create mode 100644 include/graphics/LVGL/LVGLDriver.h create mode 100644 include/graphics/LVGL/LVGL_ST7789_Driver.h create mode 100644 include/graphics/LVGL/LVGL_T_DECK.h create mode 100644 include/graphics/driver/DisplayDeviceDriver.h create mode 100644 include/graphics/driver/EINKDriver.h create mode 100644 source/graphics/LVGL/LVGL_T_DECK.cpp diff --git a/include/graphics/driver/LGFXDriver.h b/include/graphics/LGFX/LGFXDriver.h similarity index 99% rename from include/graphics/driver/LGFXDriver.h rename to include/graphics/LGFX/LGFXDriver.h index 930412ac..66593a36 100644 --- a/include/graphics/driver/LGFXDriver.h +++ b/include/graphics/LGFX/LGFXDriver.h @@ -1,5 +1,6 @@ #pragma once +#ifdef LGFX_DRIVER #include "LovyanGFX.h" #include "graphics/driver/DisplayDriverConfig.h" #include "graphics/driver/TFTDriver.h" @@ -460,3 +461,5 @@ template void LGFXDriver::printConfig(void) ILOG_DEBUG("BL pin assigned"); } } + +#endif \ No newline at end of file diff --git a/include/graphics/LGFX/LGFX_GENERIC.h b/include/graphics/LGFX/LGFX_GENERIC.h index 3be7115d..31d49a85 100644 --- a/include/graphics/LGFX/LGFX_GENERIC.h +++ b/include/graphics/LGFX/LGFX_GENERIC.h @@ -12,6 +12,7 @@ * build_flags = * -D LGFX_DRIVER_TEMPLATE * -D LGFX_DRIVER=LGFX_GENERIC + * -D GFX_DRIVER_INC=\"graphics/LGFX/LGFX_GENERIC.h\" * -D LGFX_PANEL=ST7789 * -D LGFX_TOUCH=XPT2046 * -D LGFX_INVERT_COLOR=true diff --git a/include/graphics/LVGL/LVGLConfig.h b/include/graphics/LVGL/LVGLConfig.h new file mode 100644 index 00000000..85e637ae --- /dev/null +++ b/include/graphics/LVGL/LVGLConfig.h @@ -0,0 +1,210 @@ +#pragma once + +#ifdef LVGL_DRIVER + +#include "graphics/LVGL/LVGLDriver.h" +#include "graphics/LVGL/LVGL_ST7789_Driver.h" +#include "graphics/driver/DisplayDriverConfig.h" +#include "strings.h" +#include "util/ILog.h" + +class DisplayDeviceDriver; + +/** + * @brief Runtime configuration class for lvgl driver + * + */ +class LVGLConfig : public LVGLDriver +{ + public: + uint16_t screenWidth = 0; + uint16_t screenHeight = 0; + + void init(void) {} + bool hasButton(void) { return false; } + bool light(void) { return true; } + + LVGLConfig(void) : LVGLDriver(0, 0) {} + + LVGLConfig(const DisplayDriverConfig &config) : LVGLDriver(config._width, config._height) + { + ILOG_DEBUG("LVGLConfig ...\n"); + { // configure panel settings + if (strcasecmp(config._panel.type, "ST7789") == 0) { + lvglDeviceDriver = new LVGL_ST7789_Driver(config); + // lvglDeviceDriver = new LVGLDriver(config); + // TODO: allocate touch driver + } else { + ILOG_ERROR("LVGL device panel support not yet implemented for '%s'\n", config._panel.type); + return; + } + } +#if 0 + auto cfg = lvglDriver->config(); + + if (config._panel.rotation) { + cfg.panel_width = config._height; + cfg.panel_height = config._width; + } else { + cfg.panel_width = config._width; + cfg.panel_height = config._height; + } + screenWidth = cfg.panel_width; + screenHeight = cfg.panel_height; + + cfg.pin_cs = config._panel.pin_cs; + cfg.pin_rst = config._panel.pin_rst; + cfg.pin_busy = config._panel.pin_busy; + cfg.offset_x = config._panel.offset_x; + cfg.offset_y = config._panel.offset_y; + cfg.offset_rotation = config._panel.offset_rotation; + cfg.invert = config._panel.invert; + cfg.dummy_read_pixel = config._panel.dummy_read_pixel; + cfg.dummy_read_bits = config._panel.dummy_read_bits; + cfg.readable = config._panel.readable; + cfg.invert = config._panel.invert; + cfg.rgb_order = config._panel.rgb_order; + cfg.dlen_16bit = config._panel.dlen_16bit; + cfg.bus_shared = config._panel.bus_shared; + + ILOG_DEBUG("Panel_Device(%s): %dx%d, cs=%d, rst=%d, busy=%d\n", config._panel.type, screenWidth, screenHeight, + cfg.pin_cs, cfg.pin_rst, cfg.pin_busy); + _panel_instance->config(cfg); + } + + { // configure bus settings +#ifndef ARCH_PORTDUINO + if (config._bus.parallel.pin_d0 > 0) { + lgfx::Bus_Parallel8 *bus = new lgfx::Bus_Parallel8; + auto cfg = bus->config(); + cfg.freq_write = config._bus.freq_write; +#if CONFIG_IDF_TARGET_ESP32S3 + cfg.freq_read = config._bus.freq_read; +#endif + for (int i = 0; i < 8; i++) + cfg.pin_data[i] = config._bus.parallel.pin_data[i]; + cfg.pin_rd = config._bus.parallel.pin_rd; + cfg.pin_wr = config._bus.parallel.pin_wr; + cfg.pin_rs = config._bus.parallel.pin_rs; + bus->config(cfg); + _bus_instance = bus; + _panel_instance->setBus(_bus_instance); + } else +#endif + { + lgfx::Bus_SPI *bus = new lgfx::Bus_SPI; + auto cfg = bus->config(); + cfg.freq_write = config._bus.freq_write; + cfg.freq_read = config._bus.freq_read; + cfg.pin_sclk = config._bus.spi.pin_sclk; + cfg.pin_miso = config._bus.spi.pin_miso; + cfg.pin_mosi = config._bus.spi.pin_mosi; + cfg.pin_dc = config._bus.spi.pin_dc; + cfg.spi_mode = config._bus.spi.spi_mode; +#ifdef ARDUINO_ARCH_ESP32 + cfg.spi_host = (spi_host_device_t)config._bus.spi.spi_host; +#else + cfg.spi_host = config._bus.spi.spi_host; +#endif + ILOG_DEBUG("Bus_SPI: freq=%d, host=%02x, dc=%d\n", cfg.freq_write, cfg.spi_host, cfg.pin_dc); + bus->config(cfg); + _bus_instance = bus; + _panel_instance->setBus(_bus_instance); + } + } + + { // Configure settings for touch control. + if (config._touch.type && strcasecmp(config._touch.type, "NOTOUCH") != 0) { + if (strcasecmp(config._touch.type, "XPT2046") == 0) { + _touch_instance = new lgfx::Touch_XPT2046; + } else if (strcasecmp(config._touch.type, "GT911") == 0) { + _touch_instance = new lgfx::Touch_GT911; + } else if (strcasecmp(config._touch.type, "FT5x06") == 0 || strcasecmp(config._touch.type, "FT5206") == 0 || + strcasecmp(config._touch.type, "FT5306") == 0 || strcasecmp(config._touch.type, "FT5406") == 0 || + strcasecmp(config._touch.type, "FT6206") == 0 || strcasecmp(config._touch.type, "FT6236") == 0 || + strcasecmp(config._touch.type, "FT6336") == 0 || strcasecmp(config._touch.type, "FT6436") == 0) { + _touch_instance = new lgfx::Touch_FT5x06; + } else if (strcasecmp(config._touch.type, "STMPE610") == 0) { + _touch_instance = new lgfx::Touch_STMPE610; + } else { + ILOG_ERROR("Touch panel '%s' support not implemented\n", config._touch.type); + return; + } + + auto cfg = _touch_instance->config(); + + cfg.freq = config._touch.freq; + if (config._touch.x_min >= 0) + cfg.x_min = config._touch.x_min; + if (config._touch.x_max >= 0) + cfg.x_max = config._touch.x_max; + if (config._touch.y_min >= 0) + cfg.y_min = config._touch.y_min; + if (config._touch.y_max >= 0) + cfg.y_max = config._touch.y_max; + cfg.pin_int = config._touch.pin_int; + cfg.pin_rst = config._touch.pin_rst; + cfg.bus_shared = config._touch.bus_shared; + cfg.offset_rotation = config._touch.offset_rotation; + cfg.pin_cs = config._touch.pin_cs; + + if (config._touch.i2c.i2c_addr > 0 && cfg.pin_cs == -1) { + cfg.i2c_port = config._touch.i2c.i2c_port; + cfg.pin_scl = config._touch.i2c.pin_scl; + cfg.pin_sda = config._touch.i2c.pin_sda; + cfg.i2c_addr = config._touch.i2c.i2c_addr; + ILOG_DEBUG("Touch_I2C: freq=%d, port=%02x, addr=%d, cs=%d, int=%d, rst=%d\n", cfg.freq, cfg.i2c_port, + cfg.i2c_addr, cfg.pin_cs, cfg.pin_int, cfg.pin_rst); + } else { + cfg.spi_host = config._touch.spi.spi_host; + cfg.pin_sclk = config._touch.spi.pin_sclk; + cfg.pin_mosi = config._touch.spi.pin_mosi; + cfg.pin_miso = config._touch.spi.pin_miso; + ILOG_DEBUG("Touch_SPI: freq=%d, host=%02x, cs=%d, int=%d, rst=%d\n", cfg.freq, cfg.spi_host, cfg.pin_cs, + cfg.pin_int, cfg.pin_rst); + } + + _touch_instance->config(cfg); + _panel_instance->setTouch(_touch_instance); + } + } + + { // configure TFT backlight + if (config._light.pin_bl != -1) { +#ifdef ARCH_PORTDUINO + auto light = new portduino::Light_PWM; +#else + auto light = new lgfx::Light_PWM; +#endif + auto cfg = light->config(); + + cfg.freq = config._light.freq; + cfg.pin_bl = config._light.pin_bl; + if (config._light.pwm_channel >= 0) + cfg.pwm_channel = config._light.pwm_channel; + cfg.invert = config._light.invert; + + ILOG_DEBUG("Light_PWM: freq=%d, pwm=%d, bl=%d\n", cfg.freq, cfg.pwm_channel, cfg.pin_bl); + light->config(cfg); + _panel_instance->setLight(light); + _light_instance = light; + } + } + + setPanel(_panel_instance); +#endif + } + + ~LVGLConfig() { delete lvglDeviceDriver; } + + protected: + lv_display_t *create(uint32_t hor_res, uint32_t ver_res) override + { + return nullptr; // TODO + } + + private: + DisplayDeviceDriver *lvglDeviceDriver; +}; + +#endif \ No newline at end of file diff --git a/include/graphics/LVGL/LVGLDriver.h b/include/graphics/LVGL/LVGLDriver.h new file mode 100644 index 00000000..c5982b88 --- /dev/null +++ b/include/graphics/LVGL/LVGLDriver.h @@ -0,0 +1,129 @@ +#pragma once + +#ifdef LVGL_DRIVER +#include "drivers/display/lcd/lv_lcd_generic_mipi.h" +#include "graphics/driver/DisplayDriverConfig.h" +#include "graphics/driver/TFTDriver.h" +#include "input/InputDriver.h" +#include "util/ILog.h" + +/** + * Base class for all specific LVGL drivers classes + */ +template class LVGLDriver : public TFTDriver +{ + public: + const uint32_t defaultScreenTimeout = 60 * 1000; + const uint32_t defaultScreenLockTimeout = 5 * 1000; + const uint32_t defaultBrightness = 153; + + LVGLDriver(uint16_t width, uint16_t height); + LVGLDriver(const DisplayDriverConfig &cfg); + void init(DeviceGUI *gui) override; + bool hasTouch(void) override; + bool hasButton(void) override { return lvgldriver->hasButton(); } + bool hasLight(void) override { return lvgldriver->light(); } + bool isPowersaving(void) override { return powerSaving; } + void task_handler(void) override; + + uint8_t getBrightness(void) override { return lvgldriver->getBrightness(); } + void setBrightness(uint8_t brightness) override {} // TODO + + uint16_t getScreenTimeout() override { return screenTimeout / 1000; } + void setScreenTimeout(uint16_t timeout) override { screenTimeout = timeout * 1000; }; + + ~LVGLDriver() { delete lvgldriver; } + + protected: + void init_lvgl(void); + virtual lv_display_t *create(uint32_t hor_res, uint32_t ver_res) = 0; + static void touchpad_read(lv_indev_t *indev_driver, lv_indev_data_t *data) {} // TODO + // static uint32_t my_tick_get_cb(void) { return millis(); } + + uint32_t screenTimeout; + uint32_t lastBrightness; + bool powerSaving; + + private: + static LVGL *lvgldriver; + lv_display_t *display; + size_t bufsize; + std::pair drawBuffer = {nullptr, nullptr}; +}; + +template LVGL *LVGLDriver::lvgldriver = nullptr; + +template +LVGLDriver::LVGLDriver(uint16_t width, uint16_t height) + : TFTDriver(lvgldriver ? lvgldriver : new LVGL, width, height), screenTimeout(defaultScreenTimeout), + lastBrightness(defaultBrightness), powerSaving(false), display(nullptr), bufsize(0) +{ + lvgldriver = this->tft; +} + +template +LVGLDriver::LVGLDriver(const DisplayDriverConfig &cfg) + : TFTDriver(lvgldriver ? lvgldriver : new LVGL(cfg), cfg.width(), cfg.height()), screenTimeout(defaultScreenTimeout), + lastBrightness(defaultBrightness), powerSaving(false), display(nullptr), bufsize(0) +{ + lvgldriver = this->tft; +} + +template void LVGLDriver::init(DeviceGUI *gui) +{ + ILOG_DEBUG("LVGLDriver::init...\n"); + init_lvgl(); + TFTDriver::init(gui); + + // LVGL: setup display device driver + ILOG_DEBUG("LVGL display driver create...\n"); + display = create(DisplayDriver::screenWidth, DisplayDriver::screenHeight); + + std::pair draw_buffers = {nullptr, nullptr}; + const auto buffer_size = + DisplayDriver::screenWidth * DisplayDriver::screenHeight * lv_color_format_get_size(lv_display_get_color_format(display)); + + ILOG_INFO("allocating %d bytes for LVGL draw buffers", buffer_size); + // ESP_ERROR_CHECK(esp_dma_malloc(EXAMPLE_LCD_H_RES * 100 * sizeof(lv_color_t), ESP_DMA_MALLOC_FLAG_PSRAM, draw_buffers.first, + // nullptr)); ESP_ERROR_CHECK(esp_dma_malloc(EXAMPLE_LCD_H_RES * 100 * sizeof(lv_color_t), ESP_DMA_MALLOC_FLAG_PSRAM, + // draw_buffers.second, nullptr)); + + draw_buffers.first = (lv_color_t *)lv_malloc(buffer_size); + if (draw_buffers.first == nullptr) { + LV_LOG_ERROR("display draw buffer malloc failed"); + return; + } + + draw_buffers.second = (lv_color_t *)lv_malloc(buffer_size); + if (draw_buffers.second == nullptr) { + LV_LOG_ERROR("display buffer malloc failed"); + lv_free(draw_buffers.first); + return; + } + lv_display_set_buffers(display, draw_buffers.first, draw_buffers.second, buffer_size, LV_DISPLAY_RENDER_MODE_PARTIAL); + + if (hasTouch()) { + lv_indev_t *indev = lv_indev_create(); + lv_indev_set_type(indev, LV_INDEV_TYPE_POINTER); + lv_indev_set_read_cb(indev, touchpad_read); + lv_indev_set_display(indev, this->display); + } +} + +template void LVGLDriver::init_lvgl(void) +{ + lvgldriver->init(); + lvgldriver->setBrightness(defaultBrightness); + // lvgldriver->fillScreen(LGFX::color565(0x3D, 0xDA, 0x83)); +} + +template bool LVGLDriver::hasTouch(void) +{ + return lvgldriver->hasTouch(); +} + +template void LVGLDriver::task_handler(void) +{ + DisplayDriver::task_handler(); +} +#endif \ No newline at end of file diff --git a/include/graphics/LVGL/LVGL_ST7789_Driver.h b/include/graphics/LVGL/LVGL_ST7789_Driver.h new file mode 100644 index 00000000..64d3c15c --- /dev/null +++ b/include/graphics/LVGL/LVGL_ST7789_Driver.h @@ -0,0 +1,19 @@ +#pragma once + +#ifdef LVGL_DRIVER + +#include "drivers/display/st7789/lv_st7789.h" +#include "graphics/driver/DisplayDeviceDriver.h" +#include "graphics/driver/DisplayDriverConfig.h" + +class LVGL_ST7789_Driver : public DisplayDeviceDriver +{ + public: + LVGL_ST7789_Driver() {} + LVGL_ST7789_Driver(const DisplayDriverConfig &) : DisplayDeviceDriver() {} + + protected: + private: +}; + +#endif \ No newline at end of file diff --git a/include/graphics/LVGL/LVGL_T_DECK.h b/include/graphics/LVGL/LVGL_T_DECK.h new file mode 100644 index 00000000..7b7779e2 --- /dev/null +++ b/include/graphics/LVGL/LVGL_T_DECK.h @@ -0,0 +1,35 @@ +#pragma once + +#ifdef LVGL_DRIVER + +#include "graphics/LVGL/LVGLDriver.h" +#include "lvgl.h" +#include "stdint.h" + +class LVGL_ST7789_Driver; + +class LVGL_TDECK : public LVGLDriver +{ + public: + LVGL_TDECK(void); + LVGL_TDECK(const DisplayDriverConfig &cfg); + + void init(void); + bool hasButton(void) { return true; } + bool light(void) { return true; } + uint8_t getBrightness(void) { return 128; } + + static constexpr uint16_t screenWidth = 320; + static constexpr uint16_t screenHeight = 240; + + protected: + lv_display_t *create(uint32_t hor_res, uint32_t ver_res) override; + + private: + static void lcd_send_cmd_cb(lv_display_t *disp, const uint8_t *cmd, size_t cmd_size, const uint8_t *param, size_t param_size); + static void lcd_send_color_cb(lv_display_t *disp, const uint8_t *cmd, size_t cmd_size, uint8_t *param, size_t param_size); + + LVGL_ST7789_Driver *driver; +}; + +#endif diff --git a/include/graphics/driver/DisplayDeviceDriver.h b/include/graphics/driver/DisplayDeviceDriver.h new file mode 100644 index 00000000..5b796de1 --- /dev/null +++ b/include/graphics/driver/DisplayDeviceDriver.h @@ -0,0 +1,30 @@ +#pragma once + +#include "stdint.h" + +/** + * Base class for all implemented display device drivers + */ +class DisplayDeviceDriver +{ + public: + DisplayDeviceDriver(){}; + virtual void init(void) {} + virtual bool hasTouch(void) { return false; } + virtual bool hasButton(void) { return false; } + virtual bool hasLight(void) { return false; } + virtual bool isPowersaving(void) { return false; } + // virtual void task_handler(void) {}; + + virtual uint8_t getBrightness(void) const { return 128; } + virtual void setBrightness(uint8_t brightness) {} + + virtual uint16_t getScreenTimeout() const { return 0; } + virtual void setScreenTimeout(uint16_t timeout) {} + + virtual ~DisplayDeviceDriver() = default; + + private: + DisplayDeviceDriver(const DisplayDeviceDriver &) = delete; + DisplayDeviceDriver &operator=(const DisplayDeviceDriver &) = delete; +}; \ No newline at end of file diff --git a/include/graphics/driver/DisplayDriverConfig.h b/include/graphics/driver/DisplayDriverConfig.h index 05748920..1b64f7f0 100644 --- a/include/graphics/driver/DisplayDriverConfig.h +++ b/include/graphics/driver/DisplayDriverConfig.h @@ -21,6 +21,7 @@ class DisplayDriverConfig CUSTOM_OLED, CUSTOM_EINK, X11, + SDL2, THMI, TDECK, INDICATOR, @@ -163,6 +164,7 @@ class DisplayDriverConfig private: friend class DisplayDriverFactory; friend class LGFXConfig; + friend class LVGLConfig; enum device_t _device; panel_config_t _panel; diff --git a/include/graphics/driver/EINKDriver.h b/include/graphics/driver/EINKDriver.h new file mode 100644 index 00000000..b820a2de --- /dev/null +++ b/include/graphics/driver/EINKDriver.h @@ -0,0 +1,23 @@ +#pragma once + +#include "graphics/driver/DisplayDriver.h" + +template class EINKDriver : public DisplayDriver +{ + public: + EINKDriver(EINK *eink, uint16_t width, uint16_t height); + void init(DeviceGUI *gui) override; + + protected: + EINK *einkDriver; +}; + +template +EINKDriver::EINKDriver(EINK *eink, uint16_t width, uint16_t height) : DisplayDriver(width, height), einkDriver(eink) +{ +} + +template void EINKDriver::init(DeviceGUI *gui) +{ + DisplayDriver::init(gui); +} diff --git a/include/graphics/driver/TFTDriver.h b/include/graphics/driver/TFTDriver.h index 56b06446..8a22c64a 100644 --- a/include/graphics/driver/TFTDriver.h +++ b/include/graphics/driver/TFTDriver.h @@ -2,6 +2,10 @@ #include "graphics/driver/DisplayDriver.h" +#ifdef ARCH_PORTDUINO +#include "Common.h" // millis() +#endif + template class TFTDriver : public DisplayDriver { public: diff --git a/include/lv_conf.h b/include/lv_conf.h index cf9788bb..bbb3044a 100644 --- a/include/lv_conf.h +++ b/include/lv_conf.h @@ -1091,10 +1091,18 @@ #endif /*Drivers for LCD devices connected via SPI/parallel port*/ +#ifndef LV_USE_ST7735 #define LV_USE_ST7735 0 +#endif +#ifndef LV_USE_ST7789 #define LV_USE_ST7789 0 +#endif +#ifndef LV_USE_ST7796 #define LV_USE_ST7796 0 +#endif +#ifndef LV_USE_ILI9341 #define LV_USE_ILI9341 0 +#endif #define LV_USE_GENERIC_MIPI (LV_USE_ST7735 | LV_USE_ST7789 | LV_USE_ST7796 | LV_USE_ILI9341) diff --git a/source/graphics/LVGL/LVGL_T_DECK.cpp b/source/graphics/LVGL/LVGL_T_DECK.cpp new file mode 100644 index 00000000..100112a7 --- /dev/null +++ b/source/graphics/LVGL/LVGL_T_DECK.cpp @@ -0,0 +1,50 @@ +#if defined(LVGL_DRIVER) + +#include "graphics/LVGL/LVGL_T_DECK.h" +#include "drivers/display/st7789/lv_st7789.h" +#include "graphics/LVGL/LVGL_ST7789_Driver.h" + +LVGL_TDECK::LVGL_TDECK(void) : LVGLDriver(screenWidth, screenHeight), driver(nullptr) {} + +/** + * Create an LCD display with ST7789 driver + * @param hor_res horizontal resolution + * @param ver_res vertical resolution + * @param flags default configuration settings (mirror, RGB ordering, etc.) + * @param send_cmd platform-dependent function to send a command to the LCD controller (usually uses polling transfer) + * @param send_color platform-dependent function to send pixel data to the LCD controller (usually uses DMA transfer: must + * implement a 'ready' callback) + * @return pointer to the created display + */ + +void LVGL_TDECK::init(void) +{ + ILOG_DEBUG("LVGL_TDECK::init...\n"); + driver = new LVGL_ST7789_Driver(); +} + +/** + * Send short command to the LCD. + * This function shall wait until the transaction finishes. + * + */ +void LVGL_TDECK::lcd_send_cmd_cb(lv_display_t *disp, const uint8_t *cmd, size_t cmd_size, const uint8_t *param, size_t param_size) +{ +} + +/** + * Send large array of pixel data to the LCD. If necessary, this function has to do the byte-swapping. + * This function can do the transfer in the background. + * + */ +void LVGL_TDECK::lcd_send_color_cb(lv_display_t *disp, const uint8_t *cmd, size_t cmd_size, uint8_t *param, size_t param_size) {} + +/** + * create lvgl display for T-Deck + */ +lv_display_t *LVGL_TDECK::create(uint32_t hor_res, uint32_t ver_res) +{ + return lv_st7789_create(hor_res, ver_res, LV_LCD_FLAG_NONE, lcd_send_cmd_cb, lcd_send_color_cb); +} + +#endif \ No newline at end of file diff --git a/source/graphics/driver/DisplayDriverFactory.cpp b/source/graphics/driver/DisplayDriverFactory.cpp index f511b53d..6e946961 100644 --- a/source/graphics/driver/DisplayDriverFactory.cpp +++ b/source/graphics/driver/DisplayDriverFactory.cpp @@ -1,87 +1,69 @@ #include "graphics/driver/DisplayDriverFactory.h" -#include "graphics/LGFX/LGFXConfig.h" -#include + #if defined(LGFX_DRIVER) || defined(ARCH_PORTDUINO) -#include "graphics/driver/LGFXDriver.h" +#include "graphics/LGFX/LGFXConfig.h" +#include "graphics/LGFX/LGFXDriver.h" #endif + +#if defined(LVGL_DRIVER) || defined(ARCH_PORTDUINO) +#include "graphics/LVGL/LVGLConfig.h" +#include "graphics/LVGL/LVGLDriver.h" +#endif + #if defined(OLED_DRIVER) || defined(ARCH_PORTDUINO) #include "graphics/driver/OLEDDriver.h" #endif + #if defined(EINK_DRIVER) || defined(ARCH_PORTDUINO) -// TODO #include "graphics/driver/EINKDriver.h" +#include "graphics/driver/EINKDriver.h" #endif + #if defined(USE_X11) #include "graphics/driver/X11Driver.h" #endif -#ifndef ARCH_PORTDUINO -#ifdef LGFX_DRIVER_TEMPLATE -#include "graphics/LGFX/LGFX_GENERIC.h" -#endif -#ifdef T_HMI -#include "graphics/LGFX/LGFX_T_HMI.h" -#endif -#ifdef SENSECAP_INDICATOR -#include "graphics/LGFX/LGFX_INDICATOR.h" -#endif -#ifdef ESP_4848S040 -#include "graphics/LGFX/LGFX_4848S040.h" -#endif -#ifdef MAKERFABS_480X480 -#include "graphics/LGFX/LGFX_MAKERFABS480X480.h" -#endif -#ifdef T_DECK -#include "graphics/LGFX/LGFX_T_DECK.h" -#endif -#ifdef PICOMPUTER_S3 -#include "graphics/LGFX/LGFX_PICOMPUTER_S3.h" -#endif -#ifdef T_WATCH_S3 -#include "graphics/LGFX/LGFX_T_WATCH_S3.h" -#endif -#ifdef UNPHONE -#include "graphics/LGFX/LGFX_UNPHONE.h" -#endif -#ifdef ESP32_2432S022 -#include "graphics/LGFX/LGFX_ESP2432S022.h" -#endif -#ifdef ESP32_2432S028RV1 -#include "graphics/LGFX/LGFX_ESP2432S028RV1.h" -#endif -#ifdef ESP32_2432S028RV2 -#include "graphics/LGFX/LGFX_ESP2432S028RV2.h" -#endif -#ifdef WT32_SC01 -#include "graphics/LGFX/LGFX_WT_SC01PLUS.h" -#endif -#ifdef HELTEC_TRACKER -#include "graphics/LGFX/LGFX_HELTEC_TRACKER.h" -#endif -#ifdef NODEMCU_32S -#include "graphics/LGFX/LGFX_ESPILI9341XPT2046.h" +#if defined(USE_SDL2) +#include "graphics/driver/SDL2Driver.h" #endif + +#if defined(GFX_DRIVER_INC) +#include GFX_DRIVER_INC #endif +#include + DisplayDriverFactory::DisplayDriverFactory() {} +/** + * ctor for compiled-in display driver + */ DisplayDriver *DisplayDriverFactory::create(uint16_t width, uint16_t height) { #if defined(USE_X11) return &X11Driver::create(width, height); +#elif defined(USE_SDL2) + return &SDL2Driver::create(width, height); #elif defined(LGFX_DRIVER) return new LGFXDriver(width, height); +#elif defined(LVGL_DRIVER) + return new LVGL_DRIVER(); #endif ILOG_CRIT("DisplayDriverFactory: missing or wrong configuration"); assert(false); return nullptr; } +/** + * ctor for run-time configurable display driver + */ DisplayDriver *DisplayDriverFactory::create(const DisplayDriverConfig &cfg) { -#if defined(LGFXConfig) || defined(ARCH_PORTDUINO) +#if defined(ARCH_PORTDUINO) if (cfg._device == DisplayDriverConfig::device_t::CUSTOM_TFT) { - // for now assume LGFX driver, but could be also TFT_eSPI if implemented - return new LGFXDriver(cfg); + if (strcasecmp(cfg._panel.type, "ST7789") == 0) + return new LVGLConfig(cfg); + else + return new LGFXDriver(cfg); } #endif #if defined(OLEDConfig) || defined(ARCH_PORTDUINO) @@ -99,69 +81,18 @@ DisplayDriver *DisplayDriverFactory::create(const DisplayDriverConfig &cfg) return &X11Driver::create(cfg.width(), cfg.height()); } #endif - switch (cfg._device) { -#ifndef ARCH_PORTDUINO -#if !defined(LGFX_DRIVER) -#error "LGFX_DRIVER must be defined!" +#if defined(USE_SDL2) + if (cfg._device == DisplayDriverConfig::device_t::SDL2) { + return &SDL2Driver::create(cfg.width(), cfg.height()); + } #endif -#if defined(T_HMI) - case DisplayDriverConfig::device_t::THMI: - return new LGFXDriver(cfg.width(), cfg.height()); - break; -#elif defined(T_DECK) - case DisplayDriverConfig::device_t::TDECK: - return new LGFXDriver(cfg.width(), cfg.height()); - break; -#elif defined(SENSECAP_INDICATOR) - case DisplayDriverConfig::device_t::INDICATOR: - return new LGFXDriver(cfg.width(), cfg.height()); - break; -#elif defined(ESP_4848S040) - case DisplayDriverConfig::device_t::ESP4848S040: - return new LGFXDriver(cfg.width(), cfg.height()); - break; -#elif defined(MAKERFABS_480X480) - case DisplayDriverConfig::device_t::MAKERFABS480X480: - return new LGFXDriver(cfg.width(), cfg.height()); - break; -#elif defined(PICOMPUTER_S3) - case DisplayDriverConfig::device_t::BPICOMPUTER_S3: - return new LGFXDriver(cfg.width(), cfg.height()); - break; -#elif defined(TWATCH_S3) - case DisplayDriverConfig::device_t::TWATCH_S3: - return new LGFXDriver(cfg.width(), cfg.height()); - break; -#elif defined(UNPHONE) - case DisplayDriverConfig::device_t::UNPHONE_V9: - return new LGFXDriver(cfg.width(), cfg.height()); - break; -#elif defined(HELTEC_TRACKER) - case DisplayDriverConfig::device_t::HELTEC_TRACKER: - // return new LGFXDriver(cfg.width(), cfg.height()); - break; -#elif defined(WT_SC01_PLUS) - case DisplayDriverConfig::device_t::WT32_SC01_PLUS: - return new LGFXDriver(cfg.width(), cfg.height()); - break; -#elif defined(ESP2432S028RV1) - case DisplayDriverConfig::device_t::ESP2432S028RV1: - return new LGFXDriver(cfg.width(), cfg.height()); - break; -#elif defined(ESP2432S028RV2) - case DisplayDriverConfig::device_t::ESP2432S028RV2: - return new LGFXDriver(cfg.width(), cfg.height()); - break; + +#if !defined(ARCH_PORTDUINO) +#if defined(LGFX_DRIVER) + return new LGFXDriver(cfg.width(), cfg.height()); +#elif defined(LVGL_DRIVER) + return new LVGL_DRIVER(cfg); #endif -#elif defined(USE_X11) - case DisplayDriverConfig::device_t::X11: - return &X11Driver::create(cfg.width(), cfg.height()); - break; #endif - default: - ILOG_CRIT("LGFX device_t config not implemented: %d", cfg._device); - assert(false); - break; - } return nullptr; } From c2a165be5eb04829e93dd848be962450d0edc961 Mon Sep 17 00:00:00 2001 From: mverch67 Date: Sun, 26 Jan 2025 16:38:38 +0100 Subject: [PATCH 2/4] lvgl driver class structures completed --- include/graphics/LVGL/LVGLConfig.h | 196 ++---------------- include/graphics/LVGL/LVGLDriver.h | 13 +- include/graphics/LVGL/LVGL_ST7789_Driver.h | 10 +- include/graphics/LVGL/LVGL_T_DECK.h | 16 +- include/graphics/driver/DisplayDeviceDriver.h | 13 +- include/graphics/driver/DisplayDriverConfig.h | 3 + source/graphics/LVGL/LVGLConfig.cpp | 75 +++++++ source/graphics/LVGL/LVGL_ST7789_Driver.cpp | 50 +++++ source/graphics/LVGL/LVGL_T_DECK.cpp | 40 +--- .../graphics/driver/DisplayDriverFactory.cpp | 9 +- 10 files changed, 187 insertions(+), 238 deletions(-) create mode 100644 source/graphics/LVGL/LVGLConfig.cpp create mode 100644 source/graphics/LVGL/LVGL_ST7789_Driver.cpp diff --git a/include/graphics/LVGL/LVGLConfig.h b/include/graphics/LVGL/LVGLConfig.h index 85e637ae..601f5188 100644 --- a/include/graphics/LVGL/LVGLConfig.h +++ b/include/graphics/LVGL/LVGLConfig.h @@ -1,7 +1,5 @@ #pragma once -#ifdef LVGL_DRIVER - #include "graphics/LVGL/LVGLDriver.h" #include "graphics/LVGL/LVGL_ST7789_Driver.h" #include "graphics/driver/DisplayDriverConfig.h" @@ -14,197 +12,29 @@ class DisplayDeviceDriver; * @brief Runtime configuration class for lvgl driver * */ -class LVGLConfig : public LVGLDriver +class LVGLConfig { public: uint16_t screenWidth = 0; uint16_t screenHeight = 0; - void init(void) {} - bool hasButton(void) { return false; } - bool light(void) { return true; } - - LVGLConfig(void) : LVGLDriver(0, 0) {} - - LVGLConfig(const DisplayDriverConfig &config) : LVGLDriver(config._width, config._height) - { - ILOG_DEBUG("LVGLConfig ...\n"); - { // configure panel settings - if (strcasecmp(config._panel.type, "ST7789") == 0) { - lvglDeviceDriver = new LVGL_ST7789_Driver(config); - // lvglDeviceDriver = new LVGLDriver(config); - // TODO: allocate touch driver - } else { - ILOG_ERROR("LVGL device panel support not yet implemented for '%s'\n", config._panel.type); - return; - } - } -#if 0 - auto cfg = lvglDriver->config(); - - if (config._panel.rotation) { - cfg.panel_width = config._height; - cfg.panel_height = config._width; - } else { - cfg.panel_width = config._width; - cfg.panel_height = config._height; - } - screenWidth = cfg.panel_width; - screenHeight = cfg.panel_height; - - cfg.pin_cs = config._panel.pin_cs; - cfg.pin_rst = config._panel.pin_rst; - cfg.pin_busy = config._panel.pin_busy; - cfg.offset_x = config._panel.offset_x; - cfg.offset_y = config._panel.offset_y; - cfg.offset_rotation = config._panel.offset_rotation; - cfg.invert = config._panel.invert; - cfg.dummy_read_pixel = config._panel.dummy_read_pixel; - cfg.dummy_read_bits = config._panel.dummy_read_bits; - cfg.readable = config._panel.readable; - cfg.invert = config._panel.invert; - cfg.rgb_order = config._panel.rgb_order; - cfg.dlen_16bit = config._panel.dlen_16bit; - cfg.bus_shared = config._panel.bus_shared; - - ILOG_DEBUG("Panel_Device(%s): %dx%d, cs=%d, rst=%d, busy=%d\n", config._panel.type, screenWidth, screenHeight, - cfg.pin_cs, cfg.pin_rst, cfg.pin_busy); - _panel_instance->config(cfg); - } - - { // configure bus settings -#ifndef ARCH_PORTDUINO - if (config._bus.parallel.pin_d0 > 0) { - lgfx::Bus_Parallel8 *bus = new lgfx::Bus_Parallel8; - auto cfg = bus->config(); - cfg.freq_write = config._bus.freq_write; -#if CONFIG_IDF_TARGET_ESP32S3 - cfg.freq_read = config._bus.freq_read; -#endif - for (int i = 0; i < 8; i++) - cfg.pin_data[i] = config._bus.parallel.pin_data[i]; - cfg.pin_rd = config._bus.parallel.pin_rd; - cfg.pin_wr = config._bus.parallel.pin_wr; - cfg.pin_rs = config._bus.parallel.pin_rs; - bus->config(cfg); - _bus_instance = bus; - _panel_instance->setBus(_bus_instance); - } else -#endif - { - lgfx::Bus_SPI *bus = new lgfx::Bus_SPI; - auto cfg = bus->config(); - cfg.freq_write = config._bus.freq_write; - cfg.freq_read = config._bus.freq_read; - cfg.pin_sclk = config._bus.spi.pin_sclk; - cfg.pin_miso = config._bus.spi.pin_miso; - cfg.pin_mosi = config._bus.spi.pin_mosi; - cfg.pin_dc = config._bus.spi.pin_dc; - cfg.spi_mode = config._bus.spi.spi_mode; -#ifdef ARDUINO_ARCH_ESP32 - cfg.spi_host = (spi_host_device_t)config._bus.spi.spi_host; -#else - cfg.spi_host = config._bus.spi.spi_host; -#endif - ILOG_DEBUG("Bus_SPI: freq=%d, host=%02x, dc=%d\n", cfg.freq_write, cfg.spi_host, cfg.pin_dc); - bus->config(cfg); - _bus_instance = bus; - _panel_instance->setBus(_bus_instance); - } - } - - { // Configure settings for touch control. - if (config._touch.type && strcasecmp(config._touch.type, "NOTOUCH") != 0) { - if (strcasecmp(config._touch.type, "XPT2046") == 0) { - _touch_instance = new lgfx::Touch_XPT2046; - } else if (strcasecmp(config._touch.type, "GT911") == 0) { - _touch_instance = new lgfx::Touch_GT911; - } else if (strcasecmp(config._touch.type, "FT5x06") == 0 || strcasecmp(config._touch.type, "FT5206") == 0 || - strcasecmp(config._touch.type, "FT5306") == 0 || strcasecmp(config._touch.type, "FT5406") == 0 || - strcasecmp(config._touch.type, "FT6206") == 0 || strcasecmp(config._touch.type, "FT6236") == 0 || - strcasecmp(config._touch.type, "FT6336") == 0 || strcasecmp(config._touch.type, "FT6436") == 0) { - _touch_instance = new lgfx::Touch_FT5x06; - } else if (strcasecmp(config._touch.type, "STMPE610") == 0) { - _touch_instance = new lgfx::Touch_STMPE610; - } else { - ILOG_ERROR("Touch panel '%s' support not implemented\n", config._touch.type); - return; - } + LVGLConfig(void); + LVGLConfig(const DisplayDriverConfig &cfg); + void init(void); + lv_display_t *create(uint32_t hor_res, uint32_t ver_res); + void touchpad_read(lv_indev_t *indev_driver, lv_indev_data_t *data); - auto cfg = _touch_instance->config(); + bool hasButton(void); + bool hasTouch(void); + bool light(void); - cfg.freq = config._touch.freq; - if (config._touch.x_min >= 0) - cfg.x_min = config._touch.x_min; - if (config._touch.x_max >= 0) - cfg.x_max = config._touch.x_max; - if (config._touch.y_min >= 0) - cfg.y_min = config._touch.y_min; - if (config._touch.y_max >= 0) - cfg.y_max = config._touch.y_max; - cfg.pin_int = config._touch.pin_int; - cfg.pin_rst = config._touch.pin_rst; - cfg.bus_shared = config._touch.bus_shared; - cfg.offset_rotation = config._touch.offset_rotation; - cfg.pin_cs = config._touch.pin_cs; + uint8_t getBrightness(void); + void setBrightness(uint8_t setBrightness); - if (config._touch.i2c.i2c_addr > 0 && cfg.pin_cs == -1) { - cfg.i2c_port = config._touch.i2c.i2c_port; - cfg.pin_scl = config._touch.i2c.pin_scl; - cfg.pin_sda = config._touch.i2c.pin_sda; - cfg.i2c_addr = config._touch.i2c.i2c_addr; - ILOG_DEBUG("Touch_I2C: freq=%d, port=%02x, addr=%d, cs=%d, int=%d, rst=%d\n", cfg.freq, cfg.i2c_port, - cfg.i2c_addr, cfg.pin_cs, cfg.pin_int, cfg.pin_rst); - } else { - cfg.spi_host = config._touch.spi.spi_host; - cfg.pin_sclk = config._touch.spi.pin_sclk; - cfg.pin_mosi = config._touch.spi.pin_mosi; - cfg.pin_miso = config._touch.spi.pin_miso; - ILOG_DEBUG("Touch_SPI: freq=%d, host=%02x, cs=%d, int=%d, rst=%d\n", cfg.freq, cfg.spi_host, cfg.pin_cs, - cfg.pin_int, cfg.pin_rst); - } - - _touch_instance->config(cfg); - _panel_instance->setTouch(_touch_instance); - } - } - - { // configure TFT backlight - if (config._light.pin_bl != -1) { -#ifdef ARCH_PORTDUINO - auto light = new portduino::Light_PWM; -#else - auto light = new lgfx::Light_PWM; -#endif - auto cfg = light->config(); - - cfg.freq = config._light.freq; - cfg.pin_bl = config._light.pin_bl; - if (config._light.pwm_channel >= 0) - cfg.pwm_channel = config._light.pwm_channel; - cfg.invert = config._light.invert; - - ILOG_DEBUG("Light_PWM: freq=%d, pwm=%d, bl=%d\n", cfg.freq, cfg.pwm_channel, cfg.pin_bl); - light->config(cfg); - _panel_instance->setLight(light); - _light_instance = light; - } - } - - setPanel(_panel_instance); -#endif - } - - ~LVGLConfig() { delete lvglDeviceDriver; } + ~LVGLConfig(); protected: - lv_display_t *create(uint32_t hor_res, uint32_t ver_res) override - { - return nullptr; // TODO - } - private: + const DisplayDriverConfig *config; DisplayDeviceDriver *lvglDeviceDriver; }; - -#endif \ No newline at end of file diff --git a/include/graphics/LVGL/LVGLDriver.h b/include/graphics/LVGL/LVGLDriver.h index c5982b88..cdf55993 100644 --- a/include/graphics/LVGL/LVGLDriver.h +++ b/include/graphics/LVGL/LVGLDriver.h @@ -36,9 +36,10 @@ template class LVGLDriver : public TFTDriver protected: void init_lvgl(void); - virtual lv_display_t *create(uint32_t hor_res, uint32_t ver_res) = 0; - static void touchpad_read(lv_indev_t *indev_driver, lv_indev_data_t *data) {} // TODO - // static uint32_t my_tick_get_cb(void) { return millis(); } + static void touchpad_read(lv_indev_t *indev_driver, lv_indev_data_t *data) + { + return lvgldriver->touchpad_read(indev_driver, data); + } uint32_t screenTimeout; uint32_t lastBrightness; @@ -71,13 +72,13 @@ LVGLDriver::LVGLDriver(const DisplayDriverConfig &cfg) template void LVGLDriver::init(DeviceGUI *gui) { - ILOG_DEBUG("LVGLDriver::init...\n"); + ILOG_DEBUG("LVGLDriver::init..."); init_lvgl(); TFTDriver::init(gui); // LVGL: setup display device driver - ILOG_DEBUG("LVGL display driver create...\n"); - display = create(DisplayDriver::screenWidth, DisplayDriver::screenHeight); + ILOG_DEBUG("LVGL display driver create..."); + display = lvgldriver->create(DisplayDriver::screenWidth, DisplayDriver::screenHeight); std::pair draw_buffers = {nullptr, nullptr}; const auto buffer_size = diff --git a/include/graphics/LVGL/LVGL_ST7789_Driver.h b/include/graphics/LVGL/LVGL_ST7789_Driver.h index 64d3c15c..dded12a9 100644 --- a/include/graphics/LVGL/LVGL_ST7789_Driver.h +++ b/include/graphics/LVGL/LVGL_ST7789_Driver.h @@ -9,11 +9,17 @@ class LVGL_ST7789_Driver : public DisplayDeviceDriver { public: - LVGL_ST7789_Driver() {} - LVGL_ST7789_Driver(const DisplayDriverConfig &) : DisplayDeviceDriver() {} + LVGL_ST7789_Driver(uint16_t width, uint16_t height); + void init(int16_t spiBus, int16_t sclk, int16_t mosi, int16_t miso, int16_t dc, int16_t rst, int16_t cs); + lv_display_t *create(uint32_t hor_res, uint32_t ver_res); protected: private: + LVGL_ST7789_Driver(const LVGL_ST7789_Driver &) = delete; + LVGL_ST7789_Driver &operator=(const LVGL_ST7789_Driver &) = delete; + + static void lcd_send_cmd_cb(lv_display_t *disp, const uint8_t *cmd, size_t cmd_size, const uint8_t *param, size_t param_size); + static void lcd_send_color_cb(lv_display_t *disp, const uint8_t *cmd, size_t cmd_size, uint8_t *param, size_t param_size); }; #endif \ No newline at end of file diff --git a/include/graphics/LVGL/LVGL_T_DECK.h b/include/graphics/LVGL/LVGL_T_DECK.h index 7b7779e2..ceef52f4 100644 --- a/include/graphics/LVGL/LVGL_T_DECK.h +++ b/include/graphics/LVGL/LVGL_T_DECK.h @@ -8,27 +8,27 @@ class LVGL_ST7789_Driver; -class LVGL_TDECK : public LVGLDriver +class LVGL_TDECK //: public LVGLDriver { public: + static constexpr uint16_t screenWidth = 320; + static constexpr uint16_t screenHeight = 240; + LVGL_TDECK(void); LVGL_TDECK(const DisplayDriverConfig &cfg); void init(void); bool hasButton(void) { return true; } + bool hasTouch(void) { return true; } bool light(void) { return true; } uint8_t getBrightness(void) { return 128; } + void setBrightness(uint8_t setBrightness) {} - static constexpr uint16_t screenWidth = 320; - static constexpr uint16_t screenHeight = 240; + lv_display_t *create(uint32_t hor_res, uint32_t ver_res); + void touchpad_read(lv_indev_t *indev_driver, lv_indev_data_t *data); protected: - lv_display_t *create(uint32_t hor_res, uint32_t ver_res) override; - private: - static void lcd_send_cmd_cb(lv_display_t *disp, const uint8_t *cmd, size_t cmd_size, const uint8_t *param, size_t param_size); - static void lcd_send_color_cb(lv_display_t *disp, const uint8_t *cmd, size_t cmd_size, uint8_t *param, size_t param_size); - LVGL_ST7789_Driver *driver; }; diff --git a/include/graphics/driver/DisplayDeviceDriver.h b/include/graphics/driver/DisplayDeviceDriver.h index 5b796de1..47458b51 100644 --- a/include/graphics/driver/DisplayDeviceDriver.h +++ b/include/graphics/driver/DisplayDeviceDriver.h @@ -8,13 +8,10 @@ class DisplayDeviceDriver { public: - DisplayDeviceDriver(){}; + DisplayDeviceDriver(uint16_t width, uint16_t height) : screenWidth(width), screenHeight(height){}; + virtual void init(void) {} - virtual bool hasTouch(void) { return false; } - virtual bool hasButton(void) { return false; } - virtual bool hasLight(void) { return false; } - virtual bool isPowersaving(void) { return false; } - // virtual void task_handler(void) {}; + virtual lv_display_t *create(uint32_t hor_res, uint32_t ver_res) = 0; virtual uint8_t getBrightness(void) const { return 128; } virtual void setBrightness(uint8_t brightness) {} @@ -24,6 +21,10 @@ class DisplayDeviceDriver virtual ~DisplayDeviceDriver() = default; + protected: + const uint16_t screenWidth; + const uint16_t screenHeight; + private: DisplayDeviceDriver(const DisplayDeviceDriver &) = delete; DisplayDeviceDriver &operator=(const DisplayDeviceDriver &) = delete; diff --git a/include/graphics/driver/DisplayDriverConfig.h b/include/graphics/driver/DisplayDriverConfig.h index 1b64f7f0..f69bff0e 100644 --- a/include/graphics/driver/DisplayDriverConfig.h +++ b/include/graphics/driver/DisplayDriverConfig.h @@ -15,6 +15,8 @@ class DisplayDriver; class DisplayDriverConfig { public: + enum struct driver_t { LGFX, LVGL, ADAFRUIT, OTHER }; + enum struct device_t { NONE, CUSTOM_TFT, @@ -38,6 +40,7 @@ class DisplayDriverConfig struct panel_config_t { char *type = nullptr; + driver_t driver = driver_t::LGFX; uint16_t panel_width = 0; uint16_t panel_height = 0; bool rotation = false; diff --git a/source/graphics/LVGL/LVGLConfig.cpp b/source/graphics/LVGL/LVGLConfig.cpp new file mode 100644 index 00000000..a77964c7 --- /dev/null +++ b/source/graphics/LVGL/LVGLConfig.cpp @@ -0,0 +1,75 @@ +#ifdef LVGL_DRIVER + +#include "graphics/LVGL/LVGLConfig.h" +#include "util/ILog.h" +#include + +LVGLConfig::LVGLConfig(void) : config(nullptr) +{ + ILOG_ERROR("ctor called without config"); + assert(0); +} + +LVGLConfig::LVGLConfig(const DisplayDriverConfig &cfg) : config(&cfg) +{ + ILOG_DEBUG("LVGLConfig ..."); +} + +void LVGLConfig::init() +{ + ILOG_DEBUG("LVGLConfig::init() ..."); + if (strcasecmp(config->_panel.type, "ST7789") == 0) { + lvglDeviceDriver = new LVGL_ST7789_Driver(config->_width, config->_height); + } else { + ILOG_CRIT("LVGL device panel support not yet implemented for '%s'", config->_panel.type); + return; + } + + // TODO: allocate touch driver + if (config->_touch.type && strcasecmp(config->_touch.type, "NOTOUCH") != 0) { + ILOG_ERROR("LVGLConfig: touch not yet implemented!"); + } +} + +lv_display_t *LVGLConfig::create(uint32_t hor_res, uint32_t ver_res) +{ + ILOG_DEBUG("LVGLConfig::create() ..."); + return lvglDeviceDriver->create(hor_res, ver_res); +} + +void LVGLConfig::touchpad_read(lv_indev_t *indev_driver, lv_indev_data_t *data) +{ + ILOG_DEBUG("LVGLConfig::touchpad_read()"); +} + +bool LVGLConfig::hasButton(void) +{ + return false; // TODO +} + +bool LVGLConfig::hasTouch(void) +{ + return true; // TODO +} + +bool LVGLConfig::light(void) +{ + return false; // TODO +} + +uint8_t LVGLConfig::getBrightness(void) +{ + return 128; // TODO +} + +void LVGLConfig::setBrightness(uint8_t setBrightness) +{ + // TODO +} + +LVGLConfig::~LVGLConfig() +{ + delete lvglDeviceDriver; +} + +#endif \ No newline at end of file diff --git a/source/graphics/LVGL/LVGL_ST7789_Driver.cpp b/source/graphics/LVGL/LVGL_ST7789_Driver.cpp new file mode 100644 index 00000000..e63aa43d --- /dev/null +++ b/source/graphics/LVGL/LVGL_ST7789_Driver.cpp @@ -0,0 +1,50 @@ +#include "graphics/LVGL/LVGL_ST7789_Driver.h" +#include "util/ILog.h" + +LVGL_ST7789_Driver::LVGL_ST7789_Driver(uint16_t width, uint16_t height) : DisplayDeviceDriver(width, height) +{ + ILOG_DEBUG("LVGL_ST7789_Driver()..."); +} + +void LVGL_ST7789_Driver::init(int16_t spiBus, int16_t sclk, int16_t mosi, int16_t miso, int16_t dc, int16_t rst, int16_t cs) +{ + ILOG_DEBUG("LVGL_ST7789_Driver::init()..."); +} + +/** + * Create an LCD display with ST7789 driver + * @param hor_res horizontal resolution + * @param ver_res vertical resolution + * @param flags default configuration settings (mirror, RGB ordering, etc.) + * @param send_cmd platform-dependent function to send a command to the LCD controller (usually uses polling transfer) + * @param send_color platform-dependent function to send pixel data to the LCD controller (usually uses DMA transfer: must + * implement a 'ready' callback) + * @return pointer to the created display + */ +lv_display_t *LVGL_ST7789_Driver::create(uint32_t hor_res, uint32_t ver_res) +{ + ILOG_DEBUG("lv_st7789_create..."); + lv_display_t *display = lv_st7789_create(hor_res, ver_res, LV_LCD_FLAG_NONE, lcd_send_cmd_cb, lcd_send_color_cb); + lv_display_set_color_format(display, LV_COLOR_FORMAT_RGB565); + return display; +} + +/** + * Send short command to the LCD. + * This function shall wait until the transaction finishes. + * + */ +void LVGL_ST7789_Driver::lcd_send_cmd_cb(lv_display_t *disp, const uint8_t *cmd, size_t cmd_size, const uint8_t *param, + size_t param_size) +{ +} + +/** + * Send large array of pixel data to the LCD. If necessary, this function has to do the byte-swapping. + * This function can do the transfer in the background. + * + */ +void LVGL_ST7789_Driver::lcd_send_color_cb(lv_display_t *disp, const uint8_t *cmd, size_t cmd_size, uint8_t *param, + size_t param_size) +{ +} diff --git a/source/graphics/LVGL/LVGL_T_DECK.cpp b/source/graphics/LVGL/LVGL_T_DECK.cpp index 100112a7..ce1788f5 100644 --- a/source/graphics/LVGL/LVGL_T_DECK.cpp +++ b/source/graphics/LVGL/LVGL_T_DECK.cpp @@ -1,50 +1,32 @@ -#if defined(LVGL_DRIVER) +#if defined(T_DECK) && defined(LVGL_DRIVER) #include "graphics/LVGL/LVGL_T_DECK.h" #include "drivers/display/st7789/lv_st7789.h" #include "graphics/LVGL/LVGL_ST7789_Driver.h" +#include "hal/spi_types.h" -LVGL_TDECK::LVGL_TDECK(void) : LVGLDriver(screenWidth, screenHeight), driver(nullptr) {} - -/** - * Create an LCD display with ST7789 driver - * @param hor_res horizontal resolution - * @param ver_res vertical resolution - * @param flags default configuration settings (mirror, RGB ordering, etc.) - * @param send_cmd platform-dependent function to send a command to the LCD controller (usually uses polling transfer) - * @param send_color platform-dependent function to send pixel data to the LCD controller (usually uses DMA transfer: must - * implement a 'ready' callback) - * @return pointer to the created display - */ +LVGL_TDECK::LVGL_TDECK(void) : driver(nullptr) +{ + driver = new LVGL_ST7789_Driver(screenWidth, screenHeight); +} void LVGL_TDECK::init(void) { - ILOG_DEBUG("LVGL_TDECK::init...\n"); - driver = new LVGL_ST7789_Driver(); + ILOG_DEBUG("LVGL_TDECK::init..."); + driver->init(SPI2_HOST, 40, 41, 38, 11, -1, 12); } -/** - * Send short command to the LCD. - * This function shall wait until the transaction finishes. - * - */ -void LVGL_TDECK::lcd_send_cmd_cb(lv_display_t *disp, const uint8_t *cmd, size_t cmd_size, const uint8_t *param, size_t param_size) +void LVGL_TDECK::touchpad_read(lv_indev_t *indev_driver, lv_indev_data_t *data) { + ILOG_DEBUG("LVGL_TDECK::touchpad_read()"); } -/** - * Send large array of pixel data to the LCD. If necessary, this function has to do the byte-swapping. - * This function can do the transfer in the background. - * - */ -void LVGL_TDECK::lcd_send_color_cb(lv_display_t *disp, const uint8_t *cmd, size_t cmd_size, uint8_t *param, size_t param_size) {} - /** * create lvgl display for T-Deck */ lv_display_t *LVGL_TDECK::create(uint32_t hor_res, uint32_t ver_res) { - return lv_st7789_create(hor_res, ver_res, LV_LCD_FLAG_NONE, lcd_send_cmd_cb, lcd_send_color_cb); + return driver->create(hor_res, ver_res); } #endif \ No newline at end of file diff --git a/source/graphics/driver/DisplayDriverFactory.cpp b/source/graphics/driver/DisplayDriverFactory.cpp index 6e946961..038c65d0 100644 --- a/source/graphics/driver/DisplayDriverFactory.cpp +++ b/source/graphics/driver/DisplayDriverFactory.cpp @@ -46,7 +46,7 @@ DisplayDriver *DisplayDriverFactory::create(uint16_t width, uint16_t height) #elif defined(LGFX_DRIVER) return new LGFXDriver(width, height); #elif defined(LVGL_DRIVER) - return new LVGL_DRIVER(); + return new LVGLDriver(width, height); #endif ILOG_CRIT("DisplayDriverFactory: missing or wrong configuration"); assert(false); @@ -60,8 +60,8 @@ DisplayDriver *DisplayDriverFactory::create(const DisplayDriverConfig &cfg) { #if defined(ARCH_PORTDUINO) if (cfg._device == DisplayDriverConfig::device_t::CUSTOM_TFT) { - if (strcasecmp(cfg._panel.type, "ST7789") == 0) - return new LVGLConfig(cfg); + if (cfg._panel.driver == DisplayDriverConfig::driver_t::LVGL && strcasecmp(cfg._panel.type, "ST7789") == 0) + return new LVGLDriver(cfg); else return new LGFXDriver(cfg); } @@ -91,8 +91,9 @@ DisplayDriver *DisplayDriverFactory::create(const DisplayDriverConfig &cfg) #if defined(LGFX_DRIVER) return new LGFXDriver(cfg.width(), cfg.height()); #elif defined(LVGL_DRIVER) - return new LVGL_DRIVER(cfg); + return new LVGLDriver(cfg.width(), cfg.height()); #endif #endif + ILOG_CRIT("DisplayDriverFactory: unsupported or missing device type"); return nullptr; } From 85a4ca9054f7d07e29e8e3dd83c302bdea57137a Mon Sep 17 00:00:00 2001 From: mverch67 Date: Sun, 26 Jan 2025 18:27:30 +0100 Subject: [PATCH 3/4] fix compiler error if USE_ST7789 not defined --- source/graphics/LVGL/LVGL_ST7789_Driver.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/source/graphics/LVGL/LVGL_ST7789_Driver.cpp b/source/graphics/LVGL/LVGL_ST7789_Driver.cpp index e63aa43d..48d3b924 100644 --- a/source/graphics/LVGL/LVGL_ST7789_Driver.cpp +++ b/source/graphics/LVGL/LVGL_ST7789_Driver.cpp @@ -1,3 +1,5 @@ +#if defined(LV_USE_ST7789) && LV_USE_ST7789 == 1 + #include "graphics/LVGL/LVGL_ST7789_Driver.h" #include "util/ILog.h" @@ -48,3 +50,5 @@ void LVGL_ST7789_Driver::lcd_send_color_cb(lv_display_t *disp, const uint8_t *cm size_t param_size) { } + +#endif From 5c52c48cac37d6a1608d3ce2c82fd6a0b2a805bf Mon Sep 17 00:00:00 2001 From: mverch67 Date: Mon, 27 Jan 2025 22:20:45 +0100 Subject: [PATCH 4/4] set GPIO capabilities --- include/graphics/LGFX/LGFX_GENERIC.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/include/graphics/LGFX/LGFX_GENERIC.h b/include/graphics/LGFX/LGFX_GENERIC.h index 31d49a85..b09226e7 100644 --- a/include/graphics/LGFX/LGFX_GENERIC.h +++ b/include/graphics/LGFX/LGFX_GENERIC.h @@ -31,6 +31,8 @@ */ #define LGFX_USE_V1 +#include "hal/gpio_types.h" +#include "util/ILog.h" #include #ifndef SPI_FREQUENCY @@ -207,6 +209,20 @@ class LGFX_GENERIC : public lgfx::LGFX_Device bool hasButton(void) { return false; } + bool init_impl(bool use_reset, bool use_clear) override + { + // increase output power to SPI GPIOs to be able to run with higher frequency + if (LGFX_PIN_SCK >= 0) { + gpio_set_direction((gpio_num_t)LGFX_PIN_SCK, GPIO_MODE_OUTPUT); + gpio_set_drive_capability((gpio_num_t)LGFX_PIN_SCK, GPIO_DRIVE_CAP_3); + } + if (LGFX_PIN_MOSI >= 0) { + gpio_set_direction((gpio_num_t)LGFX_PIN_SCK, GPIO_MODE_OUTPUT); + gpio_set_drive_capability((gpio_num_t)LGFX_PIN_MOSI, GPIO_DRIVE_CAP_3); + } + return lgfx::LGFX_Device::init_impl(use_reset, use_clear); + } + LGFX_GENERIC(void) { {