From 0563e42dc918084319ce2f80e1c013fdf9d27efe Mon Sep 17 00:00:00 2001 From: Ken Van Hoeylandt Date: Wed, 19 Feb 2025 21:01:13 +0100 Subject: [PATCH] New board: Elecrow CrowPanel Avance 2.8" (#224) - Added new board - Extracted ST7789 driver and backlight PWM driver into separate subprojects - Refactored T-Deck to use the shared driver modules - Fix bug in WiFi service: searching for APs was broken --- .github/workflows/build-firmware.yml | 9 + App/CMakeLists.txt | 1 + App/Kconfig | 8 + App/Source/Boards.h | 3 + .../ElecrowCrowpanelAdvance28/CMakeLists.txt | 7 + .../Source/CrowPanelAdvance28.cpp | 150 +++++++++++ .../Source/CrowPanelAdvance28.h | 5 + .../Source/hal/CrowPanelDisplay.cpp | 27 ++ .../Source/hal/CrowPanelDisplay.h | 40 +++ .../Source/hal/CrowPanelDisplayConstants.h | 17 ++ .../Source/hal/CrowPanelSdCard.cpp | 29 +++ .../Source/hal/CrowPanelSdCard.h | 7 + .../Source/hal/CrowPanelTouch.cpp | 85 ++++++ .../Source/hal/CrowPanelTouch.h | 25 ++ Boards/LilygoTdeck/CMakeLists.txt | 2 +- Boards/LilygoTdeck/Source/Init.cpp | 8 +- .../LilygoTdeck/Source/hal/TdeckDisplay.cpp | 243 ++---------------- Boards/LilygoTdeck/Source/hal/TdeckDisplay.h | 2 +- .../Source/hal/TdeckDisplayConstants.h | 11 - Boards/LilygoTdeck/Source/hal/TdeckTouch.cpp | 2 +- Buildscripts/build-and-release-all.sh | 3 + CMakeLists.txt | 1 + Drivers/PwmBacklight/CMakeLists.txt | 5 + Drivers/PwmBacklight/README.md | 3 + Drivers/PwmBacklight/Source/PwmBacklight.cpp | 62 +++++ Drivers/PwmBacklight/Source/PwmBacklight.h | 11 + Drivers/ST7789/CMakeLists.txt | 5 + Drivers/ST7789/README.md | 3 + Drivers/ST7789/Source/St7789Display.cpp | 180 +++++++++++++ Drivers/ST7789/Source/St7789Display.h | 84 ++++++ Tactility/Source/app/boot/Boot.cpp | 4 + .../Tactility/hal/sdcard/SpiSdCardDevice.h | 10 +- .../Source/hal/sdcard/SpiSdCard.cpp | 8 +- .../Source/service/wifi/WifiEsp.cpp | 2 +- sdkconfig.board.elecrow-crowpanel-advance-28 | 55 ++++ 35 files changed, 865 insertions(+), 252 deletions(-) create mode 100644 Boards/ElecrowCrowpanelAdvance28/CMakeLists.txt create mode 100644 Boards/ElecrowCrowpanelAdvance28/Source/CrowPanelAdvance28.cpp create mode 100644 Boards/ElecrowCrowpanelAdvance28/Source/CrowPanelAdvance28.h create mode 100644 Boards/ElecrowCrowpanelAdvance28/Source/hal/CrowPanelDisplay.cpp create mode 100644 Boards/ElecrowCrowpanelAdvance28/Source/hal/CrowPanelDisplay.h create mode 100644 Boards/ElecrowCrowpanelAdvance28/Source/hal/CrowPanelDisplayConstants.h create mode 100644 Boards/ElecrowCrowpanelAdvance28/Source/hal/CrowPanelSdCard.cpp create mode 100644 Boards/ElecrowCrowpanelAdvance28/Source/hal/CrowPanelSdCard.h create mode 100644 Boards/ElecrowCrowpanelAdvance28/Source/hal/CrowPanelTouch.cpp create mode 100644 Boards/ElecrowCrowpanelAdvance28/Source/hal/CrowPanelTouch.h create mode 100644 Drivers/PwmBacklight/CMakeLists.txt create mode 100644 Drivers/PwmBacklight/README.md create mode 100644 Drivers/PwmBacklight/Source/PwmBacklight.cpp create mode 100644 Drivers/PwmBacklight/Source/PwmBacklight.h create mode 100644 Drivers/ST7789/CMakeLists.txt create mode 100644 Drivers/ST7789/README.md create mode 100644 Drivers/ST7789/Source/St7789Display.cpp create mode 100644 Drivers/ST7789/Source/St7789Display.h create mode 100644 sdkconfig.board.elecrow-crowpanel-advance-28 diff --git a/.github/workflows/build-firmware.yml b/.github/workflows/build-firmware.yml index c7d3f1a6..8c50dc93 100644 --- a/.github/workflows/build-firmware.yml +++ b/.github/workflows/build-firmware.yml @@ -18,6 +18,15 @@ jobs: with: board_id: cyd-2432S024c arch: esp32 + elecrow-crowpanel-advance-28: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: "Build" + uses: ./.github/actions/build-firmware + with: + board_id: elecrow-crowpanel-advance-28 + arch: esp32s3 lilygo-tdeck: runs-on: ubuntu-latest steps: diff --git a/App/CMakeLists.txt b/App/CMakeLists.txt index 9ddae03c..acd6e570 100644 --- a/App/CMakeLists.txt +++ b/App/CMakeLists.txt @@ -12,6 +12,7 @@ if (DEFINED ENV{ESP_IDF_VERSION}) if("${IDF_TARGET}" STREQUAL "esp32s3") list(APPEND BOARD_COMPONENTS + ElecrowCrowpanelAdvance28 LilygoTdeck M5stackCoreS3 UnPhone diff --git a/App/Kconfig b/App/Kconfig index 8bc13263..9357c491 100644 --- a/App/Kconfig +++ b/App/Kconfig @@ -13,6 +13,14 @@ menu "Tactility App" bool "Custom" config TT_BOARD_CYD_2432S024C bool "CYD 2432S024C" + config TT_BOARD_ELECROW_CROWPANEL_ADVANCE_28 + bool "Elecrow CrowPanel Advance 2.8" + config TT_BOARD_ELECROW_CROWPANEL_ADVANCE_35 + bool "Elecrow CrowPanel Advance 3.5" + config TT_BOARD_ELECROW_CROWPANEL_BASIC_28 + bool "Elecrow CrowPanel Basic 2.8" + config TT_BOARD_ELECROW_CROWPANEL_BASIC_35 + bool "Elecrow CrowPanel Basic 3.5" config TT_BOARD_LILYGO_TDECK bool "LilyGo T-Deck" config TT_BOARD_M5STACK_CORE2 diff --git a/App/Source/Boards.h b/App/Source/Boards.h index 068e353d..ab9c401b 100644 --- a/App/Source/Boards.h +++ b/App/Source/Boards.h @@ -10,6 +10,9 @@ #elif defined(CONFIG_TT_BOARD_CYD_2432S024C) #include "CYD2432S024C.h" #define TT_BOARD_HARDWARE &cyd_2432S024c_config +#elif (defined(CONFIG_TT_BOARD_ELECROW_CROWPANEL_ADVANCE_28)) +#define TT_BOARD_HARDWARE &crowpanel_advance_28 +#include "CrowPanelAdvance28.h" #elif defined(CONFIG_TT_BOARD_M5STACK_CORE2) #include "M5stackCore2.h" #define TT_BOARD_HARDWARE &m5stack_core2 diff --git a/Boards/ElecrowCrowpanelAdvance28/CMakeLists.txt b/Boards/ElecrowCrowpanelAdvance28/CMakeLists.txt new file mode 100644 index 00000000..1ecb2679 --- /dev/null +++ b/Boards/ElecrowCrowpanelAdvance28/CMakeLists.txt @@ -0,0 +1,7 @@ +file(GLOB_RECURSE SOURCE_FILES Source/*.c*) + +idf_component_register( + SRCS ${SOURCE_FILES} + INCLUDE_DIRS "Source" + REQUIRES Tactility esp_lvgl_port esp_lcd esp_lcd_touch_ft5x06 ST7789 PwmBacklight driver esp_adc +) diff --git a/Boards/ElecrowCrowpanelAdvance28/Source/CrowPanelAdvance28.cpp b/Boards/ElecrowCrowpanelAdvance28/Source/CrowPanelAdvance28.cpp new file mode 100644 index 00000000..e4b89a16 --- /dev/null +++ b/Boards/ElecrowCrowpanelAdvance28/Source/CrowPanelAdvance28.cpp @@ -0,0 +1,150 @@ +#include "PwmBacklight.h" +#include "Tactility/lvgl/LvglSync.h" +#include "hal/CrowPanelDisplay.h" +#include "hal/CrowPanelDisplayConstants.h" +#include "hal/CrowPanelSdCard.h" + +#include + +#define CROWPANEL_SPI_TRANSFER_SIZE_LIMIT (CROWPANEL_LCD_HORIZONTAL_RESOLUTION * CROWPANEL_LCD_SPI_TRANSFER_HEIGHT * (CROWPANEL_LCD_BITS_PER_PIXEL / 8)) + +using namespace tt::hal; + +bool initBoot() { + return driver::pwmbacklight::init(GPIO_NUM_38); +} + +extern const Configuration crowpanel_advance_28 = { + .initBoot = initBoot, + .createDisplay = createDisplay, + .sdcard = createSdCard(), + .i2c = { + // There is only 1 (internal for touch, and also serves as "I2C-OUT" port) + // Note: You could repurpose 1 or more UART interfaces as I2C interfaces + i2c::Configuration { + .name = "Main", + .port = I2C_NUM_0, + .initMode = i2c::InitMode::ByTactility, + .canReinit = false, + .hasMutableConfiguration = false, + .config = (i2c_config_t) { + .mode = I2C_MODE_MASTER, + .sda_io_num = GPIO_NUM_15, + .scl_io_num = GPIO_NUM_16, + .sda_pullup_en = true, + .scl_pullup_en = true, + .master = { + .clk_speed = 400000 + }, + .clk_flags = 0 + } + } + }, + .spi { + // Display + spi::Configuration { + .device = SPI2_HOST, + .dma = SPI_DMA_DISABLED, + .config = { + .mosi_io_num = GPIO_NUM_39, + .miso_io_num = GPIO_NUM_NC, + .sclk_io_num = GPIO_NUM_42, + .quadwp_io_num = GPIO_NUM_NC, + .quadhd_io_num = GPIO_NUM_NC, + .data4_io_num = 0, + .data5_io_num = 0, + .data6_io_num = 0, + .data7_io_num = 0, + .data_io_default_level = false, + .max_transfer_sz = CROWPANEL_SPI_TRANSFER_SIZE_LIMIT, + .flags = 0, + .isr_cpu_id = ESP_INTR_CPU_AFFINITY_AUTO, + .intr_flags = 0 + }, + .initMode = spi::InitMode::ByTactility, + .canReinit = false, + .hasMutableConfiguration = false, + .lock = tt::lvgl::getSyncLock() // esp_lvgl_port owns the lock for the display + }, + // SD card + spi::Configuration { + .device = SPI3_HOST, + .dma = SPI_DMA_CH_AUTO, + .config = { + .mosi_io_num = GPIO_NUM_6, + .miso_io_num = GPIO_NUM_4, + .sclk_io_num = GPIO_NUM_5, + .quadwp_io_num = GPIO_NUM_NC, + .quadhd_io_num = GPIO_NUM_NC, + .data4_io_num = 0, + .data5_io_num = 0, + .data6_io_num = 0, + .data7_io_num = 0, + .data_io_default_level = false, + .max_transfer_sz = 32768, + .flags = 0, + .isr_cpu_id = ESP_INTR_CPU_AFFINITY_AUTO, + .intr_flags = 0 + }, + .initMode = spi::InitMode::ByTactility, + .canReinit = false, + .hasMutableConfiguration = false, + .lock = nullptr // No custom lock needed + } + }, + .uart { + // "UART0-IN" + uart::Configuration { + .port = UART_NUM_1, + .initMode = uart::InitMode::Disabled, // Manual init + .canReinit = true, + .hasMutableConfiguration = false, + .rxPin = GPIO_NUM_44, + .txPin = GPIO_NUM_43, + .rtsPin = GPIO_NUM_NC, + .ctsPin = GPIO_NUM_NC, + .rxBufferSize = 1024, + .txBufferSize = 1024, + .config = { + .baud_rate = 115200, + .data_bits = UART_DATA_8_BITS, + .parity = UART_PARITY_DISABLE, + .stop_bits = UART_STOP_BITS_1, + .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, + .rx_flow_ctrl_thresh = 0, + .source_clk = UART_SCLK_DEFAULT, + .flags = { + .allow_pd = 0, + .backup_before_sleep = 0, + } + } + }, + // "UART1-OUT" + uart::Configuration { + .port = UART_NUM_1, + .initMode = uart::InitMode::Disabled, // Manual init + .canReinit = true, + .hasMutableConfiguration = false, + .rxPin = GPIO_NUM_18, + .txPin = GPIO_NUM_17, + .rtsPin = GPIO_NUM_NC, + .ctsPin = GPIO_NUM_NC, + .rxBufferSize = 1024, + .txBufferSize = 1024, + .config = { + .baud_rate = 115200, + .data_bits = UART_DATA_8_BITS, + .parity = UART_PARITY_DISABLE, + .stop_bits = UART_STOP_BITS_1, + .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, + .rx_flow_ctrl_thresh = 0, + .source_clk = UART_SCLK_DEFAULT, + .flags = { + .allow_pd = 0, + .backup_before_sleep = 0, + } + } + } + }, + .gps = {} +}; diff --git a/Boards/ElecrowCrowpanelAdvance28/Source/CrowPanelAdvance28.h b/Boards/ElecrowCrowpanelAdvance28/Source/CrowPanelAdvance28.h new file mode 100644 index 00000000..0a1d5d50 --- /dev/null +++ b/Boards/ElecrowCrowpanelAdvance28/Source/CrowPanelAdvance28.h @@ -0,0 +1,5 @@ +#pragma once + +#include + +extern const tt::hal::Configuration crowpanel_advance_28; diff --git a/Boards/ElecrowCrowpanelAdvance28/Source/hal/CrowPanelDisplay.cpp b/Boards/ElecrowCrowpanelAdvance28/Source/hal/CrowPanelDisplay.cpp new file mode 100644 index 00000000..5b1aafbf --- /dev/null +++ b/Boards/ElecrowCrowpanelAdvance28/Source/hal/CrowPanelDisplay.cpp @@ -0,0 +1,27 @@ +#include "CrowPanelDisplay.h" +#include "CrowPanelDisplayConstants.h" +#include "CrowPanelTouch.h" + +#include +#include + +#include + +#define TAG "crowpanel_display" + +std::shared_ptr createDisplay() { + auto touch = std::make_shared(); + + auto configuration = std::make_unique( + CROWPANEL_LCD_SPI_HOST, + CROWPANEL_LCD_PIN_CS, + CROWPANEL_LCD_PIN_DC, + 320, + 240, + touch + ); + + configuration->backlightDutyFunction = driver::pwmbacklight::setBacklightDuty; + + return std::make_shared(std::move(configuration)); +} diff --git a/Boards/ElecrowCrowpanelAdvance28/Source/hal/CrowPanelDisplay.h b/Boards/ElecrowCrowpanelAdvance28/Source/hal/CrowPanelDisplay.h new file mode 100644 index 00000000..6c0fde39 --- /dev/null +++ b/Boards/ElecrowCrowpanelAdvance28/Source/hal/CrowPanelDisplay.h @@ -0,0 +1,40 @@ +#pragma once + +#include "Tactility/hal/display/DisplayDevice.h" +#include +#include + +class CrowPanelDisplay : public tt::hal::display::DisplayDevice { + +private: + + esp_lcd_panel_io_handle_t ioHandle = nullptr; + esp_lcd_panel_handle_t panelHandle = nullptr; + lv_display_t* displayHandle = nullptr; + bool poweredOn = false; + +public: + + std::string getName() const final { return "ST7789"; } + std::string getDescription() const final { return "SPI display"; } + + bool start() override; + + bool stop() override; + + void setPowerOn(bool turnOn) override; + bool isPoweredOn() const override { return poweredOn; }; + bool supportsPowerControl() const override { return true; } + + std::shared_ptr _Nullable createTouch() override; + + void setBacklightDuty(uint8_t backlightDuty) override; + bool supportsBacklightDuty() const override { return true; } + + void setGammaCurve(uint8_t index) override; + uint8_t getGammaCurveCount() const override { return 4; }; + + lv_display_t* _Nullable getLvglDisplay() const override { return displayHandle; } +}; + +std::shared_ptr createDisplay(); diff --git a/Boards/ElecrowCrowpanelAdvance28/Source/hal/CrowPanelDisplayConstants.h b/Boards/ElecrowCrowpanelAdvance28/Source/hal/CrowPanelDisplayConstants.h new file mode 100644 index 00000000..58e4d923 --- /dev/null +++ b/Boards/ElecrowCrowpanelAdvance28/Source/hal/CrowPanelDisplayConstants.h @@ -0,0 +1,17 @@ +#pragma once + +#define CROWPANEL_LCD_SPI_HOST SPI2_HOST +#define CROWPANEL_LCD_PIN_CS GPIO_NUM_40 +#define CROWPANEL_LCD_PIN_DC GPIO_NUM_41 // RS +#define CROWPANEL_LCD_HORIZONTAL_RESOLUTION 320 +#define CROWPANEL_LCD_VERTICAL_RESOLUTION 240 +#define CROWPANEL_LCD_BITS_PER_PIXEL 16 +#define CROWPANEL_LCD_SPI_TRANSFER_HEIGHT (CROWPANEL_LCD_VERTICAL_RESOLUTION / 10) + +// Backlight (PWM) +#define CROWPANEL_LCD_BACKLIGHT_LEDC_TIMER LEDC_TIMER_0 +#define CROWPANEL_LCD_BACKLIGHT_LEDC_MODE LEDC_LOW_SPEED_MODE +#define CROWPANEL_LCD_BACKLIGHT_LEDC_CHANNEL LEDC_CHANNEL_0 +#define CROWPANEL_LCD_BACKLIGHT_LEDC_DUTY_RES LEDC_TIMER_8_BIT +#define CROWPANEL_LCD_BACKLIGHT_LEDC_FREQUENCY (4000) + diff --git a/Boards/ElecrowCrowpanelAdvance28/Source/hal/CrowPanelSdCard.cpp b/Boards/ElecrowCrowpanelAdvance28/Source/hal/CrowPanelSdCard.cpp new file mode 100644 index 00000000..af404a9c --- /dev/null +++ b/Boards/ElecrowCrowpanelAdvance28/Source/hal/CrowPanelSdCard.cpp @@ -0,0 +1,29 @@ +#include "CrowPanelSdCard.h" + +#include +#include + +#include + +using tt::hal::sdcard::SpiSdCardDevice; + +#define CROWPANEL_SDCARD_PIN_CS GPIO_NUM_7 + +std::shared_ptr createSdCard() { + auto* configuration = new SpiSdCardDevice::Config( + CROWPANEL_SDCARD_PIN_CS, + GPIO_NUM_NC, + GPIO_NUM_NC, + GPIO_NUM_NC, + SdCardDevice::MountBehaviour::AtBoot, + tt::lvgl::getSyncLock(), + {}, + SPI3_HOST + ); + + auto* sdcard = (SdCardDevice*) new SpiSdCardDevice( + std::unique_ptr(configuration) + ); + + return std::shared_ptr(sdcard); +} diff --git a/Boards/ElecrowCrowpanelAdvance28/Source/hal/CrowPanelSdCard.h b/Boards/ElecrowCrowpanelAdvance28/Source/hal/CrowPanelSdCard.h new file mode 100644 index 00000000..5cb65a73 --- /dev/null +++ b/Boards/ElecrowCrowpanelAdvance28/Source/hal/CrowPanelSdCard.h @@ -0,0 +1,7 @@ +#pragma once + +#include "Tactility/hal/sdcard/SdCardDevice.h" + +using tt::hal::sdcard::SdCardDevice; + +std::shared_ptr createSdCard(); diff --git a/Boards/ElecrowCrowpanelAdvance28/Source/hal/CrowPanelTouch.cpp b/Boards/ElecrowCrowpanelAdvance28/Source/hal/CrowPanelTouch.cpp new file mode 100644 index 00000000..52567b15 --- /dev/null +++ b/Boards/ElecrowCrowpanelAdvance28/Source/hal/CrowPanelTouch.cpp @@ -0,0 +1,85 @@ +#include "CrowPanelTouch.h" +#include "esp_lcd_touch_ft5x06.h" + +#include +#include +#include + +#define TAG "crowpanel_touch" + +// Touch (GT911) +#define CROWPANEL_TOUCH_I2C_BUS_HANDLE I2C_NUM_0 +#define CROWPANEL_TOUCH_X_MAX 240 +#define CROWPANEL_TOUCH_Y_MAX 320 + +bool CrowPanelTouch::start(lv_display_t* display) { + esp_lcd_panel_io_i2c_config_t io_config = ESP_LCD_TOUCH_IO_I2C_FT5x06_CONFIG(); + + if (esp_lcd_new_panel_io_i2c(CROWPANEL_TOUCH_I2C_BUS_HANDLE, &io_config, &ioHandle) != ESP_OK) { + TT_LOG_E(TAG, "touch io i2c creation failed"); + return false; + } + + esp_lcd_touch_config_t config = { + .x_max = CROWPANEL_TOUCH_X_MAX, + .y_max = CROWPANEL_TOUCH_Y_MAX, + .rst_gpio_num = GPIO_NUM_NC, // GPIO_NUM_48, + .int_gpio_num = GPIO_NUM_NC, // GPIO_NUM_47, + .levels = { + .reset = 0, + .interrupt = 0, + }, + .flags = { + .swap_xy = 1, + .mirror_x = 1, + .mirror_y = 0, + }, + .process_coordinates = nullptr, + .interrupt_callback = nullptr, + .user_data = nullptr, + .driver_data = nullptr + }; + + if (esp_lcd_touch_new_i2c_ft5x06(ioHandle, &config, &touchHandle) != ESP_OK) { + TT_LOG_E(TAG, "GT911 driver init failed"); + cleanup(); + return false; + } + + const lvgl_port_touch_cfg_t touch_cfg = { + .disp = display, + .handle = touchHandle, + }; + + TT_LOG_I(TAG, "Adding touch to LVGL"); + deviceHandle = lvgl_port_add_touch(&touch_cfg); + if (deviceHandle == nullptr) { + TT_LOG_E(TAG, "Adding touch failed"); + cleanup(); + return false; + } + + return true; +} + +bool CrowPanelTouch::stop() { + cleanup(); + return true; +} + +void CrowPanelTouch::cleanup() { + if (deviceHandle != nullptr) { + lv_indev_delete(deviceHandle); + deviceHandle = nullptr; + } + + if (touchHandle != nullptr) { + esp_lcd_touch_del(touchHandle); + touchHandle = nullptr; + } + + if (ioHandle != nullptr) { + esp_lcd_panel_io_del(ioHandle); + ioHandle = nullptr; + } +} diff --git a/Boards/ElecrowCrowpanelAdvance28/Source/hal/CrowPanelTouch.h b/Boards/ElecrowCrowpanelAdvance28/Source/hal/CrowPanelTouch.h new file mode 100644 index 00000000..82b67216 --- /dev/null +++ b/Boards/ElecrowCrowpanelAdvance28/Source/hal/CrowPanelTouch.h @@ -0,0 +1,25 @@ +#pragma once + +#include "Tactility/hal/touch/TouchDevice.h" +#include +#include +#include + +class CrowPanelTouch : public tt::hal::touch::TouchDevice { + +private: + + std::string getName() const final { return "GT911"; } + std::string getDescription() const final { return "I2C Touch Driver"; } + + esp_lcd_panel_io_handle_t _Nullable ioHandle = nullptr; + esp_lcd_touch_handle_t _Nullable touchHandle = nullptr; + lv_indev_t* _Nullable deviceHandle = nullptr; + void cleanup(); + +public: + + bool start(lv_display_t* display) override; + bool stop() override; + lv_indev_t* _Nullable getLvglIndev() override { return deviceHandle; } +}; diff --git a/Boards/LilygoTdeck/CMakeLists.txt b/Boards/LilygoTdeck/CMakeLists.txt index 6211f2e4..5b34c58a 100644 --- a/Boards/LilygoTdeck/CMakeLists.txt +++ b/Boards/LilygoTdeck/CMakeLists.txt @@ -3,5 +3,5 @@ file(GLOB_RECURSE SOURCE_FILES Source/*.c*) idf_component_register( SRCS ${SOURCE_FILES} INCLUDE_DIRS "Source" - REQUIRES Tactility esp_lvgl_port esp_lcd esp_lcd_touch_gt911 driver esp_adc + REQUIRES Tactility esp_lvgl_port esp_lcd esp_lcd_touch_gt911 ST7789 PwmBacklight driver esp_adc ) diff --git a/Boards/LilygoTdeck/Source/Init.cpp b/Boards/LilygoTdeck/Source/Init.cpp index cdb383c1..f7d92fe7 100644 --- a/Boards/LilygoTdeck/Source/Init.cpp +++ b/Boards/LilygoTdeck/Source/Init.cpp @@ -1,4 +1,5 @@ -#include +#include "PwmBacklight.h" + #include #define TAG "tdeck" @@ -33,5 +34,10 @@ bool tdeckInit() { return false; } + if (!driver::pwmbacklight::init(GPIO_NUM_42)) { + TT_LOG_E(TAG, "Backlight init failed"); + return false; + } + return true; } diff --git a/Boards/LilygoTdeck/Source/hal/TdeckDisplay.cpp b/Boards/LilygoTdeck/Source/hal/TdeckDisplay.cpp index e1d8759e..f701f4f3 100644 --- a/Boards/LilygoTdeck/Source/hal/TdeckDisplay.cpp +++ b/Boards/LilygoTdeck/Source/hal/TdeckDisplay.cpp @@ -2,237 +2,26 @@ #include "TdeckDisplayConstants.h" #include "TdeckTouch.h" -#include -#include +#include +#include -#include -#include #include -#include -#include -#include -#include #define TAG "tdeck_display" -static bool isBacklightInitialized = false; - -static bool initBacklight() { - TT_LOG_I(TAG, "Init backlight"); - ledc_timer_config_t ledc_timer = { - .speed_mode = TDECK_LCD_BACKLIGHT_LEDC_MODE, - .duty_resolution = TDECK_LCD_BACKLIGHT_LEDC_DUTY_RES, - .timer_num = TDECK_LCD_BACKLIGHT_LEDC_TIMER, - .freq_hz = TDECK_LCD_BACKLIGHT_LEDC_FREQUENCY, - .clk_cfg = LEDC_AUTO_CLK, - .deconfigure = false - }; - - if (ledc_timer_config(&ledc_timer) != ESP_OK) { - TT_LOG_E(TAG, "Backlight led timer config failed"); - return false; - } - - return true; -} - -static bool setBacklight(uint8_t duty) { - ledc_channel_config_t ledc_channel = { - .gpio_num = TDECK_LCD_PIN_BACKLIGHT, - .speed_mode = TDECK_LCD_BACKLIGHT_LEDC_MODE, - .channel = TDECK_LCD_BACKLIGHT_LEDC_CHANNEL, - .intr_type = LEDC_INTR_DISABLE, - .timer_sel = TDECK_LCD_BACKLIGHT_LEDC_TIMER, - .duty = duty, - .hpoint = 0, - .sleep_mode = LEDC_SLEEP_MODE_NO_ALIVE_NO_PD, - .flags = { - .output_invert = 0 - } - }; - - // Setting the config in the timer init and then calling ledc_set_duty() doesn't work when - // the app is running. For an unknown reason we have to call this config method every time: - return ledc_channel_config(&ledc_channel) == ESP_OK; -} - -bool TdeckDisplay::start() { - TT_LOG_I(TAG, "Starting"); - - const esp_lcd_panel_io_spi_config_t panel_io_config = { - .cs_gpio_num = TDECK_LCD_PIN_CS, - .dc_gpio_num = TDECK_LCD_PIN_DC, - .spi_mode = 0, - .pclk_hz = TDECK_LCD_SPI_FREQUENCY, - .trans_queue_depth = 10, - .on_color_trans_done = nullptr, - .user_ctx = nullptr, - .lcd_cmd_bits = 8, - .lcd_param_bits = 8, - .cs_ena_pretrans = 0, - .cs_ena_posttrans = 0, - .flags = { - .dc_high_on_cmd = 0, - .dc_low_on_data = 0, - .dc_low_on_param = 0, - .octal_mode = 0, - .quad_mode = 0, - .sio_mode = 1, - .lsb_first = 0, - .cs_high_active = 0, - } - }; - - if (esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)TDECK_LCD_SPI_HOST, &panel_io_config, &ioHandle) != ESP_OK) { - TT_LOG_E(TAG, "Failed to create panel IO"); - return false; - } - - const esp_lcd_panel_dev_config_t panel_config = { - .reset_gpio_num = GPIO_NUM_NC, - .rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB, - .data_endian = LCD_RGB_DATA_ENDIAN_LITTLE, - .bits_per_pixel = TDECK_LCD_BITS_PER_PIXEL, - .flags = { - .reset_active_high = 0 - }, - .vendor_config = nullptr - }; - - if (esp_lcd_new_panel_st7789(ioHandle, &panel_config, &panelHandle) != ESP_OK) { - TT_LOG_E(TAG, "Failed to create panel"); - return false; - } - - if (esp_lcd_panel_reset(panelHandle) != ESP_OK) { - TT_LOG_E(TAG, "Failed to reset panel"); - return false; - } - - if (esp_lcd_panel_init(panelHandle) != ESP_OK) { - TT_LOG_E(TAG, "Failed to init panel"); - return false; - } - - if (esp_lcd_panel_invert_color(panelHandle, true) != ESP_OK) { - TT_LOG_E(TAG, "Failed to init panel"); - return false; - } - - if (esp_lcd_panel_swap_xy(panelHandle, true) != ESP_OK) { - TT_LOG_E(TAG, "Failed to swap XY "); - return false; - } - - if (esp_lcd_panel_mirror(panelHandle, true, false) != ESP_OK) { - TT_LOG_E(TAG, "Failed to mirror panel"); - return false; - } - - if (esp_lcd_panel_disp_on_off(panelHandle, true) != ESP_OK) { - TT_LOG_E(TAG, "Failed to turn display on"); - return false; - } - - const lvgl_port_display_cfg_t disp_cfg = { - .io_handle = ioHandle, - .panel_handle = panelHandle, - .control_handle = nullptr, - .buffer_size = TDECK_LCD_HORIZONTAL_RESOLUTION * TDECK_LCD_DRAW_BUFFER_HEIGHT, - .double_buffer = false, // Disable to free up memory - .trans_size = 0, - .hres = TDECK_LCD_HORIZONTAL_RESOLUTION, - .vres = TDECK_LCD_VERTICAL_RESOLUTION, - .monochrome = false, - .rotation = { - .swap_xy = true, - .mirror_x = true, - .mirror_y = false, - }, - .color_format = LV_COLOR_FORMAT_RGB565, - .flags = { - .buff_dma = true, - .buff_spiram = false, - .sw_rotate = false, - .swap_bytes = false, - .full_refresh = false, - .direct_mode = false - } - }; - - displayHandle = lvgl_port_add_disp(&disp_cfg); - TT_LOG_I(TAG, "Finished"); - return displayHandle != nullptr; -} - -bool TdeckDisplay::stop() { - assert(displayHandle != nullptr); - - lvgl_port_remove_disp(displayHandle); - - if (esp_lcd_panel_del(panelHandle) != ESP_OK) { - return false; - } - - if (esp_lcd_panel_io_del(ioHandle) != ESP_OK) { - return false; - } - - displayHandle = nullptr; - return true; - -} - -void TdeckDisplay::setPowerOn(bool turnOn) { - if (esp_lcd_panel_disp_on_off(panelHandle, turnOn) != ESP_OK) { - TT_LOG_E(TAG, "Failed to turn display on/off"); - } else { - poweredOn = turnOn; - } -} - -std::shared_ptr _Nullable TdeckDisplay::createTouch() { - return std::make_shared(); -} - -void TdeckDisplay::setBacklightDuty(uint8_t backlightDuty) { - if (!isBacklightInitialized) { - tt_check(initBacklight()); - isBacklightInitialized = true; - } - - if (!setBacklight(backlightDuty)) { - TT_LOG_E(TAG, "Failed to configure display backlight"); - } -} - -void TdeckDisplay::setGammaCurve(uint8_t index) { - uint8_t gamma_curve; - switch (index) { - case 0: - gamma_curve = 0x01; - break; - case 1: - gamma_curve = 0x04; - break; - case 2: - gamma_curve = 0x02; - break; - case 3: - gamma_curve = 0x08; - break; - default: - return; - } - const uint8_t param[] = { - gamma_curve - }; - - if (esp_lcd_panel_io_tx_param(ioHandle , LCD_CMD_GAMSET, param, 1) != ESP_OK) { - TT_LOG_E(TAG, "Failed to set gamma"); - } -} - std::shared_ptr createDisplay() { - return std::make_shared(); + auto touch = std::make_shared(); + + auto configuration = std::make_unique( + TDECK_LCD_SPI_HOST, + TDECK_LCD_PIN_CS, + TDECK_LCD_PIN_DC, + 320, + 240, + touch + ); + + configuration->backlightDutyFunction = driver::pwmbacklight::setBacklightDuty; + + return std::make_shared(std::move(configuration)); } diff --git a/Boards/LilygoTdeck/Source/hal/TdeckDisplay.h b/Boards/LilygoTdeck/Source/hal/TdeckDisplay.h index 29bb05e7..e9a26ec4 100644 --- a/Boards/LilygoTdeck/Source/hal/TdeckDisplay.h +++ b/Boards/LilygoTdeck/Source/hal/TdeckDisplay.h @@ -15,7 +15,7 @@ private: public: - std::string getName() const final { return "ST7780"; } + std::string getName() const final { return "ST7789"; } std::string getDescription() const final { return "SPI display"; } bool start() override; diff --git a/Boards/LilygoTdeck/Source/hal/TdeckDisplayConstants.h b/Boards/LilygoTdeck/Source/hal/TdeckDisplayConstants.h index b209ac06..05b2deb7 100644 --- a/Boards/LilygoTdeck/Source/hal/TdeckDisplayConstants.h +++ b/Boards/LilygoTdeck/Source/hal/TdeckDisplayConstants.h @@ -3,18 +3,7 @@ #define TDECK_LCD_SPI_HOST SPI2_HOST #define TDECK_LCD_PIN_CS GPIO_NUM_12 #define TDECK_LCD_PIN_DC GPIO_NUM_11 // RS -#define TDECK_LCD_PIN_BACKLIGHT GPIO_NUM_42 -#define TDECK_LCD_SPI_FREQUENCY 80000000 #define TDECK_LCD_HORIZONTAL_RESOLUTION 320 #define TDECK_LCD_VERTICAL_RESOLUTION 240 #define TDECK_LCD_BITS_PER_PIXEL 16 -#define TDECK_LCD_DRAW_BUFFER_HEIGHT (TDECK_LCD_VERTICAL_RESOLUTION / 10) #define TDECK_LCD_SPI_TRANSFER_HEIGHT (TDECK_LCD_VERTICAL_RESOLUTION / 10) - -// Backlight (PWM) -#define TDECK_LCD_BACKLIGHT_LEDC_TIMER LEDC_TIMER_0 -#define TDECK_LCD_BACKLIGHT_LEDC_MODE LEDC_LOW_SPEED_MODE -#define TDECK_LCD_BACKLIGHT_LEDC_CHANNEL LEDC_CHANNEL_0 -#define TDECK_LCD_BACKLIGHT_LEDC_DUTY_RES LEDC_TIMER_8_BIT -#define TDECK_LCD_BACKLIGHT_LEDC_FREQUENCY (4000) - diff --git a/Boards/LilygoTdeck/Source/hal/TdeckTouch.cpp b/Boards/LilygoTdeck/Source/hal/TdeckTouch.cpp index 36771b88..25e67139 100644 --- a/Boards/LilygoTdeck/Source/hal/TdeckTouch.cpp +++ b/Boards/LilygoTdeck/Source/hal/TdeckTouch.cpp @@ -41,7 +41,7 @@ bool TdeckTouch::start(lv_display_t* display) { }; if (esp_lcd_touch_new_i2c_gt911(ioHandle, &config, &touchHandle) != ESP_OK) { - TT_LOG_E(TAG, "GT199 driver init failed"); + TT_LOG_E(TAG, "GT911 driver init failed"); cleanup(); return false; } diff --git a/Buildscripts/build-and-release-all.sh b/Buildscripts/build-and-release-all.sh index f9b7615b..9bfcfb0b 100755 --- a/Buildscripts/build-and-release-all.sh +++ b/Buildscripts/build-and-release-all.sh @@ -14,6 +14,9 @@ function releaseSdk() { SECONDS=0 +build elecrow-crowpanel-advance-28 +release elecrow-crowpanel-advance-28 + build lilygo-tdeck release lilygo-tdeck diff --git a/CMakeLists.txt b/CMakeLists.txt index 20e9924e..5a18a36e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -42,6 +42,7 @@ if (DEFINED ENV{ESP_IDF_VERSION}) # Non-ESP32-S3 boards if(NOT "${IDF_TARGET}" STREQUAL "esp32s3") + set(EXCLUDE_COMPONENTS "ElecrowCrowpanelAdvance28") set(EXCLUDE_COMPONENTS "LilygoTdeck") set(EXCLUDE_COMPONENTS "M5stackCoreS3") set(EXCLUDE_COMPONENTS "UnPhone") diff --git a/Drivers/PwmBacklight/CMakeLists.txt b/Drivers/PwmBacklight/CMakeLists.txt new file mode 100644 index 00000000..48a85913 --- /dev/null +++ b/Drivers/PwmBacklight/CMakeLists.txt @@ -0,0 +1,5 @@ +idf_component_register( + SRC_DIRS "Source" + INCLUDE_DIRS "Source" + REQUIRES TactilityCore driver +) diff --git a/Drivers/PwmBacklight/README.md b/Drivers/PwmBacklight/README.md new file mode 100644 index 00000000..25bd8be1 --- /dev/null +++ b/Drivers/PwmBacklight/README.md @@ -0,0 +1,3 @@ +# PWM Backlight Driver + +A very basic driver to control an LCD panel backlight with a PWM signal. diff --git a/Drivers/PwmBacklight/Source/PwmBacklight.cpp b/Drivers/PwmBacklight/Source/PwmBacklight.cpp new file mode 100644 index 00000000..02981817 --- /dev/null +++ b/Drivers/PwmBacklight/Source/PwmBacklight.cpp @@ -0,0 +1,62 @@ +#include +#include +#include + +#define TAG "pwm_backlight" + +namespace driver::pwmbacklight { + +static bool isBacklightInitialized = false; +static gpio_num_t backlightPin = GPIO_NUM_NC; + +bool init(gpio_num_t pin) { + backlightPin = pin; + + TT_LOG_I(TAG, "Init"); + ledc_timer_config_t ledc_timer = { + .speed_mode = LEDC_LOW_SPEED_MODE, + .duty_resolution = LEDC_TIMER_8_BIT, + .timer_num = LEDC_TIMER_0, + .freq_hz = 4000, + .clk_cfg = LEDC_AUTO_CLK, + .deconfigure = false + }; + + if (ledc_timer_config(&ledc_timer) != ESP_OK) { + TT_LOG_E(TAG, "Timer config failed"); + return false; + } + + ledc_channel_config_t ledc_channel = { + .gpio_num = backlightPin, + .speed_mode = LEDC_LOW_SPEED_MODE, + .channel = LEDC_CHANNEL_0, + .intr_type = LEDC_INTR_DISABLE, + .timer_sel = LEDC_TIMER_0, + .duty = 0, + .hpoint = 0, + .sleep_mode = LEDC_SLEEP_MODE_NO_ALIVE_NO_PD, + .flags = { + .output_invert = 0 + } + }; + + if (ledc_channel_config(&ledc_channel) != ESP_OK) { + TT_LOG_E(TAG, "Channel config failed"); + } + + isBacklightInitialized = true; + + return true; +} + +bool setBacklightDuty(uint8_t duty) { + if (!isBacklightInitialized) { + TT_LOG_E(TAG, "Not initialized"); + return false; + } + return ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, duty) == ESP_OK && + ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0) == ESP_OK; +} + +} diff --git a/Drivers/PwmBacklight/Source/PwmBacklight.h b/Drivers/PwmBacklight/Source/PwmBacklight.h new file mode 100644 index 00000000..d151edce --- /dev/null +++ b/Drivers/PwmBacklight/Source/PwmBacklight.h @@ -0,0 +1,11 @@ +#pragma once + +#include + +namespace driver::pwmbacklight { + +bool init(gpio_num_t pin); + +void setBacklightDuty(uint8_t duty); + +} diff --git a/Drivers/ST7789/CMakeLists.txt b/Drivers/ST7789/CMakeLists.txt new file mode 100644 index 00000000..2dd2736d --- /dev/null +++ b/Drivers/ST7789/CMakeLists.txt @@ -0,0 +1,5 @@ +idf_component_register( + SRC_DIRS "Source" + INCLUDE_DIRS "Source" + REQUIRES Tactility esp_lvgl_port esp_lcd driver +) diff --git a/Drivers/ST7789/README.md b/Drivers/ST7789/README.md new file mode 100644 index 00000000..2f6c6fb7 --- /dev/null +++ b/Drivers/ST7789/README.md @@ -0,0 +1,3 @@ +# ST7789 + +A basic ESP32 LVGL driver for ST7789 displays. diff --git a/Drivers/ST7789/Source/St7789Display.cpp b/Drivers/ST7789/Source/St7789Display.cpp new file mode 100644 index 00000000..44b0b552 --- /dev/null +++ b/Drivers/ST7789/Source/St7789Display.cpp @@ -0,0 +1,180 @@ +#include "St7789Display.h" + +#include + +#include +#include +#include +#include + +#define TAG "st7789" + +bool St7789Display::start() { + TT_LOG_I(TAG, "Starting"); + + const esp_lcd_panel_io_spi_config_t panel_io_config = { + .cs_gpio_num = configuration->csPin, + .dc_gpio_num = configuration->dcPin, + .spi_mode = 0, + .pclk_hz = configuration->pixelClockFrequency, + .trans_queue_depth = configuration->transactionQueueDepth, + .on_color_trans_done = nullptr, + .user_ctx = nullptr, + .lcd_cmd_bits = 8, + .lcd_param_bits = 8, + .cs_ena_pretrans = 0, + .cs_ena_posttrans = 0, + .flags = { + .dc_high_on_cmd = 0, + .dc_low_on_data = 0, + .dc_low_on_param = 0, + .octal_mode = 0, + .quad_mode = 0, + .sio_mode = 1, + .lsb_first = 0, + .cs_high_active = 0 + } + }; + + if (esp_lcd_new_panel_io_spi(configuration->spiBusHandle, &panel_io_config, &ioHandle) != ESP_OK) { + TT_LOG_E(TAG, "Failed to create panel"); + return false; + } + + const esp_lcd_panel_dev_config_t panel_config = { + .reset_gpio_num = configuration->resetPin, + .rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB, + .data_endian = LCD_RGB_DATA_ENDIAN_LITTLE, + .bits_per_pixel = 16, + .flags = { + .reset_active_high = false + }, + .vendor_config = nullptr + }; + + if (esp_lcd_new_panel_st7789(ioHandle, &panel_config, &panelHandle) != ESP_OK) { + TT_LOG_E(TAG, "Failed to create panel"); + return false; + } + + if (esp_lcd_panel_reset(panelHandle) != ESP_OK) { + TT_LOG_E(TAG, "Failed to reset panel"); + return false; + } + + if (esp_lcd_panel_init(panelHandle) != ESP_OK) { + TT_LOG_E(TAG, "Failed to init panel"); + return false; + } + + if (esp_lcd_panel_invert_color(panelHandle, true) != ESP_OK) { + TT_LOG_E(TAG, "Failed to set panel to invert"); + return false; + } + + if (esp_lcd_panel_swap_xy(panelHandle, true) != ESP_OK) { + TT_LOG_E(TAG, "Failed to swap XY "); + return false; + } + + if (esp_lcd_panel_mirror(panelHandle, true, false) != ESP_OK) { + TT_LOG_E(TAG, "Failed to set panel to mirror"); + return false; + } + + if (esp_lcd_panel_disp_on_off(panelHandle, true) != ESP_OK) { + TT_LOG_E(TAG, "Failed to turn display on"); + return false; + } + uint32_t buffer_size; + if (configuration->bufferSize == 0) { + buffer_size = configuration->horizontalResolution * configuration->verticalResolution / 10; + } else { + buffer_size = configuration->bufferSize; + } + + const lvgl_port_display_cfg_t disp_cfg = { + .io_handle = ioHandle, + .panel_handle = panelHandle, + .control_handle = nullptr, + .buffer_size = buffer_size, + .double_buffer = false, + .trans_size = 0, + .hres = configuration->horizontalResolution, + .vres = configuration->verticalResolution, + .monochrome = false, + .rotation = { + .swap_xy = true, + .mirror_x = true, + .mirror_y = false, + }, + .color_format = LV_COLOR_FORMAT_RGB565, + .flags = { + .buff_dma = true, + .buff_spiram = false, + .sw_rotate = false, + .swap_bytes = false, + .full_refresh = false, + .direct_mode = false + } + }; + + displayHandle = lvgl_port_add_disp(&disp_cfg); + + TT_LOG_I(TAG, "Finished"); + return displayHandle != nullptr; +} + +bool St7789Display::stop() { + assert(displayHandle != nullptr); + + lvgl_port_remove_disp(displayHandle); + + if (esp_lcd_panel_del(panelHandle) != ESP_OK) { + return false; + } + + if (esp_lcd_panel_io_del(ioHandle) != ESP_OK) { + return false; + } + + displayHandle = nullptr; + return true; +} + +/** + * Note: + * The datasheet implies this should work, but it doesn't: + * https://www.digikey.com/htmldatasheets/production/1640716/0/0/1/ILI9341-Datasheet.pdf + * + * This repo claims it only has 1 curve: + * https://github.com/brucemack/hello-ili9341 + * + * I'm leaving it in as I'm not sure if it's just my hardware that's problematic. + */ +void St7789Display::setGammaCurve(uint8_t index) { + uint8_t gamma_curve; + switch (index) { + case 0: + gamma_curve = 0x01; + break; + case 1: + gamma_curve = 0x04; + break; + case 2: + gamma_curve = 0x02; + break; + case 3: + gamma_curve = 0x08; + break; + default: + return; + } + const uint8_t param[] = { + gamma_curve + }; + + if (esp_lcd_panel_io_tx_param(ioHandle , LCD_CMD_GAMSET, param, 1) != ESP_OK) { + TT_LOG_E(TAG, "Failed to set gamma"); + } +} diff --git a/Drivers/ST7789/Source/St7789Display.h b/Drivers/ST7789/Source/St7789Display.h new file mode 100644 index 00000000..820b3382 --- /dev/null +++ b/Drivers/ST7789/Source/St7789Display.h @@ -0,0 +1,84 @@ +#pragma once + +#include "Tactility/hal/display/DisplayDevice.h" + +#include +#include +#include +#include +#include +#include + +class St7789Display final : public tt::hal::display::DisplayDevice { + +public: + + class Configuration { + + public: + + Configuration( + esp_lcd_spi_bus_handle_t spi_bus_handle, + gpio_num_t csPin, + gpio_num_t dcPin, + unsigned int horizontalResolution, + unsigned int verticalResolution, + std::shared_ptr touch + ) : spiBusHandle(spi_bus_handle), + csPin(csPin), + dcPin(dcPin), + horizontalResolution(horizontalResolution), + verticalResolution(verticalResolution), + touch(std::move(touch)) + {} + + esp_lcd_spi_bus_handle_t spiBusHandle; + gpio_num_t csPin; + gpio_num_t dcPin; + gpio_num_t resetPin = GPIO_NUM_NC; + unsigned int pixelClockFrequency = 80'000'000; // Hertz + size_t transactionQueueDepth = 10; + unsigned int horizontalResolution; + unsigned int verticalResolution; + uint32_t bufferSize = 0; // Size in pixel count. 0 means default, which is 1/10 of the screen size + std::shared_ptr touch; + std::function _Nullable backlightDutyFunction = nullptr; + }; + +private: + + std::unique_ptr configuration; + esp_lcd_panel_io_handle_t ioHandle = nullptr; + esp_lcd_panel_handle_t panelHandle = nullptr; + lv_display_t* displayHandle = nullptr; + +public: + + explicit St7789Display(std::unique_ptr inConfiguration) : configuration(std::move(inConfiguration)) { + assert(configuration != nullptr); + } + + std::string getName() const final { return "ST7789"; } + std::string getDescription() const final { return "ST7789 display"; } + + bool start() final; + + bool stop() final; + + std::shared_ptr _Nullable createTouch() final { return configuration->touch; } + + void setBacklightDuty(uint8_t backlightDuty) final { + if (configuration->backlightDutyFunction != nullptr) { + configuration->backlightDutyFunction(backlightDuty); + } + } + + bool supportsBacklightDuty() const final { return configuration->backlightDutyFunction != nullptr; } + + void setGammaCurve(uint8_t index) final; + uint8_t getGammaCurveCount() const final { return 4; }; + + lv_display_t* _Nullable getLvglDisplay() const final { return displayHandle; } +}; + +std::shared_ptr createDisplay(); diff --git a/Tactility/Source/app/boot/Boot.cpp b/Tactility/Source/app/boot/Boot.cpp index e77aa6b1..41cbd2ef 100644 --- a/Tactility/Source/app/boot/Boot.cpp +++ b/Tactility/Source/app/boot/Boot.cpp @@ -43,7 +43,11 @@ private: assert(hal_display != nullptr); if (hal_display->supportsBacklightDuty()) { int32_t backlight_duty = app::display::getBacklightDuty(); + TT_LOG_I(TAG, "backlight %ld", backlight_duty); hal_display->setBacklightDuty(backlight_duty); + } else { + + TT_LOG_I(TAG, "no backlight"); } if (hal::usb::isUsbBootMode()) { diff --git a/TactilityHeadless/Include/Tactility/hal/sdcard/SpiSdCardDevice.h b/TactilityHeadless/Include/Tactility/hal/sdcard/SpiSdCardDevice.h index e6fd2c99..3a66b106 100644 --- a/TactilityHeadless/Include/Tactility/hal/sdcard/SpiSdCardDevice.h +++ b/TactilityHeadless/Include/Tactility/hal/sdcard/SpiSdCardDevice.h @@ -26,7 +26,7 @@ public: gpio_num_t spiPinWp, gpio_num_t spiPinInt, MountBehaviour mountBehaviourAtBoot, - std::shared_ptr lockable = std::make_shared(), + std::shared_ptr lock = std::make_shared(), std::vector csPinWorkAround = std::vector(), spi_host_device_t spiHost = SPI2_HOST, int spiFrequencyKhz = SDMMC_FREQ_DEFAULT @@ -36,11 +36,11 @@ public: spiPinWp(spiPinWp), spiPinInt(spiPinInt), mountBehaviourAtBoot(mountBehaviourAtBoot), - lockable(std::move(lockable)), + lock(std::move(lock)), csPinWorkAround(std::move(csPinWorkAround)), spiHost(spiHost) { - assert(this->lockable != nullptr); + assert(this->lock != nullptr); } int spiFrequencyKhz; @@ -49,7 +49,7 @@ public: gpio_num_t spiPinWp; // Write-protect gpio_num_t spiPinInt; // Interrupt SdCardDevice::MountBehaviour mountBehaviourAtBoot; - std::shared_ptr _Nullable lockable; + std::shared_ptr _Nullable lock; std::vector csPinWorkAround; spi_host_device_t spiHost; bool formatOnMountFailed = false; @@ -80,7 +80,7 @@ public: bool unmount() final; std::string getMountPath() const final { return mountPath; } - Lock& getLock() const final { return *config->lockable; } + Lock& getLock() const final { return *config->lock; } State getState() const override; diff --git a/TactilityHeadless/Source/hal/sdcard/SpiSdCard.cpp b/TactilityHeadless/Source/hal/sdcard/SpiSdCard.cpp index 97b16363..36729a5a 100644 --- a/TactilityHeadless/Source/hal/sdcard/SpiSdCard.cpp +++ b/TactilityHeadless/Source/hal/sdcard/SpiSdCard.cpp @@ -134,8 +134,8 @@ SdCardDevice::State SpiSdCardDevice::getState() const { * Writing and reading to the bus from 2 devices at the same time causes crashes. * This work-around ensures that this check is only happening when LVGL isn't rendering. */ - if (config->lockable) { - bool locked = config->lockable->lock(50); // TODO: Refactor to a more reliable locking mechanism + if (config->lock) { + bool locked = config->lock->lock(50); // TODO: Refactor to a more reliable locking mechanism if (!locked) { TT_LOG_E(TAG, LOG_MESSAGE_MUTEX_LOCK_FAILED_FMT, "LVGL"); return State::Unknown; @@ -144,8 +144,8 @@ SdCardDevice::State SpiSdCardDevice::getState() const { bool result = sdmmc_get_status(card) == ESP_OK; - if (config->lockable) { - config->lockable->unlock(); + if (config->lock) { + config->lock->unlock(); } if (result) { diff --git a/TactilityHeadless/Source/service/wifi/WifiEsp.cpp b/TactilityHeadless/Source/service/wifi/WifiEsp.cpp index b2e332a6..40728b60 100644 --- a/TactilityHeadless/Source/service/wifi/WifiEsp.cpp +++ b/TactilityHeadless/Source/service/wifi/WifiEsp.cpp @@ -381,7 +381,7 @@ static bool copy_scan_list(std::shared_ptr wifi) { } auto lock = wifi->dataMutex.asScopedLock(); - if (lock.lock()) { + if (!lock.lock()) { return false; } diff --git a/sdkconfig.board.elecrow-crowpanel-advance-28 b/sdkconfig.board.elecrow-crowpanel-advance-28 new file mode 100644 index 00000000..3fffe971 --- /dev/null +++ b/sdkconfig.board.elecrow-crowpanel-advance-28 @@ -0,0 +1,55 @@ +# Software defaults +# Increase stack size for WiFi (fixes crash after scan) +CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=3072 +CONFIG_LV_FONT_MONTSERRAT_14=y +CONFIG_LV_FONT_MONTSERRAT_18=y +CONFIG_LV_USE_USER_DATA=y +CONFIG_LV_USE_FS_STDIO=y +CONFIG_LV_FS_STDIO_LETTER=65 +CONFIG_LV_FS_STDIO_PATH="" +CONFIG_LV_FS_STDIO_CACHE_SIZE=4096 +CONFIG_LV_USE_LODEPNG=y +CONFIG_LV_USE_BUILTIN_MALLOC=n +CONFIG_LV_USE_CLIB_MALLOC=y +CONFIG_LV_USE_MSGBOX=n +CONFIG_LV_USE_SPINNER=n +CONFIG_LV_USE_WIN=n +CONFIG_LV_USE_SNAPSHOT=y +CONFIG_FREERTOS_HZ=1000 +CONFIG_FREERTOS_TASK_NOTIFICATION_ARRAY_ENTRIES=2 +CONFIG_FREERTOS_SMP=n +CONFIG_FREERTOS_UNICORE=n +CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=4096 +CONFIG_FREERTOS_USE_TRACE_FACILITY=y +CONFIG_PARTITION_TABLE_CUSTOM=y +CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv" +CONFIG_PARTITION_TABLE_FILENAME="partitions.csv" +CONFIG_ELF_LOADER_CUSTOMER_SYMBOLS=y +CONFIG_FATFS_LFN_HEAP=y +CONFIG_FATFS_VOLUME_COUNT=3 + +# Hardware: Main +CONFIG_TT_BOARD_ELECROW_CROWPANEL_ADVANCE_28=y +CONFIG_TT_BOARD_NAME="CrowPanel Advance 2.8" +CONFIG_TT_BOARD_ID="crowpanel-advance-28" +CONFIG_IDF_EXPERIMENTAL_FEATURES=y +CONFIG_IDF_TARGET="esp32s3" +CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y +CONFIG_ESP32_DEFAULT_CPU_FREQ_240=y +CONFIG_ESPTOOLPY_FLASHSIZE_16MB=y +CONFIG_FLASHMODE_QIO=y +# Hardware: SPI RAM +CONFIG_ESP32S3_SPIRAM_SUPPORT=y +CONFIG_SPIRAM_MODE_OCT=y +CONFIG_SPIRAM_SPEED_120M=y +CONFIG_SPIRAM_USE_MALLOC=y +CONFIG_SPIRAM_TRY_ALLOCATE_WIFI_LWIP=y +# SPI Flash (can set back to 80MHz after ESP-IDF bug is resolved) +CONFIG_ESPTOOLPY_FLASHFREQ_120M=y +# LVGL +# TODO: Update DPI +CONFIG_LV_DPI_DEF=139 +CONFIG_LV_DISP_DEF_REFR_PERIOD=10 +# USB +CONFIG_TINYUSB_MSC_ENABLED=y +CONFIG_TINYUSB_MSC_MOUNT_PATH="/sdcard" \ No newline at end of file