From 67b9fc710a99460cfd9b050b7c9764a62485be63 Mon Sep 17 00:00:00 2001 From: Ken Van Hoeylandt Date: Thu, 7 Nov 2024 23:17:26 +0100 Subject: [PATCH] M5stack CoreS3 support (#71) --- .github/workflows/esp.yml | 15 +++ CMakeLists.txt | 1 + README.md | 1 + app-esp/CMakeLists.txt | 1 + app-esp/Kconfig | 2 + app-esp/src/board_config.h | 3 + boards/m5stack_core2/CMakeLists.txt | 2 +- boards/m5stack_core2/private/bootstrap.h | 11 -- boards/m5stack_core2/private/config.h | 24 ---- boards/m5stack_core2/private/display_i.hpp | 15 --- boards/m5stack_core2/private/lvgl_i.h | 13 --- boards/m5stack_core2/private/touch_i.hpp | 11 -- boards/m5stack_core2/source/bootstrap.cpp | 105 ------------------ boards/m5stack_core2/source/display.cpp | 98 ---------------- boards/m5stack_core2/source/m5stack_core2.c | 14 +-- .../{sdcard.c => m5stack_core2_sdcard.c} | 4 +- boards/m5stack_core2/source/touch.cpp | 38 ------- boards/m5stack_cores3/CMakeLists.txt | 6 + .../m5stack_cores3/include/m5stack_cores3.h | 13 +++ boards/m5stack_cores3/private/config.h | 13 +++ boards/m5stack_cores3/source/m5stack_cores3.c | 12 ++ boards/m5stack_cores3/source/m5stack_sdcard.c | 79 +++++++++++++ boards/m5stack_shared/CMakeLists.txt | 5 + .../m5stack_shared/src/m5stack_bootstrap.cpp | 18 +++ .../src/m5stack_lvgl.c} | 18 +-- .../src/m5stack_lvgl_display.cpp | 69 ++++++++++++ .../m5stack_shared/src/m5stack_lvgl_touch.cpp | 37 ++++++ .../src/m5stack_power.cpp} | 2 +- boards/m5stack_shared/src/m5stack_shared.h | 18 +++ sdkconfig.board.m5stack_cores3 | 41 +++++++ 30 files changed, 355 insertions(+), 334 deletions(-) delete mode 100644 boards/m5stack_core2/private/bootstrap.h delete mode 100644 boards/m5stack_core2/private/display_i.hpp delete mode 100644 boards/m5stack_core2/private/lvgl_i.h delete mode 100644 boards/m5stack_core2/private/touch_i.hpp delete mode 100644 boards/m5stack_core2/source/bootstrap.cpp delete mode 100644 boards/m5stack_core2/source/display.cpp rename boards/m5stack_core2/source/{sdcard.c => m5stack_core2_sdcard.c} (96%) delete mode 100644 boards/m5stack_core2/source/touch.cpp create mode 100644 boards/m5stack_cores3/CMakeLists.txt create mode 100644 boards/m5stack_cores3/include/m5stack_cores3.h create mode 100644 boards/m5stack_cores3/private/config.h create mode 100644 boards/m5stack_cores3/source/m5stack_cores3.c create mode 100644 boards/m5stack_cores3/source/m5stack_sdcard.c create mode 100644 boards/m5stack_shared/CMakeLists.txt create mode 100644 boards/m5stack_shared/src/m5stack_bootstrap.cpp rename boards/{m5stack_core2/source/lvgl.c => m5stack_shared/src/m5stack_lvgl.c} (62%) create mode 100644 boards/m5stack_shared/src/m5stack_lvgl_display.cpp create mode 100644 boards/m5stack_shared/src/m5stack_lvgl_touch.cpp rename boards/{m5stack_core2/source/power.cpp => m5stack_shared/src/m5stack_power.cpp} (97%) create mode 100644 boards/m5stack_shared/src/m5stack_shared.h create mode 100644 sdkconfig.board.m5stack_cores3 diff --git a/.github/workflows/esp.yml b/.github/workflows/esp.yml index 6c0a6c5c..9ac94b5a 100644 --- a/.github/workflows/esp.yml +++ b/.github/workflows/esp.yml @@ -61,3 +61,18 @@ jobs: esp_idf_version: v5.2.3 target: esp32 path: './' + build-m5stack-cores3: + runs-on: ubuntu-latest + steps: + - name: checkout repo + uses: actions/checkout@v2 + with: + submodules: recursive + - name: board select + run: cp sdkconfig.board.m5stack_cores3 sdkconfig + - name: build + uses: espressif/esp-idf-ci-action@main + with: + esp_idf_version: v5.2.3 + target: esp32s3 + path: './' diff --git a/CMakeLists.txt b/CMakeLists.txt index ceadf2dc..7fad55dc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,6 +28,7 @@ if (DEFINED ENV{ESP_IDF_VERSION}) if(NOT "${IDF_TARGET}" STREQUAL "esp32") set(EXCLUDE_COMPONENTS "yellow_board_2432s024") set(EXCLUDE_COMPONENTS "m5stack_core2") + set(EXCLUDE_COMPONENTS "m5stack_cores3") endif() # ESP32-S3 boards diff --git a/README.md b/README.md index 90008ec9..9ea334b7 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,7 @@ Predefined configurations are available for: | Device | Screen&Touch | SD card | Power | Other | |------------------------------------------|--------------|---------|-------|----------| | [M5Stack Core2][m5stack] | ✅ | ✅ | ✅ | | +| [M5Stack CoreS3][m5stack] | ✅ | ✅ | ✅ | | | [LilyGo T-Deck][tdeck] | ✅ | ✅ | | Keyboard | | [Waveshare S3 Touch][waveshare_s3_touch] | ✅ | ⏳ | | | | Yellow Board 2432S024C (\*) | ✅ | ✅ | | | diff --git a/app-esp/CMakeLists.txt b/app-esp/CMakeLists.txt index e07c9772..a0c2c55c 100644 --- a/app-esp/CMakeLists.txt +++ b/app-esp/CMakeLists.txt @@ -13,6 +13,7 @@ endif() if("${IDF_TARGET}" STREQUAL "esp32s3") list(APPEND BOARD_COMPONENTS lilygo_tdeck + m5stack_cores3 waveshare_s3_touch ) endif() diff --git a/app-esp/Kconfig b/app-esp/Kconfig index f6477465..12b4116c 100644 --- a/app-esp/Kconfig +++ b/app-esp/Kconfig @@ -12,6 +12,8 @@ menu "Tactility App" bool "LilyGo T-Deck" config TT_BOARD_M5STACK_CORE2 bool "M5Stack Core2" + config TT_BOARD_M5STACK_CORES3 + bool "M5Stack CoreS3" config TT_BOARD_WAVESHARE_S3_TOUCH bool "Waveshare S3 Touch LCD 4.3\"" endchoice diff --git a/app-esp/src/board_config.h b/app-esp/src/board_config.h index 0184abe6..ee393ef9 100644 --- a/app-esp/src/board_config.h +++ b/app-esp/src/board_config.h @@ -12,6 +12,9 @@ #elif defined(CONFIG_TT_BOARD_M5STACK_CORE2) #include "m5stack_core2.h" #define TT_BOARD_HARDWARE &m5stack_core2 +#elif defined(CONFIG_TT_BOARD_M5STACK_CORES3) +#include "m5stack_cores3.h" +#define TT_BOARD_HARDWARE &m5stack_cores3 #elif defined(CONFIG_TT_BOARD_WAVESHARE_S3_TOUCH) #include "waveshare_s3_touch.h" #define TT_BOARD_HARDWARE &waveshare_s3_touch diff --git a/boards/m5stack_core2/CMakeLists.txt b/boards/m5stack_core2/CMakeLists.txt index 5c3a61b5..2dba219b 100644 --- a/boards/m5stack_core2/CMakeLists.txt +++ b/boards/m5stack_core2/CMakeLists.txt @@ -2,5 +2,5 @@ idf_component_register( SRC_DIRS "source" INCLUDE_DIRS "include" PRIV_INCLUDE_DIRS "private" - REQUIRES tactility esp_lvgl_port esp_lcd_ili9341 driver vfs fatfs M5Unified + REQUIRES tactility m5stack_shared vfs fatfs M5Unified ) diff --git a/boards/m5stack_core2/private/bootstrap.h b/boards/m5stack_core2/private/bootstrap.h deleted file mode 100644 index 70c1b355..00000000 --- a/boards/m5stack_core2/private/bootstrap.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -#ifdef __cplusplus -extern "C" { -#endif - -bool core2_bootstrap(); - -#ifdef __cplusplus -} -#endif \ No newline at end of file diff --git a/boards/m5stack_core2/private/config.h b/boards/m5stack_core2/private/config.h index a882213f..2f5ce29f 100644 --- a/boards/m5stack_core2/private/config.h +++ b/boards/m5stack_core2/private/config.h @@ -1,32 +1,8 @@ #pragma once #include "driver/spi_common.h" -#include "driver/i2c.h" #include "driver/gpio.h" -// I2C -#define CORE2_I2C_PIN_SDA 21 -#define CORE2_I2C_PIN_SCL 22 - -// SPI2 - Display, SD -#define CORE2_SPI2_PIN_SCLK GPIO_NUM_18 -#define CORE2_SPI2_PIN_MOSI GPIO_NUM_23 -#define CORE2_SPI2_PIN_MISO GPIO_NUM_38 -#define CORE2_SPI2_TRANSACTION_LIMIT CORE2_LCD_DRAW_BUFFER_SIZE - -// Display -#define CORE2_LCD_SPI_HOST SPI2_HOST -#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 * (CORE2_LCD_BITS_PER_PIXEL / 8)) -#define CORE2_LCD_PIN_CS GPIO_NUM_5 -#define CORE2_LCD_PIN_DC GPIO_NUM_15 - -// Touch -#define CORE2_TOUCH_I2C_PORT I2C_NUM_0 - // SD Card #define CORE2_SDCARD_SPI_HOST SPI2_HOST #define CORE2_SDCARD_PIN_CS GPIO_NUM_4 diff --git a/boards/m5stack_core2/private/display_i.hpp b/boards/m5stack_core2/private/display_i.hpp deleted file mode 100644 index ea846ce1..00000000 --- a/boards/m5stack_core2/private/display_i.hpp +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once - -#include -#include -#include "lvgl.h" - -#ifdef __cplusplus -extern "C" { -#endif - -lv_disp_t* core2_display_init(); - -#ifdef __cplusplus -} -#endif \ No newline at end of file diff --git a/boards/m5stack_core2/private/lvgl_i.h b/boards/m5stack_core2/private/lvgl_i.h deleted file mode 100644 index cb4713e9..00000000 --- a/boards/m5stack_core2/private/lvgl_i.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -bool core2_lvgl_init(); - -#ifdef __cplusplus -} -#endif \ No newline at end of file diff --git a/boards/m5stack_core2/private/touch_i.hpp b/boards/m5stack_core2/private/touch_i.hpp deleted file mode 100644 index 412016c5..00000000 --- a/boards/m5stack_core2/private/touch_i.hpp +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -#ifdef __cplusplus -extern "C" { -#endif - -bool core2_touch_init(); - -#ifdef __cplusplus -} -#endif \ No newline at end of file diff --git a/boards/m5stack_core2/source/bootstrap.cpp b/boards/m5stack_core2/source/bootstrap.cpp deleted file mode 100644 index fc2f0532..00000000 --- a/boards/m5stack_core2/source/bootstrap.cpp +++ /dev/null @@ -1,105 +0,0 @@ -#include "bootstrap.h" - -#include "M5Unified.hpp" -#include "config.h" -#include "log.h" - -m5::IMU_Class& Imu = M5.Imu; -m5::Power_Class& Power = M5.Power; -m5::RTC8563_Class& Rtc = M5.Rtc; -m5::Touch_Class& Touch = M5.Touch; - -m5::Speaker_Class& Speaker = M5.Speaker; - -m5::Button_Class& BtnPWR = M5.BtnPWR; - -#ifdef __cplusplus -extern "C" { -#endif - -#define TAG "core2_bootstrap" - -static bool init_i2c() { - const i2c_config_t i2c_conf = { - .mode = I2C_MODE_MASTER, - .sda_io_num = CORE2_I2C_PIN_SDA, - .scl_io_num = CORE2_I2C_PIN_SCL, - .sda_pullup_en = GPIO_PULLUP_DISABLE, - .scl_pullup_en = GPIO_PULLUP_DISABLE, - .master = { - .clk_speed = 100000 - }, - .clk_flags = 0 - }; - - if (i2c_param_config(CORE2_TOUCH_I2C_PORT, &i2c_conf) != ESP_OK) { - TT_LOG_E(TAG, "i2c config failed"); - return false; - } - - if (i2c_driver_install(CORE2_TOUCH_I2C_PORT, i2c_conf.mode, 0, 0, 0) != ESP_OK) { - TT_LOG_E(TAG, "i2c driver install failed"); - return false; - } - - return true; -} - -static bool init_spi2() { - const spi_bus_config_t bus_config = { - .mosi_io_num = CORE2_SPI2_PIN_MOSI, - .miso_io_num = CORE2_SPI2_PIN_MISO, - .sclk_io_num = CORE2_SPI2_PIN_SCLK, - .data2_io_num = GPIO_NUM_NC, - .data3_io_num = GPIO_NUM_NC, - .data4_io_num = GPIO_NUM_NC, - .data5_io_num = GPIO_NUM_NC, - .data6_io_num = GPIO_NUM_NC, - .data7_io_num = GPIO_NUM_NC, - .max_transfer_sz = CORE2_SPI2_TRANSACTION_LIMIT, - .flags = 0, - .isr_cpu_id = ESP_INTR_CPU_AFFINITY_AUTO, - .intr_flags = 0 - }; - - if (spi_bus_initialize(SPI2_HOST, &bus_config, SPI_DMA_CH_AUTO) != ESP_OK) { - TT_LOG_E(TAG, "SPI bus init failed"); - return false; - } - - return true; -} - -static void log_power_status() { - TT_LOG_I( - TAG, - "Battery: level = %ld, voltage = %.1f, charging = %s", - M5.Power.getBatteryLevel(), - (float)M5.Power.getBatteryVoltage() / 1000.0f, - M5.Power.isCharging() ? "true" : "false" - ); -} - -bool core2_bootstrap() { - TT_LOG_I(TAG, "Initializing M5Unified"); - M5.begin(); - // For models with EPD : refresh control - M5.Display.setEpdMode(epd_mode_t::epd_fastest); // fastest but very-low quality. - log_power_status(); - - TT_LOG_I(TAG, "Initializing I2C"); - if (!init_i2c()) { - return false; - } - - TT_LOG_I(TAG, "Initializing SPI"); - if (!init_spi2()) { - return false; - } - - return true; -} - -#ifdef __cplusplus -} -#endif diff --git a/boards/m5stack_core2/source/display.cpp b/boards/m5stack_core2/source/display.cpp deleted file mode 100644 index 99670c49..00000000 --- a/boards/m5stack_core2/source/display.cpp +++ /dev/null @@ -1,98 +0,0 @@ -#include "config.h" -#include "tactility_core.h" - -#include "esp_err.h" -#include "esp_lcd_ili9341.h" -#include "esp_lcd_panel_io.h" -#include "esp_lcd_panel_ops.h" -#include "esp_lvgl_port.h" - -#define TAG "core2" - -#ifdef __cplusplus -extern "C" { -#endif - -lv_disp_t* core2_display_init() { - TT_LOG_I(TAG, "Display init"); - - 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 - ); - - esp_lcd_panel_io_handle_t io_handle; - if (esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)CORE2_LCD_SPI_HOST, &panel_io_config, &io_handle) != ESP_OK) { - TT_LOG_E(TAG, "Failed to create panel"); - return nullptr; - } - - 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_BIG, - .bits_per_pixel = CORE2_LCD_BITS_PER_PIXEL, - .flags = { - .reset_active_high = false - }, - .vendor_config = nullptr - }; - - esp_lcd_panel_handle_t panel_handle; - if (esp_lcd_new_panel_ili9341(io_handle, &panel_config, &panel_handle) != ESP_OK) { - TT_LOG_E(TAG, "Failed to create ili9341"); - return nullptr; - } - - if (esp_lcd_panel_reset(panel_handle) != ESP_OK) { - TT_LOG_E(TAG, "Failed to reset panel"); - return nullptr; - } - - if (esp_lcd_panel_init(panel_handle) != ESP_OK) { - TT_LOG_E(TAG, "Failed to init panel"); - return nullptr; - } - - if (esp_lcd_panel_invert_color(panel_handle, true) != ESP_OK) { - TT_LOG_E(TAG, "Failed to invert panel colours"); - return nullptr; - } - - if (esp_lcd_panel_disp_on_off(panel_handle, true) != ESP_OK) { - TT_LOG_E(TAG, "Failed to turn display on"); - return nullptr; - } - - const lvgl_port_display_cfg_t disp_cfg = { - .io_handle = io_handle, - .panel_handle = panel_handle, - .buffer_size = CORE2_LCD_DRAW_BUFFER_SIZE, - .double_buffer = false, - .trans_size = CORE2_SPI2_TRANSACTION_LIMIT, - .hres = CORE2_LCD_HORIZONTAL_RESOLUTION, - .vres = CORE2_LCD_VERTICAL_RESOLUTION, - .monochrome = false, - .rotation = { - .swap_xy = false, - .mirror_x = false, - .mirror_y = false, - }, - .flags = { - .buff_dma = false, - .buff_spiram = true, - .sw_rotate = false, - .swap_bytes = true - } - }; - - lv_display_t* display = lvgl_port_add_disp(&disp_cfg); - - return display; -} - -#ifdef __cplusplus -} -#endif diff --git a/boards/m5stack_core2/source/m5stack_core2.c b/boards/m5stack_core2/source/m5stack_core2.c index 90364154..460fd022 100644 --- a/boards/m5stack_core2/source/m5stack_core2.c +++ b/boards/m5stack_core2/source/m5stack_core2.c @@ -1,16 +1,14 @@ #include "m5stack_core2.h" -#include "bootstrap.h" -#include "lvgl_i.h" +#include "m5stack_shared.h" -extern const SdCard core2_sdcard; -extern Power core2_power; // Making it const fails the build +extern const SdCard m5stack_core2_sdcard; const HardwareConfig m5stack_core2 = { - .bootstrap = &core2_bootstrap, + .bootstrap = &m5stack_bootstrap, .display = { .set_backlight_duty = NULL }, - .init_graphics = &core2_lvgl_init, - .sdcard = &core2_sdcard, - .power = &core2_power + .init_graphics = &m5stack_lvgl_init, + .sdcard = &m5stack_core2_sdcard, + .power = &m5stack_power }; diff --git a/boards/m5stack_core2/source/sdcard.c b/boards/m5stack_core2/source/m5stack_core2_sdcard.c similarity index 96% rename from boards/m5stack_core2/source/sdcard.c rename to boards/m5stack_core2/source/m5stack_core2_sdcard.c index 16b8d799..5ce1655d 100644 --- a/boards/m5stack_core2/source/sdcard.c +++ b/boards/m5stack_core2/source/m5stack_core2_sdcard.c @@ -6,7 +6,7 @@ #include "esp_vfs_fat.h" #include "sdmmc_cmd.h" -#define TAG "core2_sdcard" +#define TAG "m5stack_core2_sdcard" typedef struct { const char* mount_point; @@ -71,7 +71,7 @@ static bool sdcard_is_mounted(void* context) { return (data != NULL) && (sdmmc_get_status(data->card) == ESP_OK); } -const SdCard core2_sdcard = { +const SdCard m5stack_core2_sdcard = { .mount = &sdcard_mount, .unmount = &sdcard_unmount, .is_mounted = &sdcard_is_mounted, diff --git a/boards/m5stack_core2/source/touch.cpp b/boards/m5stack_core2/source/touch.cpp deleted file mode 100644 index 14c5a82a..00000000 --- a/boards/m5stack_core2/source/touch.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include "tactility_core.h" -#include "lvgl.h" -#include "M5Unified.hpp" - -#define TAG "core2_touch" - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * Touch seems to be offset by a certain amount. - * The docs don't mention it, so this is the estimated value. - */ -#define TOUCH_Y_OFFSET 16 - -static void read_touch(TT_UNUSED lv_indev_t* indev, lv_indev_data_t* data) { - lgfx::touch_point_t point; // Making it static makes it unreliable - bool touched = M5.Lcd.getTouch(&point) > 0; - if (touched) { - data->point.x = point.x; - data->point.y = point.y - TOUCH_Y_OFFSET; - data->state = LV_INDEV_STATE_PRESSED; - } else { - data->state = LV_INDEV_STATE_RELEASED; - } -} - -bool core2_touch_init() { - lv_indev_t _Nullable* touch_indev = lv_indev_create(); - lv_indev_set_type(touch_indev, LV_INDEV_TYPE_POINTER); - lv_indev_set_read_cb(touch_indev, read_touch); - return true; -} - -#ifdef __cplusplus -} -#endif diff --git a/boards/m5stack_cores3/CMakeLists.txt b/boards/m5stack_cores3/CMakeLists.txt new file mode 100644 index 00000000..2dba219b --- /dev/null +++ b/boards/m5stack_cores3/CMakeLists.txt @@ -0,0 +1,6 @@ +idf_component_register( + SRC_DIRS "source" + INCLUDE_DIRS "include" + PRIV_INCLUDE_DIRS "private" + REQUIRES tactility m5stack_shared vfs fatfs M5Unified +) diff --git a/boards/m5stack_cores3/include/m5stack_cores3.h b/boards/m5stack_cores3/include/m5stack_cores3.h new file mode 100644 index 00000000..d13058cb --- /dev/null +++ b/boards/m5stack_cores3/include/m5stack_cores3.h @@ -0,0 +1,13 @@ +#pragma once + +#include "hardware_config.h" + +#ifdef __cplusplus +extern "C" { +#endif + +extern const HardwareConfig m5stack_cores3; + +#ifdef __cplusplus +} +#endif diff --git a/boards/m5stack_cores3/private/config.h b/boards/m5stack_cores3/private/config.h new file mode 100644 index 00000000..930d7862 --- /dev/null +++ b/boards/m5stack_cores3/private/config.h @@ -0,0 +1,13 @@ +#pragma once + +#include "driver/spi_common.h" +#include "driver/gpio.h" + +// SD Card +#define CORES3_SDCARD_SPI_HOST SPI2_HOST +#define CORES3_SDCARD_PIN_CS GPIO_NUM_4 +#define CORES3_SDCARD_SPI_FREQUENCY 800000U +#define CORES3_SDCARD_FORMAT_ON_MOUNT_FAILED false +#define CORES3_SDCARD_MAX_OPEN_FILES 4 +#define CORES3_SDCARD_ALLOC_UNIT_SIZE (16 * 1024) +#define CORES3_SDCARD_STATUS_CHECK_ENABLED false diff --git a/boards/m5stack_cores3/source/m5stack_cores3.c b/boards/m5stack_cores3/source/m5stack_cores3.c new file mode 100644 index 00000000..a342db07 --- /dev/null +++ b/boards/m5stack_cores3/source/m5stack_cores3.c @@ -0,0 +1,12 @@ +#include "m5stack_cores3.h" +#include "m5stack_shared.h" + +const HardwareConfig m5stack_cores3 = { + .bootstrap = &m5stack_bootstrap, + .display = { + .set_backlight_duty = NULL + }, + .init_graphics = &m5stack_lvgl_init, + .sdcard = &m5stack_sdcard, + .power = &m5stack_power +}; diff --git a/boards/m5stack_cores3/source/m5stack_sdcard.c b/boards/m5stack_cores3/source/m5stack_sdcard.c new file mode 100644 index 00000000..775fe32d --- /dev/null +++ b/boards/m5stack_cores3/source/m5stack_sdcard.c @@ -0,0 +1,79 @@ +#include "sdcard.h" +#include "check.h" +#include "log.h" +#include "config.h" + +#include "esp_vfs_fat.h" +#include "sdmmc_cmd.h" + +#define TAG "m5stack_cores3_sdcard" + +typedef struct { + const char* mount_point; + sdmmc_card_t* card; +} MountData; + +static void* sdcard_mount(const char* mount_point) { + TT_LOG_I(TAG, "Mounting %s", mount_point); + + esp_vfs_fat_sdmmc_mount_config_t mount_config = { + .format_if_mount_failed = CORES3_SDCARD_FORMAT_ON_MOUNT_FAILED, + .max_files = CORES3_SDCARD_MAX_OPEN_FILES, + .allocation_unit_size = CORES3_SDCARD_ALLOC_UNIT_SIZE, + .disk_status_check_enable = CORES3_SDCARD_STATUS_CHECK_ENABLED + }; + + sdmmc_card_t* card; + + // Init without card detect (CD) and write protect (WD) + sdspi_device_config_t slot_config = SDSPI_DEVICE_CONFIG_DEFAULT(); + slot_config.gpio_cs = CORES3_SDCARD_PIN_CS; + slot_config.host_id = CORES3_SDCARD_SPI_HOST; + + sdmmc_host_t host = SDSPI_HOST_DEFAULT(); + host.max_freq_khz = CORES3_SDCARD_SPI_FREQUENCY; + esp_err_t ret = esp_vfs_fat_sdspi_mount(mount_point, &host, &slot_config, &mount_config, &card); + + if (ret != ESP_OK) { + if (ret == ESP_FAIL) { + TT_LOG_E(TAG, "Mounting failed. Ensure the card is formatted with FAT."); + } else { + TT_LOG_E(TAG, "Mounting failed (%s)", esp_err_to_name(ret)); + } + return NULL; + } + + MountData* data = malloc(sizeof(MountData)); + *data = (MountData) { + .card = card, + .mount_point = mount_point + }; + + sdmmc_card_print_info(stdout, data->card); + + return data; +} + +static void sdcard_unmount(void* context) { + MountData* data = (MountData*)context; + TT_LOG_I(TAG, "Unmounting %s", data->mount_point); + + tt_assert(data != NULL); + if (esp_vfs_fat_sdcard_unmount(data->mount_point, data->card) != ESP_OK) { + TT_LOG_E(TAG, "Unmount failed for %s", data->mount_point); + } + + free(data); +} + +static bool sdcard_is_mounted(void* context) { + MountData* data = (MountData*)context; + return (data != NULL) && (sdmmc_get_status(data->card) == ESP_OK); +} + +const SdCard m5stack_sdcard = { + .mount = &sdcard_mount, + .unmount = &sdcard_unmount, + .is_mounted = &sdcard_is_mounted, + .mount_behaviour = SdcardMountBehaviourAnytime +}; diff --git a/boards/m5stack_shared/CMakeLists.txt b/boards/m5stack_shared/CMakeLists.txt new file mode 100644 index 00000000..2822db28 --- /dev/null +++ b/boards/m5stack_shared/CMakeLists.txt @@ -0,0 +1,5 @@ +idf_component_register( + SRC_DIRS "src" + INCLUDE_DIRS "src" + REQUIRES tactility esp_lvgl_port M5Unified +) diff --git a/boards/m5stack_shared/src/m5stack_bootstrap.cpp b/boards/m5stack_shared/src/m5stack_bootstrap.cpp new file mode 100644 index 00000000..bf526c25 --- /dev/null +++ b/boards/m5stack_shared/src/m5stack_bootstrap.cpp @@ -0,0 +1,18 @@ +#include "M5Unified.hpp" +#include "log.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define TAG "m5stack_bootstrap" + +bool m5stack_bootstrap() { + TT_LOG_I(TAG, "Initializing M5Unified"); + M5.begin(); + return true; +} + +#ifdef __cplusplus +} +#endif diff --git a/boards/m5stack_core2/source/lvgl.c b/boards/m5stack_shared/src/m5stack_lvgl.c similarity index 62% rename from boards/m5stack_core2/source/lvgl.c rename to boards/m5stack_shared/src/m5stack_lvgl.c index f31965c1..6f02fb31 100644 --- a/boards/m5stack_core2/source/lvgl.c +++ b/boards/m5stack_shared/src/m5stack_lvgl.c @@ -1,13 +1,14 @@ -#include "display_i.hpp" #include "esp_lvgl_port.h" #include "log.h" #include "thread.h" -#include "touch_i.hpp" #include "ui/lvgl_sync.h" -#define TAG "core2_lvgl" +#define TAG "cores3_lvgl" -bool core2_lvgl_init() { +extern _Nullable lv_disp_t* m5stack_lvgl_display(bool usePsram); +extern _Nullable lv_indev_t* m5stack_lvgl_touch(); + +bool m5stack_lvgl_init() { static lv_display_t* display = NULL; const lvgl_port_cfg_t lvgl_cfg = { @@ -19,21 +20,24 @@ bool core2_lvgl_init() { }; if (lvgl_port_init(&lvgl_cfg) != ESP_OK) { - TT_LOG_E(TAG, "lvgl port init failed"); + TT_LOG_E(TAG, "lvgl_port_init failed"); return false; } // Add display - display = core2_display_init(); + display = m5stack_lvgl_display(true); if (display == NULL) { TT_LOG_E(TAG, "failed to add display"); return false; } // Add touch - if (!core2_touch_init()) { + lv_indev_t* touch_indev = m5stack_lvgl_touch(); + if (touch_indev == NULL) { + TT_LOG_E(TAG, "failed to add touch"); return false; } + lv_indev_set_display(touch_indev, display); // Set syncing functions tt_lvgl_sync_set(&lvgl_port_lock, &lvgl_port_unlock); diff --git a/boards/m5stack_shared/src/m5stack_lvgl_display.cpp b/boards/m5stack_shared/src/m5stack_lvgl_display.cpp new file mode 100644 index 00000000..7b0c7764 --- /dev/null +++ b/boards/m5stack_shared/src/m5stack_lvgl_display.cpp @@ -0,0 +1,69 @@ +#include "tactility_core.h" + +#include "M5Unified.hpp" +#include "esp_err.h" +#include "esp_lvgl_port.h" + +#ifdef __cplusplus +extern "C" { +#endif + +static void flush_callback(lv_display_t* display, const lv_area_t* area, uint8_t* px_map) { + M5GFX& gfx = *(M5GFX*)lv_display_get_driver_data(display); + + int32_t width = (area->x2 - area->x1 + 1); + int32_t height = (area->y2 - area->y1 + 1); + + gfx.startWrite(); + gfx.setAddrWindow(area->x1, area->y1, width, height); + gfx.writePixels((lgfx::rgb565_t*)px_map, width * height); + gfx.endWrite(); + + lv_display_flush_ready(display); +} + + +_Nullable lv_disp_t* m5stack_lvgl_display(bool usePsram) { + M5GFX& gfx = M5.Display; + + static lv_display_t* display = lv_display_create(gfx.width(), gfx.height()); + LV_ASSERT_MALLOC(display) + if (display == nullptr) { + return nullptr; + } + + lv_display_set_driver_data(display, &gfx); + lv_display_set_flush_cb(display, flush_callback); + + const size_t bytes_per_pixel = 2; // assume 16-bit color + const size_t buffer_size = gfx.width() * gfx.height() * bytes_per_pixel / 8; + if (usePsram) { + static auto* buffer1 = (uint8_t*)heap_caps_malloc(buffer_size, MALLOC_CAP_SPIRAM); + LV_ASSERT_MALLOC(buffer1) + static auto* buffer2 = (uint8_t*)heap_caps_malloc(buffer_size, MALLOC_CAP_SPIRAM); + LV_ASSERT_MALLOC(buffer2) + lv_display_set_buffers( + display, + (void*)buffer1, + (void*)buffer2, + buffer_size, + LV_DISPLAY_RENDER_MODE_PARTIAL + ); + } else { + static auto* buffer = (uint8_t*)malloc(buffer_size); + LV_ASSERT_MALLOC(buffer) + lv_display_set_buffers( + display, + (void*)buffer, + nullptr, + buffer_size, + LV_DISPLAY_RENDER_MODE_PARTIAL + ); + } + + return display; +} + +#ifdef __cplusplus +} +#endif diff --git a/boards/m5stack_shared/src/m5stack_lvgl_touch.cpp b/boards/m5stack_shared/src/m5stack_lvgl_touch.cpp new file mode 100644 index 00000000..b50ab18e --- /dev/null +++ b/boards/m5stack_shared/src/m5stack_lvgl_touch.cpp @@ -0,0 +1,37 @@ +#include "M5Unified.hpp" +#include "lvgl.h" +#include "tactility_core.h" + +#define TAG "cores3_touch" + +#ifdef __cplusplus +extern "C" { +#endif + +static void touch_read_callback(TT_UNUSED lv_indev_t* indev, lv_indev_data_t* data) { + lgfx::touch_point_t point; // Making it static makes it unreliable + bool touched = M5.Lcd.getTouch(&point) > 0; + if (!touched) { + data->state = LV_INDEV_STATE_REL; + } else { + data->state = LV_INDEV_STATE_PR; + data->point.x = point.x; + data->point.y = point.y; + } +} + +_Nullable lv_indev_t* m5stack_lvgl_touch() { + static lv_indev_t* indev = lv_indev_create(); + LV_ASSERT_MALLOC(indev) + if (indev == nullptr) { + return nullptr; + } + + lv_indev_set_type(indev, LV_INDEV_TYPE_POINTER); + lv_indev_set_read_cb(indev, touch_read_callback); + return indev; +} + +#ifdef __cplusplus +} +#endif diff --git a/boards/m5stack_core2/source/power.cpp b/boards/m5stack_shared/src/m5stack_power.cpp similarity index 97% rename from boards/m5stack_core2/source/power.cpp rename to boards/m5stack_shared/src/m5stack_power.cpp index 13a16c36..00a46d2f 100644 --- a/boards/m5stack_core2/source/power.cpp +++ b/boards/m5stack_shared/src/m5stack_power.cpp @@ -33,7 +33,7 @@ static int32_t power_get_current() { return M5.Power.getBatteryCurrent(); } -Power core2_power = { +Power m5stack_power = { .is_charging = &power_is_charging, .is_charging_enabled = &power_is_charging_enabled, .set_charging_enabled = &power_set_charging_enabled, diff --git a/boards/m5stack_shared/src/m5stack_shared.h b/boards/m5stack_shared/src/m5stack_shared.h new file mode 100644 index 00000000..7914c5df --- /dev/null +++ b/boards/m5stack_shared/src/m5stack_shared.h @@ -0,0 +1,18 @@ +#pragma once + +#include "power.h" +#include "sdcard.h" + +#ifdef __cplusplus +extern "C" { +#endif + +extern bool m5stack_lvgl_init(); +extern bool m5stack_bootstrap(); + +extern Power m5stack_power; +extern const SdCard m5stack_sdcard; + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/sdkconfig.board.m5stack_cores3 b/sdkconfig.board.m5stack_cores3 new file mode 100644 index 00000000..fbd00b83 --- /dev/null +++ b/sdkconfig.board.m5stack_cores3 @@ -0,0 +1,41 @@ +# Software defaults +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_FREERTOS_HZ=1000 +CONFIG_FREERTOS_TASK_NOTIFICATION_ARRAY_ENTRIES=2 +CONFIG_FREERTOS_SMP=n +CONFIG_FREERTOS_UNICORE=y +CONFIG_PARTITION_TABLE_CUSTOM=y +CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv" +CONFIG_PARTITION_TABLE_FILENAME="partitions.csv" + +# Hardware: Main +CONFIG_TT_BOARD_M5STACK_CORES3=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_SPIRAM=y +CONFIG_SPIRAM_MODE_QUAD=y +CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY=y +CONFIG_SPIRAM_CLK_IO=30 +CONFIG_SPIRAM_CS_IO=26 +CONFIG_SPIRAM_SPEED_40M=y +CONFIG_SPIRAM_SPEED=40 +CONFIG_SPIRAM_BOOT_INIT=y +CONFIG_SPIRAM_USE_MALLOC=y +CONFIG_SPIRAM_TRY_ALLOCATE_WIFI_LWIP=y +# LVGL +CONFIG_LV_DISP_DEF_REFR_PERIOD=17 +CONFIG_LV_INDEV_DEF_READ_PERIOD=17 +CONFIG_LV_DPI_DEF=139