From dffea46d076b70d642b7400a222efb152f6ee5f4 Mon Sep 17 00:00:00 2001 From: fvanroie <15969459+fvanroie@users.noreply.github.com> Date: Fri, 8 Oct 2021 16:05:06 +0200 Subject: [PATCH] Initial LovyanGFX driver #220 --- src/drv/old/hasp_drv_tft_espi.cpp | 4 +- src/drv/tft/tft_driver.h | 7 +- src/drv/tft/tft_driver_lovyangfx.cpp | 335 ++++++++++++++++++++ src/drv/tft/tft_driver_lovyangfx.h | 84 +++++ src/drv/touch/touch_driver.h | 2 +- src/hasp_gui.cpp | 8 +- user_setups/esp32/lolin-d32-pro_ili9341.ini | 1 - 7 files changed, 431 insertions(+), 10 deletions(-) create mode 100644 src/drv/tft/tft_driver_lovyangfx.cpp create mode 100644 src/drv/tft/tft_driver_lovyangfx.h diff --git a/src/drv/old/hasp_drv_tft_espi.cpp b/src/drv/old/hasp_drv_tft_espi.cpp index 61be6796..41cbc633 100644 --- a/src/drv/old/hasp_drv_tft_espi.cpp +++ b/src/drv/old/hasp_drv_tft_espi.cpp @@ -6,7 +6,7 @@ *********************/ #include "hasp_conf.h" -#if defined(TOUCH_CS) +#if defined(TOUCH_CS) && defined(USER_SETUP_LAODED) #include "dev/device.h" #include "drv/tft/tft_driver.h" @@ -34,7 +34,7 @@ void tft_espi_calibrate(uint16_t* calData) void tft_espi_set_touch(uint16_t* calData) { - haspTft.tft.setTouch(calData); + haspTft.tft.setTouch(calData); } bool tft_espi_get_touch(int16_t* touchX, int16_t* touchY, uint16_t threshold) diff --git a/src/drv/tft/tft_driver.h b/src/drv/tft/tft_driver.h index 9a29d188..6e2ab140 100644 --- a/src/drv/tft/tft_driver.h +++ b/src/drv/tft/tft_driver.h @@ -36,9 +36,12 @@ class BaseTft { } // namespace dev -#if defined(ESP32) -// #warning Building for ESP32 Tfts +#if defined(ESP32) && defined(USER_SETUP_LOADED) +// #warning Building for ESP32 TFT_eSPI #include "tft_driver_tftespi.h" +#elif defined(ESP32) && defined(LGFX_USE_V1) +// #warning Building for ESP32 LovyanGfx +#include "tft_driver_lovyangfx.h" #elif defined(ESP8266) // #warning Building for ESP8266 Tfts #include "tft_driver_tftespi.h" diff --git a/src/drv/tft/tft_driver_lovyangfx.cpp b/src/drv/tft/tft_driver_lovyangfx.cpp new file mode 100644 index 00000000..0df0e37b --- /dev/null +++ b/src/drv/tft/tft_driver_lovyangfx.cpp @@ -0,0 +1,335 @@ +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie + For full license information read the LICENSE file in the project folder */ + +#if defined(ARDUINO) && defined(LGFX_USE_V1) +#include "tft_driver_lovyangfx.h" + +namespace dev { + +void LovyanGfx::init(int w, int h) +{ +#ifdef USE_DMA_TO_TFT + int dma_channel = 1; // Set the DMA channel (1 or 2. 0=disable) +#else + int dma_channel = 1; // Set the DMA channel (1 or 2. 0=disable) +#endif + + { // バス制御の設定を行います。 + auto bus = (lgfx::v1::Bus_SPI*)tft._bus_instance; + auto cfg = bus->config(); // バス設定用の構造体を取得します。 + cfg.spi_host = VSPI_HOST; // 使用するSPIを選択 (VSPI_HOST or HSPI_HOST) + cfg.spi_mode = 0; // SPI通信モードを設定 (0 ~ 3) + cfg.freq_write = SPI_FREQUENCY; // 送信時のSPIクロック (最大80MHz, 80MHzを整数で割った値に丸められます) + cfg.freq_read = SPI_READ_FREQUENCY; // 受信時のSPIクロック + cfg.spi_3wire = false; // 受信をMOSIピンで行う場合はtrueを設定 + cfg.use_lock = true; // トランザクションロックを使用する場合はtrueを設定 + cfg.dma_channel = dma_channel; // Set the DMA channel (1 or 2. 0=disable) + cfg.pin_sclk = TFT_SCLK; // SPIのSCLKピン番号を設定 + cfg.pin_mosi = TFT_MOSI; // SPIのMOSIピン番号を設定 + cfg.pin_miso = TFT_MISO; // SPIのMISOピン番号を設定 (-1 = disable) + cfg.pin_dc = TFT_DC; // SPIのD/Cピン番号を設定 (-1 = disable) + bus->config(cfg); // 設定値をバスに反映します。 + tft._panel_instance.setBus(bus); // バスをパネルにセットします。 + } + + { // 表示パネル制御の設定を行います。 + auto cfg = tft._panel_instance.config(); // 表示パネル設定用の構造体を取得します。 + cfg.pin_cs = TFT_CS; // CSが接続されているピン番号 (-1 = disable) + cfg.pin_rst = TFT_RST; // RSTが接続されているピン番号 (-1 = disable) + cfg.pin_busy = -1; // BUSYが接続されているピン番号 (-1 = disable) + cfg.memory_width = w; // ドライバICがサポートしている最大の幅 + cfg.memory_height = h; // ドライバICがサポートしている最大の高さ + cfg.panel_width = w; // 実際に表示可能な幅 + cfg.panel_height = h; // 実際に表示可能な高さ + 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 = true; // パネルの明暗が反転してしまう場合 trueに設定 + cfg.rgb_order = false; // パネルの赤と青が入れ替わってしまう場合 trueに設定 + cfg.dlen_16bit = false; // データ長を16bit単位で送信するパネルの場合 trueに設定 + cfg.bus_shared = true; // SDカードとバスを共有している場合 trueに設定(drawJpgFile等でバス制御を行います) + + tft._panel_instance.config(cfg); + } + + { // バックライト制御の設定を行います。(必要なければ削除) + auto cfg = tft._light_instance.config(); // バックライト設定用の構造体を取得します。 + + cfg.pin_bl = TFT_BCKL; // バックライトが接続されているピン番号 + cfg.invert = false; // バックライトの輝度を反転させる場合 true + cfg.freq = 44100; // バックライトのPWM周波数 + cfg.pwm_channel = 0; // 使用するPWMのチャンネル番号 + + tft._light_instance.config(cfg); + tft._panel_instance.setLight(&tft._light_instance); // バックライトをパネルにセットします。 + } + + { // タッチスクリーン制御の設定を行います。(必要なければ削除) + auto cfg = tft._touch_instance.config(); + cfg.x_min = 0; // タッチスクリーンから得られる最小のX値(生の値) + cfg.x_max = 319; // タッチスクリーンから得られる最大のX値(生の値) + cfg.y_min = 0; // タッチスクリーンから得られる最小のY値(生の値) + cfg.y_max = 479; // タッチスクリーンから得られる最大のY値(生の値) + cfg.pin_int = -1; // INTが接続されているピン番号 + cfg.bus_shared = true; // 画面と共通のバスを使用している場合 trueを設定 + cfg.offset_rotation = 0; // 表示とタッチの向きのが一致しない場合の調整 0~7の値で設定 + cfg.spi_host = VSPI_HOST; // 使用するSPIを選択 (HSPI_HOST or VSPI_HOST) + cfg.freq = SPI_TOUCH_FREQUENCY; // SPIクロックを設定 + cfg.pin_sclk = TFT_SCLK; // SCLKが接続されているピン番号 + cfg.pin_mosi = TFT_MOSI; // MOSIが接続されているピン番号 + cfg.pin_miso = TFT_MISO; // MISOが接続されているピン番号 + cfg.pin_cs = TOUCH_CS; // CSが接続されているピン番号 + tft._touch_instance.config(cfg); + tft._panel_instance.setTouch(&tft._touch_instance); // タッチスクリーンをパネルにセットします。 + } + tft.setPanel(&tft._panel_instance); // 使用するパネルをセットします。 + + /* TFT init */ + tft.begin(); + tft.setSwapBytes(true); /* set endianess */ +} + +void LovyanGfx::show_info() +{ + splashscreen(); + + LOG_VERBOSE(TAG_TFT, F("LovyanGFX : v%d.%d.%d"), LGFX_VERSION_MAJOR, LGFX_VERSION_MINOR, LGFX_VERSION_PATCH); + + // LOG_VERBOSE(TAG_TFT, F("Transactns : %s"), (tftSetup.trans == 1) ? PSTR(D_YES) : PSTR(D_NO)); + // LOG_VERBOSE(TAG_TFT, F("Interface : %s"), (tftSetup.serial == 1) ? PSTR("SPI") : PSTR("Parallel")); + + { + auto bus = (lgfx::v1::Bus_SPI*)tft._bus_instance; + auto cfg = bus->config(); // バス設定用の構造体を取得します。 + tftPinInfo(F("MOSI"), cfg.pin_mosi); + tftPinInfo(F("MISO"), cfg.pin_miso); + tftPinInfo(F("SCLK"), cfg.pin_sclk); + tftPinInfo(F("TFT_DC"), cfg.pin_dc); + } + + { + auto cfg = tft._panel_instance.config(); // バス設定用の構造体を取得します。 + tftPinInfo(F("TFT_CS"), cfg.pin_cs); + tftPinInfo(F("TFT_RST"), cfg.pin_rst); + } + + { + auto bus = (lgfx::v1::Bus_SPI*)tft._bus_instance; + auto cfg = bus->config(); // バス設定用の構造体を取得します。 + uint32_t freq = cfg.freq_write / 100000; + LOG_VERBOSE(TAG_TFT, F("Display SPI freq. : %d.%d MHz"), freq / 10, freq % 10); + } + + { + auto cfg = tft._touch_instance.config(); // バス設定用の構造体を取得します。 + if(cfg.pin_cs != -1) { + tftPinInfo(F("TOUCH_CS"), cfg.pin_cs); + uint32_t freq = cfg.freq / 100000; + LOG_VERBOSE(TAG_TFT, F("Touch SPI freq. : %d.%d MHz"), freq / 10, freq % 10); + } + } + + // tftPinInfo(F("TFT_WR"), tftSetup.pin_tft_wr); + // tftPinInfo(F("TFT_RD"), tftSetup.pin_tft_rd); + + // tftPinInfo(F("TFT_D0"), tftSetup.pin_tft_d0); + // tftPinInfo(F("TFT_D1"), tftSetup.pin_tft_d1); + // tftPinInfo(F("TFT_D2"), tftSetup.pin_tft_d2); + // tftPinInfo(F("TFT_D3"), tftSetup.pin_tft_d3); + // tftPinInfo(F("TFT_D4"), tftSetup.pin_tft_d4); + // tftPinInfo(F("TFT_D5"), tftSetup.pin_tft_d5); + // tftPinInfo(F("TFT_D6"), tftSetup.pin_tft_d6); + // tftPinInfo(F("TFT_D7"), tftSetup.pin_tft_d7); + + // if(tftSetup.serial == 1) { + // LOG_VERBOSE(TAG_TFT, F("Display SPI freq. : %d.%d MHz"), tftSetup.tft_spi_freq / 10, + // tftSetup.tft_spi_freq % 10); + // } + // if(tftSetup.pin_tch_cs != -1) { + // LOG_VERBOSE(TAG_TFT, F("Touch SPI freq. : %d.%d MHz"), tftSetup.tch_spi_freq / 10, + // tftSetup.tch_spi_freq % 10); + // } +} + +void LovyanGfx::splashscreen() +{ + uint8_t fg[] = logoFgColor; + uint8_t bg[] = logoBgColor; + lv_color_t fgColor = lv_color_make(fg[0], fg[1], fg[2]); + lv_color_t bgColor = lv_color_make(bg[0], bg[1], bg[2]); + + tft.fillScreen(bgColor.full); + int x = (tft.width() - logoWidth) / 2; + int y = (tft.height() - logoHeight) / 2; + tft.drawXBitmap(x, y, logoImage, logoWidth, logoHeight, fgColor.full); +} + +void LovyanGfx::set_rotation(uint8_t rotation) +{ + LOG_VERBOSE(TAG_TFT, F("Rotation : %d"), rotation); + tft.setRotation(rotation); +} + +void LovyanGfx::set_invert(bool invert) +{ + char buffer[4]; + memcpy_P(buffer, invert ? PSTR(D_YES) : PSTR(D_NO), sizeof(buffer)); + + LOG_VERBOSE(TAG_TFT, F("Invert Disp: %s"), buffer); + tft.invertDisplay(invert); +} + +/* Update TFT */ +void IRAM_ATTR LovyanGfx::flush_pixels(lv_disp_drv_t* disp, const lv_area_t* area, lv_color_t* color_p) +{ + uint32_t w = (area->x2 - area->x1 + 1); + uint32_t h = (area->y2 - area->y1 + 1); + uint32_t len = w * h; + + tft.startWrite(); /* Start new TFT transaction */ + tft.setAddrWindow(area->x1, area->y1, w, h); /* set the working window */ + tft.writePixels((uint16_t*)color_p, len); /* Write words at once */ + tft.endWrite(); /* terminate TFT transaction */ + + /* Tell lvgl that flushing is done */ + lv_disp_flush_ready(disp); +} + +bool LovyanGfx::is_driver_pin(uint8_t pin) +{ + if(false // start condition is always needed + +// Use individual checks instead of switch statement, as some case labels could be duplicated +#ifdef TOUCH_CS + || (pin == TOUCH_CS) +#endif +#ifdef TFT_MOSI + || (pin == TFT_MOSI) +#endif +#ifdef TFT_MISO + || (pin == TFT_MISO) +#endif +#ifdef TFT_SCLK + || (pin == TFT_SCLK) +#endif +#ifdef TFT_CS + || (pin == TFT_CS) +#endif +#ifdef TFT_DC + || (pin == TFT_DC) +#endif +#ifdef TFT_BL + || (pin == TFT_BL) +#endif +#ifdef TFT_RST + || (pin == TFT_RST) +#endif +#ifdef TFT_WR + || (pin == TFT_WR) +#endif +#ifdef TFT_RD + || (pin == TFT_RD) +#endif +#ifdef TFT_D0 + || (pin == TFT_D0) +#endif +#ifdef TFT_D1 + || (pin == TFT_D1) +#endif +#ifdef TFT_D2 + || (pin == TFT_D2) +#endif +#ifdef TFT_D3 + || (pin == TFT_D3) +#endif +#ifdef TFT_D4 + || (pin == TFT_D4) +#endif +#ifdef TFT_D5 + || (pin == TFT_D5) +#endif +#ifdef TFT_D6 + || (pin == TFT_D6) +#endif +#ifdef TFT_D7 + || (pin == TFT_D7) +#endif +#ifdef TFT_D8 + || (pin == TFT_D8) +#endif +#ifdef TFT_D9 + || (pin == TFT_D9) +#endif +#ifdef TFT_D10 + || (pin == TFT_D10) +#endif +#ifdef TFT_D11 + || (pin == TFT_D11) +#endif +#ifdef TFT_D12 + || (pin == TFT_D12) +#endif +#ifdef TFT_D13 + || (pin == TFT_D13) +#endif +#ifdef TFT_D14 + || (pin == TFT_D14) +#endif +#ifdef TFT_D15 + || (pin == TFT_D15) +#endif + ) { + return true; + } + +#ifdef ARDUINO_ARCH_ESP8266 +#ifndef TFT_SPI_OVERLAP + if((pin >= 12) && (pin <= 14)) return true; // HSPI +#endif +#endif + + return false; +} + +const char* LovyanGfx::get_tft_model() +{ +#if defined(ILI9341_DRIVER) + return "ILI9341"; +#elif defined(ST7735_DRIVER) + return "ST7735"; +#elif defined(ILI9163_DRIVER) + return "ILI9163"; +#elif defined(S6D02A1_DRIVER) + return "S6D02A1"; +#elif defined(ST7796_DRIVER) + return "ST7796"; +#elif defined(ILI9486_DRIVER) + return "ILI9486"; +#elif defined(ILI9481_DRIVER) + return "ILI9481"; +#elif defined(ILI9488_DRIVER) + return "ILI9488"; +#elif defined(HX8357D_DRIVER) + return "HX8357D"; +#elif defined(EPD_DRIVER) + return "EPD"; +#elif defined(ST7789_DRIVER) + return "ST7789"; +#elif defined(R61581_DRIVER) + return "R61581"; +#elif defined(ST7789_2_DRIVER) + return "ST7789_2"; +#elif defined(RM68140_DRIVER) + return "RM68140"; +#else + return "Other"; +#endif +} + +} // namespace dev + +dev::LovyanGfx haspTft; +#endif \ No newline at end of file diff --git a/src/drv/tft/tft_driver_lovyangfx.h b/src/drv/tft/tft_driver_lovyangfx.h new file mode 100644 index 00000000..53181bb9 --- /dev/null +++ b/src/drv/tft/tft_driver_lovyangfx.h @@ -0,0 +1,84 @@ +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie + For full license information read the LICENSE file in the project folder */ + +#ifndef HASP_LOVYANGFX_DRIVER_H +#define HASP_LOVYANGFX_DRIVER_H + +#if defined(ARDUINO) && defined(LGFX_USE_V1) +#include "Arduino.h" + +#include "lvgl.h" +#include "LovyanGFX.hpp" + +#include "tft_driver.h" +#include "hal/hasp_hal.h" +#include "dev/device.h" +#include "hasp_debug.h" + +#ifdef HASP_CUSTOMIZE_BOOTLOGO +#include "custom/bootlogo.h" // Sketch tab header for xbm images +#else +#include "custom/bootlogo_template.h" // Sketch tab header for xbm images +#endif + +namespace dev { +class LGFX : public lgfx::LGFX_Device { + public: + lgfx::Panel_ILI9488 _panel_instance; + lgfx::IBus* _bus_instance; // SPIバスのインスタンス + lgfx::Light_PWM _light_instance; + lgfx::Touch_XPT2046 _touch_instance; + + LGFX(void) + { + _bus_instance = new lgfx::v1::Bus_SPI(); + } +}; + +class LovyanGfx : BaseTft { + + public: + LGFX tft; + + void init(int w, int h); + void show_info(); + void splashscreen(); + + void set_rotation(uint8_t rotation); + void set_invert(bool invert); + + void flush_pixels(lv_disp_drv_t* disp, const lv_area_t* area, lv_color_t* color_p); + bool is_driver_pin(uint8_t pin); + + const char* get_tft_model(); + + private: + void tftOffsetInfo(uint8_t pin, uint8_t x_offset, uint8_t y_offset) + { + if(x_offset != 0) { + LOG_VERBOSE(TAG_TFT, F("R%u x offset = %i"), pin, x_offset); + } + if(y_offset != 0) { + LOG_VERBOSE(TAG_TFT, F("R%u y offset = %i"), pin, y_offset); + } + } + + void tftPinInfo(const __FlashStringHelper* pinfunction, int8_t pin) + { + if(pin != -1) { + char buffer[64]; + snprintf_P(buffer, sizeof(buffer), PSTR("%-11s: %s (GPIO %02d)"), String(pinfunction).c_str(), + haspDevice.gpio_name(pin).c_str(), pin); + LOG_VERBOSE(TAG_TFT, buffer); + } + } +}; + +} // namespace dev + +using dev::LovyanGfx; +extern dev::LovyanGfx haspTft; + +#endif // ARDUINO + +#endif // HASP_LOVYANGFX_DRIVER_H \ No newline at end of file diff --git a/src/drv/touch/touch_driver.h b/src/drv/touch/touch_driver.h index 15a4ab46..0c1b99ef 100644 --- a/src/drv/touch/touch_driver.h +++ b/src/drv/touch/touch_driver.h @@ -47,7 +47,7 @@ class BaseTouch { #define TOUCH_DRIVER -1 // No Touch #endif -#if TOUCH_DRIVER == 2046 +#if TOUCH_DRIVER == 2046 && defined(USER_SETUP_LOADED) #warning Building for XPT2046 //#include "touch_driver_xpt2046.h" #include "touch_driver_tftespi.h" diff --git a/src/hasp_gui.cpp b/src/hasp_gui.cpp index 559aa345..7438c380 100644 --- a/src/hasp_gui.cpp +++ b/src/hasp_gui.cpp @@ -98,7 +98,7 @@ IRAM_ATTR void gui_flush_cb(lv_disp_drv_t* disp, const lv_area_t* area, lv_color void guiCalibrate(void) { -#if TOUCH_DRIVER == 2046 && USE_TFT_ESPI > 0 +#if TOUCH_DRIVER == 2046 && defined(USER_SETUP_LOADED) #ifdef TOUCH_CS haspTouch.calibrate(gui_settings.cal_data); #endif @@ -460,7 +460,7 @@ bool guiGetConfig(const JsonObject& settings) } else { changed = true; -#if TOUCH_DRIVER == 2046 && USE_TFT_ESPI > 0 && defined(TOUCH_CS) +#if TOUCH_DRIVER == 2046 && defined(USER_SETUP_LOADED) && defined(TOUCH_CS) // tft_espi_set_touch(gui_settings.cal_data); haspTft.tft.setTouch(gui_settings.cal_data); #endif @@ -476,7 +476,7 @@ bool guiGetConfig(const JsonObject& settings) } changed = true; -#if TOUCH_DRIVER == 2046 && USE_TFT_ESPI > 0 && defined(TOUCH_CS) +#if TOUCH_DRIVER == 2046 && defined(USER_SETUP_LOADED) && defined(TOUCH_CS) // tft_espi_set_touch(gui_settings.cal_data); haspTft.tft.setTouch(gui_settings.cal_data); #endif @@ -545,7 +545,7 @@ bool guiSetConfig(const JsonObject& settings) oobeSetAutoCalibrate(true); } -#if TOUCH_DRIVER == 2046 && USE_TFT_ESPI > 0 && defined(TOUCH_CS) +#if TOUCH_DRIVER == 2046 && defined(USER_SETUP_LOADED) && defined(TOUCH_CS) if(status) // tft_espi_set_touch(gui_settings.cal_data); haspTft.tft.setTouch(gui_settings.cal_data); #endif diff --git a/user_setups/esp32/lolin-d32-pro_ili9341.ini b/user_setups/esp32/lolin-d32-pro_ili9341.ini index f7445aea..6f6b24c5 100644 --- a/user_setups/esp32/lolin-d32-pro_ili9341.ini +++ b/user_setups/esp32/lolin-d32-pro_ili9341.ini @@ -24,7 +24,6 @@ build_flags = ${lcd.ili9341} ${touch.xpt2046} ${esp32.vspi} ; Use VSPI hardware SPI bus - -D USE_TFT_ESPI ; The board already defines the macros for the TFT connector: ;-D TFT_DC=27 ; Defined by board, don't redefine !! ;-D TFT_CS=14 ; Defined by board, don't redefine !!