From c74006f8b63e3aa9188cc2551ff2cbf16479deb5 Mon Sep 17 00:00:00 2001 From: Ken Van Hoeylandt Date: Sat, 8 Feb 2025 18:54:09 +0100 Subject: [PATCH] Created Drivers folder with ILI934x subproject (#209) Refactored all existing boards to re-use the ILI934x driver code. --- Boards/CYD-2432S024C/CMakeLists.txt | 2 +- .../Source/hal/YellowDisplay.cpp | 160 ++------------- .../CYD-2432S024C/Source/hal/YellowDisplay.h | 33 +-- Boards/LilygoTdeck/Source/hal/TdeckDisplay.h | 2 - Boards/M5stackCore2/CMakeLists.txt | 2 +- Boards/M5stackCore2/README.md | 2 - Boards/M5stackCore2/Source/M5stackCore2.cpp | 5 +- .../M5stackCore2/Source/hal/Core2Display.cpp | 169 ++------------- Boards/M5stackCore2/Source/hal/Core2Display.h | 39 +--- .../Source/hal/Core2DisplayConstants.h | 11 - Boards/M5stackCoreS3/CMakeLists.txt | 2 +- Boards/M5stackCoreS3/README.md | 2 - Boards/M5stackCoreS3/Source/InitBoot.cpp | 3 +- .../Source/hal/CoreS3Display.cpp | 192 ++---------------- .../M5stackCoreS3/Source/hal/CoreS3Display.h | 32 --- .../M5stackCoreS3/Source/hal/CoreS3Power.cpp | 2 - .../M5stackCoreS3/Source/hal/CoreS3Touch.cpp | 8 +- Boards/Simulator/Source/LvglTask.cpp | 4 +- Boards/Simulator/Source/hal/SdlDisplay.h | 2 + Boards/UnPhone/Source/hal/UnPhoneDisplay.h | 2 - CMakeLists.txt | 3 +- Drivers/ILI934x/CMakeLists.txt | 5 + Drivers/ILI934x/README.md | 3 + Drivers/ILI934x/Source/Ili934xDisplay.cpp | 174 ++++++++++++++++ Drivers/ILI934x/Source/Ili934xDisplay.h | 87 ++++++++ Tactility/Source/app/boot/Boot.cpp | 8 +- Tactility/Source/app/display/Display.cpp | 11 +- 27 files changed, 355 insertions(+), 610 deletions(-) delete mode 100644 Boards/M5stackCore2/Source/hal/Core2DisplayConstants.h create mode 100644 Drivers/ILI934x/CMakeLists.txt create mode 100644 Drivers/ILI934x/README.md create mode 100644 Drivers/ILI934x/Source/Ili934xDisplay.cpp create mode 100644 Drivers/ILI934x/Source/Ili934xDisplay.h diff --git a/Boards/CYD-2432S024C/CMakeLists.txt b/Boards/CYD-2432S024C/CMakeLists.txt index 20e8d511..302d1395 100644 --- a/Boards/CYD-2432S024C/CMakeLists.txt +++ b/Boards/CYD-2432S024C/CMakeLists.txt @@ -1,5 +1,5 @@ idf_component_register( SRC_DIRS "Source" "Source/hal" INCLUDE_DIRS "Source" - REQUIRES Tactility esp_lvgl_port esp_lcd_touch_cst816s esp_lcd_ili9341 driver vfs fatfs + REQUIRES Tactility esp_lvgl_port esp_lcd_touch_cst816s ILI934x driver vfs fatfs ) diff --git a/Boards/CYD-2432S024C/Source/hal/YellowDisplay.cpp b/Boards/CYD-2432S024C/Source/hal/YellowDisplay.cpp index 93893f99..3ad003a4 100644 --- a/Boards/CYD-2432S024C/Source/hal/YellowDisplay.cpp +++ b/Boards/CYD-2432S024C/Source/hal/YellowDisplay.cpp @@ -1,4 +1,5 @@ #include "YellowDisplay.h" +#include "Ili934xDisplay.h" #include "YellowDisplayConstants.h" #include "YellowTouch.h" @@ -58,106 +59,7 @@ static bool setBacklight(uint8_t duty) { return true; } -bool YellowDisplay::start() { - TT_LOG_I(TAG, "Starting"); - - const esp_lcd_panel_io_spi_config_t panel_io_config = ILI9341_PANEL_IO_SPI_CONFIG( - TWODOTFOUR_LCD_PIN_CS, - TWODOTFOUR_LCD_PIN_DC, - nullptr, - nullptr - ); - - if (esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)TWODOTFOUR_LCD_SPI_HOST, &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 = GPIO_NUM_NC, - .rgb_ele_order = LCD_RGB_ELEMENT_ORDER_BGR, - .data_endian = LCD_RGB_DATA_ENDIAN_LITTLE, - .bits_per_pixel = TWODOTFOUR_LCD_BITS_PER_PIXEL, - .flags = { - .reset_active_high = false - }, - .vendor_config = nullptr - }; - - if (esp_lcd_new_panel_ili9341(ioHandle, &panel_config, &panelHandle) != ESP_OK) { - TT_LOG_E(TAG, "Failed to create ili9341"); - 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_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; - } - - const lvgl_port_display_cfg_t disp_cfg = { - .io_handle = ioHandle, - .panel_handle = panelHandle, - .control_handle = nullptr, - .buffer_size = TWODOTFOUR_LCD_DRAW_BUFFER_SIZE, - .double_buffer = false, - .trans_size = 0, - .hres = TWODOTFOUR_LCD_HORIZONTAL_RESOLUTION, - .vres = TWODOTFOUR_LCD_VERTICAL_RESOLUTION, - .monochrome = false, - .rotation = { - .swap_xy = false, - .mirror_x = true, - .mirror_y = false, - }, - .color_format = LV_COLOR_FORMAT_RGB565, - .flags = { - .buff_dma = true, - .buff_spiram = false, - .sw_rotate = false, - .swap_bytes = true, - .full_refresh = false, - .direct_mode = false - } - }; - - displayHandle = lvgl_port_add_disp(&disp_cfg); - TT_LOG_I(TAG, "Finished"); - return displayHandle != nullptr; -} - -bool YellowDisplay::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 YellowDisplay::setBacklightDuty(uint8_t backlightDuty) { +void setBacklightDuty(uint8_t backlightDuty) { if (!isBacklightInitialized) { tt_check(initBacklight()); isBacklightInitialized = true; @@ -168,47 +70,23 @@ void YellowDisplay::setBacklightDuty(uint8_t backlightDuty) { } } -/** - * 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 YellowDisplay::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 _Nullable YellowDisplay::createTouch() { - return std::make_shared(); -} std::shared_ptr createDisplay() { - return std::make_shared(); + + auto touch = std::make_shared(); + + auto configuration = std::make_unique( + TWODOTFOUR_LCD_SPI_HOST, + TWODOTFOUR_LCD_PIN_CS, + TWODOTFOUR_LCD_PIN_DC, + TWODOTFOUR_LCD_HORIZONTAL_RESOLUTION, + TWODOTFOUR_LCD_VERTICAL_RESOLUTION, + touch + ); + + configuration->mirrorX = true; + configuration->invertColor = false; + configuration->backlightDutyFunction = ::setBacklightDuty; + + return std::make_shared(std::move(configuration)); } diff --git a/Boards/CYD-2432S024C/Source/hal/YellowDisplay.h b/Boards/CYD-2432S024C/Source/hal/YellowDisplay.h index 26ff2834..64a4e0b7 100644 --- a/Boards/CYD-2432S024C/Source/hal/YellowDisplay.h +++ b/Boards/CYD-2432S024C/Source/hal/YellowDisplay.h @@ -1,37 +1,6 @@ #pragma once -#include "lvgl.h" #include -#include "esp_lcd_panel_io.h" - -extern lv_disp_t* displayHandle; - -class YellowDisplay : public tt::hal::Display { - -private: - - esp_lcd_panel_io_handle_t ioHandle = nullptr; - esp_lcd_panel_handle_t panelHandle = nullptr; - lv_display_t* displayHandle = nullptr; - -public: - - std::string getName() const final { return "ILI9341"; } - std::string getDescription() const final { return "SPI display"; } - - bool start() override; - - bool stop() override; - - 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; } -}; +#include std::shared_ptr createDisplay(); diff --git a/Boards/LilygoTdeck/Source/hal/TdeckDisplay.h b/Boards/LilygoTdeck/Source/hal/TdeckDisplay.h index 8e4f8808..ba9293bb 100644 --- a/Boards/LilygoTdeck/Source/hal/TdeckDisplay.h +++ b/Boards/LilygoTdeck/Source/hal/TdeckDisplay.h @@ -4,8 +4,6 @@ #include #include -extern lv_disp_t* displayHandle; - class TdeckDisplay : public tt::hal::Display { private: diff --git a/Boards/M5stackCore2/CMakeLists.txt b/Boards/M5stackCore2/CMakeLists.txt index a81836b5..2e1f3a36 100644 --- a/Boards/M5stackCore2/CMakeLists.txt +++ b/Boards/M5stackCore2/CMakeLists.txt @@ -1,5 +1,5 @@ idf_component_register( SRC_DIRS "Source" "Source/hal" "Source/ft6x36" "Source/axp192" INCLUDE_DIRS "Source" - REQUIRES Tactility esp_lvgl_port esp_lcd esp_lcd_ili9341 driver vfs fatfs + REQUIRES Tactility esp_lvgl_port esp_lcd ILI934x driver vfs fatfs ) diff --git a/Boards/M5stackCore2/README.md b/Boards/M5stackCore2/README.md index 3d538d67..6160285b 100644 --- a/Boards/M5stackCore2/README.md +++ b/Boards/M5stackCore2/README.md @@ -4,8 +4,6 @@ This board implementation concerns the original Core2 hardware and **not** the v Reference implementations: - [ESP-BSP](https://github.com/espressif/esp-bsp/tree/master/bsp/m5stack_core_2) -- [M5Unified](https://github.com/m5stack/M5Unified) -- [M5GFX](https://github.com/m5stack/M5GFX) Docs: - [M5Stack.com](https://docs.m5stack.com/en/core/Core2) diff --git a/Boards/M5stackCore2/Source/M5stackCore2.cpp b/Boards/M5stackCore2/Source/M5stackCore2.cpp index ca9b2114..5408da21 100644 --- a/Boards/M5stackCore2/Source/M5stackCore2.cpp +++ b/Boards/M5stackCore2/Source/M5stackCore2.cpp @@ -1,11 +1,12 @@ #include "M5stackCore2.h" #include "InitBoot.h" -#include "Tactility/lvgl/LvglSync.h" #include "hal/Core2Display.h" -#include "hal/Core2DisplayConstants.h" #include "hal/Core2Power.h" #include "hal/Core2SdCard.h" +#include +#include + #define CORE2_SPI_TRANSFER_SIZE_LIMIT (CORE2_LCD_DRAW_BUFFER_SIZE * LV_COLOR_DEPTH / 8) extern const tt::hal::Configuration m5stack_core2 = { diff --git a/Boards/M5stackCore2/Source/hal/Core2Display.cpp b/Boards/M5stackCore2/Source/hal/Core2Display.cpp index e1e9446e..8615988a 100644 --- a/Boards/M5stackCore2/Source/hal/Core2Display.cpp +++ b/Boards/M5stackCore2/Source/hal/Core2Display.cpp @@ -1,162 +1,19 @@ #include "Core2Display.h" -#include "Core2DisplayConstants.h" #include "Core2Touch.h" -#include -#include -#include -#include -#include -#include -#include - -#define TAG "core2_display" - -bool Core2Display::start() { - TT_LOG_I(TAG, "Starting"); - - const esp_lcd_panel_io_spi_config_t panel_io_config = ILI9341_PANEL_IO_SPI_CONFIG( - CORE2_LCD_PIN_CS, - CORE2_LCD_PIN_DC, - nullptr, - nullptr - ); - - if (esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)CORE2_LCD_SPI_HOST, &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 = GPIO_NUM_NC, - .rgb_ele_order = LCD_RGB_ELEMENT_ORDER_BGR, - .data_endian = LCD_RGB_DATA_ENDIAN_LITTLE, - .bits_per_pixel = CORE2_LCD_BITS_PER_PIXEL, - .flags = { - .reset_active_high = false - }, - .vendor_config = nullptr - }; - - if (esp_lcd_new_panel_ili9341(ioHandle, &panel_config, &panelHandle) != ESP_OK) { - TT_LOG_E(TAG, "Failed to create ili9341"); - 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_mirror(panelHandle, false, false) != ESP_OK) { - TT_LOG_E(TAG, "Failed to set panel to mirror"); - 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_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 = CORE2_LCD_DRAW_BUFFER_SIZE, - .double_buffer = false, - .trans_size = 0, - .hres = CORE2_LCD_HORIZONTAL_RESOLUTION, - .vres = CORE2_LCD_VERTICAL_RESOLUTION, - .monochrome = false, - .rotation = { - .swap_xy = false, - .mirror_x = false, - .mirror_y = false, - }, - .color_format = LV_COLOR_FORMAT_RGB565, - .flags = { - .buff_dma = true, - .buff_spiram = false, - .sw_rotate = false, - .swap_bytes = true, - .full_refresh = false, - .direct_mode = false - } - }; - - displayHandle = lvgl_port_add_disp(&disp_cfg); - TT_LOG_I(TAG, "Finished"); - return displayHandle != nullptr; -} - -bool Core2Display::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 Core2Display::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 _Nullable Core2Display::createTouch() { - return std::make_shared(); -} +#include std::shared_ptr createDisplay() { - return std::make_shared(); + auto touch = std::make_shared(); + + auto configuration = std::make_unique( + CORE2_LCD_SPI_HOST, + CORE2_LCD_PIN_CS, + CORE2_LCD_PIN_DC, + CORE2_LCD_HORIZONTAL_RESOLUTION, + CORE2_LCD_VERTICAL_RESOLUTION, + touch + ); + + return std::make_shared(std::move(configuration)); } diff --git a/Boards/M5stackCore2/Source/hal/Core2Display.h b/Boards/M5stackCore2/Source/hal/Core2Display.h index b0f18b6e..4a035f6c 100644 --- a/Boards/M5stackCore2/Source/hal/Core2Display.h +++ b/Boards/M5stackCore2/Source/hal/Core2Display.h @@ -1,37 +1,14 @@ #pragma once -#include "lvgl.h" #include +#include -#include - -extern lv_disp_t* displayHandle; - -class Core2Display : public tt::hal::Display { - -private: - - esp_lcd_panel_io_handle_t ioHandle = nullptr; - esp_lcd_panel_handle_t panelHandle = nullptr; - lv_display_t* displayHandle = nullptr; - -public: - - std::string getName() const final { return "ILI9342C"; } - std::string getDescription() const final { return "Display (ILI9342C with an ILI9341 driver)"; } - - bool start() override; - - bool stop() override; - - std::shared_ptr _Nullable createTouch() override; - - bool supportsBacklightDuty() const override { return false; } - - void setGammaCurve(uint8_t index) override; - uint8_t getGammaCurveCount() const override { return 4; }; - - lv_display_t* _Nullable getLvglDisplay() const override { return displayHandle; } -}; +#define CORE2_LCD_SPI_HOST SPI2_HOST +#define CORE2_LCD_PIN_CS GPIO_NUM_5 +#define CORE2_LCD_PIN_DC GPIO_NUM_15 +#define CORE2_LCD_HORIZONTAL_RESOLUTION 320 +#define CORE2_LCD_VERTICAL_RESOLUTION 240 +#define CORE2_LCD_DRAW_BUFFER_HEIGHT (CORE2_LCD_VERTICAL_RESOLUTION / 10) +#define CORE2_LCD_DRAW_BUFFER_SIZE (CORE2_LCD_HORIZONTAL_RESOLUTION * CORE2_LCD_DRAW_BUFFER_HEIGHT) std::shared_ptr createDisplay(); diff --git a/Boards/M5stackCore2/Source/hal/Core2DisplayConstants.h b/Boards/M5stackCore2/Source/hal/Core2DisplayConstants.h deleted file mode 100644 index d6e3053a..00000000 --- a/Boards/M5stackCore2/Source/hal/Core2DisplayConstants.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -// Display -#define CORE2_LCD_SPI_HOST SPI2_HOST -#define CORE2_LCD_PIN_CS GPIO_NUM_5 -#define CORE2_LCD_PIN_DC GPIO_NUM_15 -#define CORE2_LCD_HORIZONTAL_RESOLUTION 320 -#define CORE2_LCD_VERTICAL_RESOLUTION 240 -#define CORE2_LCD_BITS_PER_PIXEL 16 -#define CORE2_LCD_DRAW_BUFFER_HEIGHT (CORE2_LCD_VERTICAL_RESOLUTION / 10) -#define CORE2_LCD_DRAW_BUFFER_SIZE (CORE2_LCD_HORIZONTAL_RESOLUTION * CORE2_LCD_DRAW_BUFFER_HEIGHT) diff --git a/Boards/M5stackCoreS3/CMakeLists.txt b/Boards/M5stackCoreS3/CMakeLists.txt index 2248d676..9d0e9cb6 100644 --- a/Boards/M5stackCoreS3/CMakeLists.txt +++ b/Boards/M5stackCoreS3/CMakeLists.txt @@ -1,5 +1,5 @@ idf_component_register( SRC_DIRS "Source" "Source/hal" "Source/Axp2101" "Source/Aw9523" INCLUDE_DIRS "Source" - REQUIRES Tactility esp_lvgl_port esp_lcd esp_lcd_ili9341 esp_lcd_touch_ft5x06 driver vfs fatfs + REQUIRES Tactility esp_lvgl_port esp_lcd esp_lcd_ili9341 ILI934x esp_lcd_touch_ft5x06 driver vfs fatfs ) diff --git a/Boards/M5stackCoreS3/README.md b/Boards/M5stackCoreS3/README.md index 4de20c83..e1381612 100644 --- a/Boards/M5stackCoreS3/README.md +++ b/Boards/M5stackCoreS3/README.md @@ -2,8 +2,6 @@ Reference implementations: - [ESP-BSP](https://github.com/espressif/esp-bsp/tree/master/bsp/m5stack_core_s3) -- [M5Unified](https://github.com/m5stack/M5Unified) -- [M5GFX](https://github.com/m5stack/M5GFX) Docs: - [M5Stack.com](https://docs.m5stack.com/en/core/CoreS3) diff --git a/Boards/M5stackCoreS3/Source/InitBoot.cpp b/Boards/M5stackCoreS3/Source/InitBoot.cpp index 1cccc500..14daa942 100644 --- a/Boards/M5stackCoreS3/Source/InitBoot.cpp +++ b/Boards/M5stackCoreS3/Source/InitBoot.cpp @@ -1,4 +1,3 @@ -#include "hal/CoreS3DisplayConstants.h" #include "Axp2101/Axp2101.h" #include "Aw9523/Aw9523.h" @@ -6,7 +5,7 @@ #include #include -#define TAG "core2" +#define TAG "cores3" std::shared_ptr axp2101; std::shared_ptr aw9523; diff --git a/Boards/M5stackCoreS3/Source/hal/CoreS3Display.cpp b/Boards/M5stackCoreS3/Source/hal/CoreS3Display.cpp index 25d568f9..75f0d058 100644 --- a/Boards/M5stackCoreS3/Source/hal/CoreS3Display.cpp +++ b/Boards/M5stackCoreS3/Source/hal/CoreS3Display.cpp @@ -1,179 +1,16 @@ #include "CoreS3Display.h" -#include "CoreS3DisplayConstants.h" -#include -#include -#include - -#include -#include -#include -#include -#include #include "CoreS3Constants.h" #include "CoreS3Touch.h" -#define TAG "cores3_display" +#include +#include -bool CoreS3Display::start() { - TT_LOG_I(TAG, "Starting"); +#include - const esp_lcd_panel_io_spi_config_t panel_io_config = { - .cs_gpio_num = CORES3_LCD_PIN_CS, - .dc_gpio_num = CORES3_LCD_PIN_DC, - .spi_mode = 0, - .pclk_hz = 40000000, - .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 = 0, - .lsb_first = 0, - .cs_high_active = 0 - } - }; +#define TAG "cores3" - if (esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)CORES3_LCD_SPI_HOST, &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 = GPIO_NUM_NC, - .rgb_ele_order = LCD_RGB_ELEMENT_ORDER_BGR, - .data_endian = LCD_RGB_DATA_ENDIAN_LITTLE, - .bits_per_pixel = CORES3_LCD_BITS_PER_PIXEL, - .flags = { - .reset_active_high = false - }, - .vendor_config = nullptr - }; - - if (esp_lcd_new_panel_ili9341(ioHandle, &panel_config, &panelHandle) != ESP_OK) { - TT_LOG_E(TAG, "Failed to create ili9341"); - 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_mirror(panelHandle, false, false) != ESP_OK) { - TT_LOG_E(TAG, "Failed to set panel to mirror"); - 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_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 = CORES3_LCD_DRAW_BUFFER_SIZE, - .double_buffer = false, - .trans_size = 0, - .hres = CORES3_LCD_HORIZONTAL_RESOLUTION, - .vres = CORES3_LCD_VERTICAL_RESOLUTION, - .monochrome = false, - .rotation = { - .swap_xy = false, - .mirror_x = false, - .mirror_y = false, - }, - .color_format = LV_COLOR_FORMAT_RGB565, - .flags = { - .buff_dma = true, - .buff_spiram = false, - .sw_rotate = false, - .swap_bytes = true, - .full_refresh = false, - .direct_mode = false - } - }; - - displayHandle = lvgl_port_add_disp(&disp_cfg); - TT_LOG_I(TAG, "Finished"); - return displayHandle != nullptr; -} - -bool CoreS3Display::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 CoreS3Display::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"); - } -} - -void CoreS3Display::setBacklightDuty(uint8_t backlightDuty) { +void setBacklightDuty(uint8_t backlightDuty) { const uint8_t voltage = 20 + ((8 * backlightDuty) / 255); // [0b00000, 0b11100] - under 20 is too dark // TODO: Refactor to use Axp2102 class with https://github.com/m5stack/M5Unified/blob/b8cfec7fed046242da7f7b8024a4e92004a51ff7/src/utility/AXP2101_Class.cpp#L42 if (!tt::hal::i2c::masterWriteRegister(I2C_NUM_0, AXP2101_ADDRESS, 0x99, &voltage, 1, 1000)) { // Sets DLD01 @@ -181,10 +18,19 @@ void CoreS3Display::setBacklightDuty(uint8_t backlightDuty) { } } -std::shared_ptr _Nullable CoreS3Display::createTouch() { - return std::make_shared(); -} - std::shared_ptr createDisplay() { - return std::make_shared(); + auto touch = std::make_shared(); + + auto configuration = std::make_unique( + SPI3_HOST, + GPIO_NUM_3, + GPIO_NUM_35, + 320, + 240, + touch + ); + + configuration->backlightDutyFunction = ::setBacklightDuty; + + return std::make_shared(std::move(configuration)); } diff --git a/Boards/M5stackCoreS3/Source/hal/CoreS3Display.h b/Boards/M5stackCoreS3/Source/hal/CoreS3Display.h index 00cd9815..5469d3dc 100644 --- a/Boards/M5stackCoreS3/Source/hal/CoreS3Display.h +++ b/Boards/M5stackCoreS3/Source/hal/CoreS3Display.h @@ -1,37 +1,5 @@ #pragma once -#include #include -#include - -extern lv_disp_t* displayHandle; - -class CoreS3Display : public tt::hal::Display { - -private: - - esp_lcd_panel_io_handle_t ioHandle = nullptr; - esp_lcd_panel_handle_t panelHandle = nullptr; - lv_display_t* displayHandle = nullptr; - -public: - - std::string getName() const final { return "ILI9342C"; } - std::string getDescription() const final { return "Display (ILI9342C with an ILI9341 driver)"; } - - bool start() override; - - bool stop() override; - - 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/M5stackCoreS3/Source/hal/CoreS3Power.cpp b/Boards/M5stackCoreS3/Source/hal/CoreS3Power.cpp index 4dcbbca3..9b0ccf46 100644 --- a/Boards/M5stackCoreS3/Source/hal/CoreS3Power.cpp +++ b/Boards/M5stackCoreS3/Source/hal/CoreS3Power.cpp @@ -1,7 +1,5 @@ #include "CoreS3Power.h" -#define TAG "core2_power" - bool CoreS3Power::supportsMetric(MetricType type) const { switch (type) { using enum MetricType; diff --git a/Boards/M5stackCoreS3/Source/hal/CoreS3Touch.cpp b/Boards/M5stackCoreS3/Source/hal/CoreS3Touch.cpp index 56177c20..fd639164 100644 --- a/Boards/M5stackCoreS3/Source/hal/CoreS3Touch.cpp +++ b/Boards/M5stackCoreS3/Source/hal/CoreS3Touch.cpp @@ -6,10 +6,10 @@ #include "esp_lcd_touch.h" #include "esp_lvgl_port.h" -#define TAG "cores3_touch" +#define TAG "cores3" bool CoreS3Touch::start(lv_display_t* display) { - TT_LOG_I(TAG, "Starting"); + TT_LOG_I(TAG, "Touch start"); esp_lcd_panel_io_i2c_config_t touch_io_config = ESP_LCD_TOUCH_IO_I2C_FT5x06_CONFIG(); @@ -39,7 +39,7 @@ bool CoreS3Touch::start(lv_display_t* display) { }; if (esp_lcd_touch_new_i2c_ft5x06(ioHandle, &config, &touchHandle) != ESP_OK) { - TT_LOG_E(TAG, "Driver init failed"); + TT_LOG_E(TAG, "Touch driver init failed"); cleanup(); return false; } @@ -51,7 +51,7 @@ bool CoreS3Touch::start(lv_display_t* display) { deviceHandle = lvgl_port_add_touch(&touch_cfg); if (deviceHandle == nullptr) { - TT_LOG_E(TAG, "Adding touch failed"); + TT_LOG_E(TAG, "Touch lvgl port failure"); cleanup(); return false; } diff --git a/Boards/Simulator/Source/LvglTask.cpp b/Boards/Simulator/Source/LvglTask.cpp index 5876bf43..cb1274b7 100644 --- a/Boards/Simulator/Source/LvglTask.cpp +++ b/Boards/Simulator/Source/LvglTask.cpp @@ -17,6 +17,8 @@ static uint32_t task_max_sleep_ms = 10; // Mutex for LVGL task state (to modify task_running state) static bool task_running = false; +lv_disp_t* displayHandle = nullptr; + static void lvgl_task(void* arg); static bool task_lock(TickType_t timeout) { @@ -72,8 +74,6 @@ void lvgl_task_start() { assert(task_result == pdTRUE); } -lv_disp_t* displayHandle = nullptr; - static void lvgl_task(TT_UNUSED void* arg) { TT_LOG_I(TAG, "lvgl task started"); diff --git a/Boards/Simulator/Source/hal/SdlDisplay.h b/Boards/Simulator/Source/hal/SdlDisplay.h index 13f64882..bb522651 100644 --- a/Boards/Simulator/Source/hal/SdlDisplay.h +++ b/Boards/Simulator/Source/hal/SdlDisplay.h @@ -4,9 +4,11 @@ #include #include +/** Hack: variable comes from LvglTask.cpp */ extern lv_disp_t* displayHandle; class SdlDisplay final : public tt::hal::Display { + public: std::string getName() const final { return "SDL Display"; } diff --git a/Boards/UnPhone/Source/hal/UnPhoneDisplay.h b/Boards/UnPhone/Source/hal/UnPhoneDisplay.h index 84e87d3d..079adbd9 100644 --- a/Boards/UnPhone/Source/hal/UnPhoneDisplay.h +++ b/Boards/UnPhone/Source/hal/UnPhoneDisplay.h @@ -4,8 +4,6 @@ #include #include -extern lv_disp_t* displayHandle; - class UnPhoneDisplay : public tt::hal::Display { private: diff --git a/CMakeLists.txt b/CMakeLists.txt index 01c35fbb..e5b038cb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,8 +17,9 @@ if (DEFINED ENV{ESP_IDF_VERSION}) set(COMPONENTS App) set(EXTRA_COMPONENT_DIRS - "Boards" "App" + "Boards" + "Drivers" "Tactility" "TactilityC" "TactilityCore" diff --git a/Drivers/ILI934x/CMakeLists.txt b/Drivers/ILI934x/CMakeLists.txt new file mode 100644 index 00000000..ac5bb4bf --- /dev/null +++ b/Drivers/ILI934x/CMakeLists.txt @@ -0,0 +1,5 @@ +idf_component_register( + SRC_DIRS "Source" + INCLUDE_DIRS "Source" + REQUIRES Tactility esp_lvgl_port esp_lcd esp_lcd_ili9341 driver +) diff --git a/Drivers/ILI934x/README.md b/Drivers/ILI934x/README.md new file mode 100644 index 00000000..a8760892 --- /dev/null +++ b/Drivers/ILI934x/README.md @@ -0,0 +1,3 @@ +# ILI934x + +A basic ESP32 LVGL driver for ILI9341 and ILI9342 displays. diff --git a/Drivers/ILI934x/Source/Ili934xDisplay.cpp b/Drivers/ILI934x/Source/Ili934xDisplay.cpp new file mode 100644 index 00000000..5ebe4b4d --- /dev/null +++ b/Drivers/ILI934x/Source/Ili934xDisplay.cpp @@ -0,0 +1,174 @@ +#include "Ili934xDisplay.h" + +#include + +#include +#include +#include + +#define TAG "ili934x" + + +bool Ili934xDisplay::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 = 0, + .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_BGR, + .data_endian = LCD_RGB_DATA_ENDIAN_LITTLE, + .bits_per_pixel = 16, + .flags = { + .reset_active_high = false + }, + .vendor_config = nullptr + }; + + if (esp_lcd_new_panel_ili9341(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_mirror(panelHandle, configuration->mirrorX, configuration->mirrorY) != ESP_OK) { + TT_LOG_E(TAG, "Failed to set panel to mirror"); + return false; + } + + if (esp_lcd_panel_invert_color(panelHandle, configuration->invertColor) != ESP_OK) { + TT_LOG_E(TAG, "Failed to set panel to invert"); + 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 = false, + .mirror_x = configuration->mirrorX, + .mirror_y = configuration->mirrorY, + }, + .color_format = LV_COLOR_FORMAT_RGB565, + .flags = { + .buff_dma = true, + .buff_spiram = false, + .sw_rotate = false, + .swap_bytes = true, + .full_refresh = false, + .direct_mode = false + } + }; + + displayHandle = lvgl_port_add_disp(&disp_cfg); + TT_LOG_I(TAG, "Finished"); + return displayHandle != nullptr; +} + +bool Ili934xDisplay::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 Ili934xDisplay::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/ILI934x/Source/Ili934xDisplay.h b/Drivers/ILI934x/Source/Ili934xDisplay.h new file mode 100644 index 00000000..7a87d3eb --- /dev/null +++ b/Drivers/ILI934x/Source/Ili934xDisplay.h @@ -0,0 +1,87 @@ +#pragma once + +#include + +#include +#include +#include +#include +#include +#include + +class Ili934xDisplay final : public tt::hal::Display { + +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 = 40'000'000; // Hertz + size_t transactionQueueDepth = 10; + unsigned int horizontalResolution; + unsigned int verticalResolution; + bool mirrorX = false; + bool mirrorY = false; + bool invertColor = true; + 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 Ili934xDisplay(std::unique_ptr inConfiguration) : configuration(std::move(inConfiguration)) { + assert(configuration != nullptr); + } + + std::string getName() const final { return "ILI934x"; } + std::string getDescription() const final { return "ILI934x 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 e6e36513..9a011076 100644 --- a/Tactility/Source/app/boot/Boot.cpp +++ b/Tactility/Source/app/boot/Boot.cpp @@ -24,6 +24,10 @@ namespace tt::app::boot { +static std::shared_ptr getHalDisplay() { + return hal::findFirstDevice(hal::Device::Type::Display); +} + class BootApp : public App { private: @@ -35,9 +39,7 @@ private: kernel::systemEventPublish(kernel::SystemEvent::BootSplash); - auto* lvgl_display = lv_display_get_default(); - assert(lvgl_display != nullptr); - auto* hal_display = (hal::Display*)lv_display_get_user_data(lvgl_display); + auto hal_display = getHalDisplay(); assert(hal_display != nullptr); if (hal_display->supportsBacklightDuty()) { int32_t backlight_duty = app::display::getBacklightDuty(); diff --git a/Tactility/Source/app/display/Display.cpp b/Tactility/Source/app/display/Display.cpp index f001dbaa..9094edf3 100644 --- a/Tactility/Source/app/display/Display.cpp +++ b/Tactility/Source/app/display/Display.cpp @@ -22,13 +22,14 @@ static uint8_t gamma = 255; #define ROTATION_270 2 #define ROTATION_90 3 +static std::shared_ptr getHalDisplay() { + return hal::findFirstDevice(hal::Device::Type::Display); +} static void onBacklightSliderEvent(lv_event_t* event) { auto* slider = static_cast(lv_event_get_target(event)); - auto* lvgl_display = lv_display_get_default(); - assert(lvgl_display != nullptr); - auto* hal_display = (tt::hal::Display*)lv_display_get_user_data(lvgl_display); + auto hal_display = getHalDisplay(); assert(hal_display != nullptr); if (hal_display->supportsBacklightDuty()) { @@ -57,10 +58,6 @@ static void onGammaSliderEvent(lv_event_t* event) { } } -static std::shared_ptr getHalDisplay() { - return hal::findFirstDevice(hal::Device::Type::Display); -} - static lv_display_rotation_t orientationSettingToDisplayRotation(uint32_t setting) { if (setting == ROTATION_180) { return LV_DISPLAY_ROTATION_180;