diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6c3441d4..7493cd9b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -62,6 +62,7 @@ jobs: { id: m5stack-cores3, arch: esp32s3 }, { id: m5stack-stickc-plus, arch: esp32 }, { id: m5stack-stickc-plus2, arch: esp32 }, + { id: m5stack-tab5, arch: esp32p4 }, { id: unphone, arch: esp32s3 }, { id: waveshare-esp32-s3-geek, arch: esp32s3 }, { id: waveshare-s3-lcd-13, arch: esp32s3 }, diff --git a/Devices/guition-jc1060p470ciwy/Source/devices/Display.cpp b/Devices/guition-jc1060p470ciwy/Source/devices/Display.cpp index 224dc245..151b05f4 100644 --- a/Devices/guition-jc1060p470ciwy/Source/devices/Display.cpp +++ b/Devices/guition-jc1060p470ciwy/Source/devices/Display.cpp @@ -61,5 +61,5 @@ std::shared_ptr createDisplay() { }); const auto display = std::make_shared(configuration); - return std::reinterpret_pointer_cast(display); + return std::static_pointer_cast(display); } diff --git a/Devices/guition-jc1060p470ciwy/device.properties b/Devices/guition-jc1060p470ciwy/device.properties index ae177ffb..a5a8abcc 100644 --- a/Devices/guition-jc1060p470ciwy/device.properties +++ b/Devices/guition-jc1060p470ciwy/device.properties @@ -1,6 +1,6 @@ [general] vendor=Guition -name=JC1060P470CIWY +name=JC1060P470C-I-W-Y [hardware] target=ESP32P4 diff --git a/Devices/m5stack-tab5/CMakeLists.txt b/Devices/m5stack-tab5/CMakeLists.txt new file mode 100644 index 00000000..c84b1ada --- /dev/null +++ b/Devices/m5stack-tab5/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 EspLcdCompat esp_lcd_ili9881c GT911 PwmBacklight driver vfs fatfs +) diff --git a/Devices/m5stack-tab5/Source/Configuration.cpp b/Devices/m5stack-tab5/Source/Configuration.cpp new file mode 100644 index 00000000..344a497b --- /dev/null +++ b/Devices/m5stack-tab5/Source/Configuration.cpp @@ -0,0 +1,152 @@ +#include "devices/Display.h" +#include "devices/SdCard.h" + +#include + +using namespace tt::hal; + +static const auto LOGGER = tt::Logger("Tab5"); + +static DeviceVector createDevices() { + return { + createDisplay(), + createSdCard(), + }; +} + +static bool initBoot() { + /* + PI4IOE5V6408-1 (0x43) + - Bit 0: RF internal/external switch + - Bit 1: Speaker enable + - Bit 2: External 5V bus enable + - Bit 3: / + - Bit 4: LCD reset + - Bit 5: Touch reset + - Bit 6: Camera reset + - Bit 7: Headphone detect + + PI4IOE5V6408-2 (0x44) + - Bit 0: C6 WLAN enable + - Bit 1: / + - Bit 2: / + - Bit 3: USB-A 5V enable + - Bit 4: Device power: PWROFF_PLUSE + - Bit 5: IP2326: nCHG_QC_EN + - Bit 6: IP2326: CHG_STAT_LED + - Bit 7: IP2326: CHG_EN + */ + + // Init byte arrays adapted from https://github.com/m5stack/M5GFX/blob/03565ccc96cb0b73c8b157f5ec3fbde439b034ad/src/M5GFX.cpp + static constexpr uint8_t reg_data_io1_1[] = { + 0x03, 0b01111111, // PI4IO_REG_IO_DIR + 0x05, 0b01000110, // PI4IO_REG_OUT_SET (bit4=LCD Reset, bit5=GT911 TouchReset -> LOW) + 0x07, 0b00000000, // PI4IO_REG_OUT_H_IM + 0x0D, 0b01111111, // PI4IO_REG_PULL_SEL + 0x0B, 0b01111111, // PI4IO_REG_PULL_EN + }; + + static constexpr uint8_t reg_data_io1_2[] = { + 0x05, 0b01110110, // PI4IO_REG_OUT_SET (bit4=LCD Reset, bit5=GT911 TouchReset -> HIGH) + }; + + static constexpr uint8_t reg_data_io2[] = { + 0x03, 0b10111001, // PI4IO_REG_IO_DIR + 0x07, 0b00000110, // PI4IO_REG_OUT_H_IM + 0x0D, 0b10111001, // PI4IO_REG_PULL_SEL + 0x0B, 0b11111001, // PI4IO_REG_PULL_EN + 0x09, 0b01000000, // PI4IO_REG_IN_DEF_STA + 0x11, 0b10111111, // PI4IO_REG_INT_MASK + 0x05, 0b10001001, // PI4IO_REG_OUT_SET (enable WiFi, USB-A 5V and CHG_EN) + }; + + constexpr auto IO_EXPANDER1_ADDRESS = 0x43; + if (!i2c::masterWriteRegisterArray(I2C_NUM_0, IO_EXPANDER1_ADDRESS, reg_data_io1_1, sizeof(reg_data_io1_1))) { + LOGGER.error("IO expander 1 init failed in phase 1"); + return false; + } + + constexpr auto IO_EXPANDER2_ADDRESS = 0x44; + if (!i2c::masterWriteRegisterArray(I2C_NUM_0, IO_EXPANDER2_ADDRESS, reg_data_io2, sizeof(reg_data_io2))) { + LOGGER.error("IO expander 2 init failed"); + return false; + } + + // The M5Stack code applies this, but it's not known why + // TODO: Remove and test it extensively + tt::kernel::delayTicks(10); + + if (!i2c::masterWriteRegisterArray(I2C_NUM_0, IO_EXPANDER1_ADDRESS, reg_data_io1_2, sizeof(reg_data_io1_2))) { + LOGGER.error("IO expander 1 init failed in phase 2"); + return false; + } + + return true; +} + +extern const Configuration hardwareConfiguration = { + .initBoot = initBoot, + .createDevices = createDevices, + .i2c = { + i2c::Configuration { + .name = "Internal", + .port = I2C_NUM_0, + .initMode = i2c::InitMode::ByTactility, + .isMutable = false, + .config = (i2c_config_t) { + .mode = I2C_MODE_MASTER, + .sda_io_num = GPIO_NUM_31, + .scl_io_num = GPIO_NUM_32, + .sda_pullup_en = true, + .scl_pullup_en = true, + .master = { + .clk_speed = 400000 + }, + .clk_flags = 0 + } + }, + i2c::Configuration { + .name = "Port A", + .port = I2C_NUM_1, + .initMode = i2c::InitMode::ByTactility, + .isMutable = false, + .config = (i2c_config_t) { + .mode = I2C_MODE_MASTER, + .sda_io_num = GPIO_NUM_53, + .scl_io_num = GPIO_NUM_54, + .sda_pullup_en = true, + .scl_pullup_en = true, + .master = { + .clk_speed = 400000 + }, + .clk_flags = 0 + } + } + }, + .spi = { + // SDCard + spi::Configuration { + .device = SPI3_HOST, + .dma = SPI_DMA_CH_AUTO, + .config = { + .mosi_io_num = GPIO_NUM_44, + .miso_io_num = GPIO_NUM_39, + .sclk_io_num = GPIO_NUM_43, + .quadwp_io_num = GPIO_NUM_NC, + .quadhd_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, + .data_io_default_level = false, + .max_transfer_sz = 0, + .flags = 0, + .isr_cpu_id = ESP_INTR_CPU_AFFINITY_AUTO, + .intr_flags = 0 + }, + .initMode = spi::InitMode::ByTactility, + .isMutable = false, + .lock = nullptr + } + } +}; diff --git a/Devices/m5stack-tab5/Source/Drivers.cpp b/Devices/m5stack-tab5/Source/Drivers.cpp new file mode 100644 index 00000000..c8a5c665 --- /dev/null +++ b/Devices/m5stack-tab5/Source/Drivers.cpp @@ -0,0 +1,7 @@ +extern "C" { + +extern void register_device_drivers() { + /* NO-OP */ +} + +} diff --git a/Devices/m5stack-tab5/Source/devices/Display.cpp b/Devices/m5stack-tab5/Source/devices/Display.cpp new file mode 100644 index 00000000..3d74e1a0 --- /dev/null +++ b/Devices/m5stack-tab5/Source/devices/Display.cpp @@ -0,0 +1,64 @@ +#include "Display.h" +#include "Ili9881cDisplay.h" + +#include +#include +#include +#include +#include + +constexpr auto LCD_PIN_RESET = GPIO_NUM_0; // Match P4 EV board reset line +constexpr auto LCD_PIN_BACKLIGHT = GPIO_NUM_22; + +static std::shared_ptr createTouch() { + auto configuration = std::make_unique( + I2C_NUM_0, + 720, + 1280, + false, // swapXY + false, // mirrorX + false, // mirrorY + GPIO_NUM_NC, // reset pin + GPIO_NUM_NC // "GPIO_NUM_23 cannot be used due to resistor to 3V3" https://github.com/espressif/esp-bsp/blob/ad668c765cbad177495a122181df0a70ff9f8f61/bsp/m5stack_tab5/src/m5stack_tab5.c#L76234 + ); + + return std::make_shared(std::move(configuration)); +} + +std::shared_ptr createDisplay() { + // Initialize PWM backlight + if (!driver::pwmbacklight::init(LCD_PIN_BACKLIGHT, 5000, LEDC_TIMER_1, LEDC_CHANNEL_0)) { + tt::Logger("Tab5").warn("Failed to initialize backlight"); + } + + auto touch = createTouch(); + + // Work-around to init touch : interrupt pin must be set to low + // Note: There is a resistor to 3V3 on interrupt pin which is blocking GT911 touch + // See https://github.com/espressif/esp-bsp/blob/ad668c765cbad177495a122181df0a70ff9f8f61/bsp/m5stack_tab5/src/m5stack_tab5.c#L777 + tt::hal::gpio::configure(23, tt::hal::gpio::Mode::Output, true, false); + tt::hal::gpio::setLevel(23, false); + + auto configuration = std::make_shared(EspLcdConfiguration { + .horizontalResolution = 720, + .verticalResolution = 1280, + .gapX = 0, + .gapY = 0, + .monochrome = false, + .swapXY = false, + .mirrorX = false, + .mirrorY = false, + .invertColor = false, + .bufferSize = 0, // 0 = default (1/10 of screen) + .touch = touch, + .backlightDutyFunction = driver::pwmbacklight::setBacklightDuty, + .resetPin = LCD_PIN_RESET, + .lvglColorFormat = LV_COLOR_FORMAT_RGB565, + .lvglSwapBytes = false, + .rgbElementOrder = LCD_RGB_ELEMENT_ORDER_RGB, + .bitsPerPixel = 16 + }); + + const auto display = std::make_shared(configuration); + return std::static_pointer_cast(display); +} diff --git a/Devices/m5stack-tab5/Source/devices/Display.h b/Devices/m5stack-tab5/Source/devices/Display.h new file mode 100644 index 00000000..344191d6 --- /dev/null +++ b/Devices/m5stack-tab5/Source/devices/Display.h @@ -0,0 +1,6 @@ +#pragma once + +#include +#include + +std::shared_ptr createDisplay(); diff --git a/Devices/m5stack-tab5/Source/devices/Ili9881cDisplay.cpp b/Devices/m5stack-tab5/Source/devices/Ili9881cDisplay.cpp new file mode 100644 index 00000000..b088d884 --- /dev/null +++ b/Devices/m5stack-tab5/Source/devices/Ili9881cDisplay.cpp @@ -0,0 +1,148 @@ +#include "Ili9881cDisplay.h" +#include "disp_init_data.h" + +#include +#include + +static const auto LOGGER = tt::Logger("ILI9881C"); + +Ili9881cDisplay::~Ili9881cDisplay() { + // TODO: This should happen during ::stop(), but this isn't currently exposed + if (mipiDsiBus != nullptr) { + esp_lcd_del_dsi_bus(mipiDsiBus); + mipiDsiBus = nullptr; + } + if (ldoChannel != nullptr) { + esp_ldo_release_channel(ldoChannel); + ldoChannel = nullptr; + } +} + +bool Ili9881cDisplay::createMipiDsiBus() { + esp_ldo_channel_config_t ldo_mipi_phy_config = { + .chan_id = 3, + .voltage_mv = 2500, + .flags = { + .adjustable = 0, + .owned_by_hw = 0, + .bypass = 0 + } + }; + + if (esp_ldo_acquire_channel(&ldo_mipi_phy_config, &ldoChannel) != ESP_OK) { + LOGGER.error("Failed to acquire LDO channel for MIPI DSI PHY"); + return false; + } + + LOGGER.info("Powered on"); + + // Create bus + // TODO: use MIPI_DSI_PHY_CLK_SRC_DEFAULT() in future ESP-IDF 6.0.0 update with esp_lcd_jd9165 library version 2.x + const esp_lcd_dsi_bus_config_t bus_config = { + .bus_id = 0, + .num_data_lanes = 2, + .phy_clk_src = MIPI_DSI_PHY_CLK_SRC_DEFAULT, + .lane_bit_rate_mbps = 1000 + }; + + if (esp_lcd_new_dsi_bus(&bus_config, &mipiDsiBus) != ESP_OK) { + LOGGER.error("Failed to create bus"); + return false; + } + + LOGGER.info("Bus created"); + return true; +} + +bool Ili9881cDisplay::createIoHandle(esp_lcd_panel_io_handle_t& ioHandle) { + // Initialize MIPI DSI bus if not already done + if (mipiDsiBus == nullptr) { + if (!createMipiDsiBus()) { + return false; + } + } + + // Use DBI interface to send LCD commands and parameters + esp_lcd_dbi_io_config_t dbi_config = ILI9881C_PANEL_IO_DBI_CONFIG(); + + if (esp_lcd_new_panel_io_dbi(mipiDsiBus, &dbi_config, &ioHandle) != ESP_OK) { + LOGGER.error("Failed to create panel IO"); + return false; + } + + return true; +} + +esp_lcd_panel_dev_config_t Ili9881cDisplay::createPanelConfig(std::shared_ptr espLcdConfiguration, gpio_num_t resetPin) { + return { + .reset_gpio_num = resetPin, + .rgb_ele_order = espLcdConfiguration->rgbElementOrder, + .data_endian = LCD_RGB_DATA_ENDIAN_LITTLE, + .bits_per_pixel = static_cast(espLcdConfiguration->bitsPerPixel), + .flags = { + .reset_active_high = 0 + }, + .vendor_config = nullptr // Will be set in createPanelHandle + }; +} + +bool Ili9881cDisplay::createPanelHandle(esp_lcd_panel_io_handle_t ioHandle, const esp_lcd_panel_dev_config_t& panelConfig, esp_lcd_panel_handle_t& panelHandle) { + // Based on BSP: https://github.com/espressif/esp-bsp/blob/master/bsp/m5stack_tab5/README.md + // TODO: undo static + esp_lcd_dpi_panel_config_t dpi_config = { + .virtual_channel = 0, + .dpi_clk_src = MIPI_DSI_DPI_CLK_SRC_DEFAULT, + .dpi_clock_freq_mhz = 60, + .pixel_format = LCD_COLOR_PIXEL_FORMAT_RGB565, + .in_color_format = LCD_COLOR_FMT_RGB565, + .out_color_format = LCD_COLOR_FMT_RGB565, + .num_fbs = 1, // TODO: 2? + .video_timing = + { + .h_size = 720, + .v_size = 1280, + .hsync_pulse_width = 40, + .hsync_back_porch = 140, + .hsync_front_porch = 40, + .vsync_pulse_width = 4, + .vsync_back_porch = 20, + .vsync_front_porch = 20, + }, + .flags { + .use_dma2d = 1, // TODO: true? + .disable_lp = 0, + } + }; + + ili9881c_vendor_config_t vendor_config = { + .init_cmds = disp_init_data, + .init_cmds_size = std::size(disp_init_data), + .mipi_config = { + .dsi_bus = mipiDsiBus, + .dpi_config = &dpi_config, + .lane_num = 2, + }, + }; + + // Create a mutable copy of panelConfig to set vendor_config + esp_lcd_panel_dev_config_t mutable_panel_config = panelConfig; + mutable_panel_config.vendor_config = &vendor_config; + + if (esp_lcd_new_panel_ili9881c(ioHandle, &mutable_panel_config, &panelHandle) != ESP_OK) { + LOGGER.error("Failed to create panel"); + return false; + } + + LOGGER.info("Panel created successfully"); + // Defer reset/init to base class applyConfiguration to avoid double initialization + return true; +} + +lvgl_port_display_dsi_cfg_t Ili9881cDisplay::getLvglPortDisplayDsiConfig(esp_lcd_panel_io_handle_t /*ioHandle*/, esp_lcd_panel_handle_t /*panelHandle*/) { + // Disable avoid_tearing to prevent stalls/blank flashes when other tasks (e.g. flash writes) block timing + return lvgl_port_display_dsi_cfg_t{ + .flags = { + .avoid_tearing = 0, + }, + }; +} diff --git a/Devices/m5stack-tab5/Source/devices/Ili9881cDisplay.h b/Devices/m5stack-tab5/Source/devices/Ili9881cDisplay.h new file mode 100644 index 00000000..e2819f86 --- /dev/null +++ b/Devices/m5stack-tab5/Source/devices/Ili9881cDisplay.h @@ -0,0 +1,44 @@ +#pragma once + +#include +#include + +#include +#include + +class Ili9881cDisplay final : public EspLcdDisplayV2 { + + class NoLock final : public tt::Lock { + bool lock(TickType_t timeout) const override { return true; } + void unlock() const override { /* NO-OP */ } + }; + + esp_lcd_dsi_bus_handle_t mipiDsiBus = nullptr; + esp_ldo_channel_handle_t ldoChannel = nullptr; + + bool createMipiDsiBus(); + +protected: + + bool createIoHandle(esp_lcd_panel_io_handle_t& ioHandle) override; + + esp_lcd_panel_dev_config_t createPanelConfig(std::shared_ptr espLcdConfiguration, gpio_num_t resetPin) override; + + bool createPanelHandle(esp_lcd_panel_io_handle_t ioHandle, const esp_lcd_panel_dev_config_t& panelConfig, esp_lcd_panel_handle_t& panelHandle) override; + + bool useDsiPanel() const override { return true; } + + lvgl_port_display_dsi_cfg_t getLvglPortDisplayDsiConfig(esp_lcd_panel_io_handle_t /*ioHandle*/, esp_lcd_panel_handle_t /*panelHandle*/) override; + +public: + + Ili9881cDisplay( + const std::shared_ptr& configuration + ) : EspLcdDisplayV2(configuration, std::make_shared()) {} + + ~Ili9881cDisplay() override; + + std::string getName() const override { return "ILI9881C"; } + + std::string getDescription() const override { return "ILI9881C MIPI-DSI display"; } +}; diff --git a/Devices/m5stack-tab5/Source/devices/SdCard.cpp b/Devices/m5stack-tab5/Source/devices/SdCard.cpp new file mode 100644 index 00000000..5103a121 --- /dev/null +++ b/Devices/m5stack-tab5/Source/devices/SdCard.cpp @@ -0,0 +1,24 @@ +#include "SdCard.h" + +#include + +constexpr auto SDCARD_PIN_CS = GPIO_NUM_42; + +using tt::hal::sdcard::SpiSdCardDevice; + +std::shared_ptr createSdCard() { + auto configuration = std::make_unique( + SDCARD_PIN_CS, + GPIO_NUM_NC, + GPIO_NUM_NC, + GPIO_NUM_NC, + SdCardDevice::MountBehaviour::AtBoot, + tt::hal::spi::getLock(SPI3_HOST), + std::vector(), + SPI3_HOST + ); + + return std::make_shared( + std::move(configuration) + ); +} diff --git a/Devices/m5stack-tab5/Source/devices/SdCard.h b/Devices/m5stack-tab5/Source/devices/SdCard.h new file mode 100644 index 00000000..98b222fa --- /dev/null +++ b/Devices/m5stack-tab5/Source/devices/SdCard.h @@ -0,0 +1,8 @@ +#pragma once + +#include +#include + +using tt::hal::sdcard::SdCardDevice; + +std::shared_ptr createSdCard(); diff --git a/Devices/m5stack-tab5/Source/devices/disp_init_data.h b/Devices/m5stack-tab5/Source/devices/disp_init_data.h new file mode 100644 index 00000000..2ddb4264 --- /dev/null +++ b/Devices/m5stack-tab5/Source/devices/disp_init_data.h @@ -0,0 +1,435 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once +#include + +static const ili9881c_lcd_init_cmd_t disp_init_data[] = { + // {cmd, { data }, data_size, delay} + + /**** CMD_Page 1 ****/ + + {0xFF, (uint8_t[]){0x98, 0x81, 0x01}, 3, 0}, + + {0xB7, (uint8_t[]){0x03}, 1, 0}, // set 2 lane + + /**** CMD_Page 3 ****/ + + {0xFF, (uint8_t[]){0x98, 0x81, 0x03}, 3, 0}, + + {0x01, (uint8_t[]){0x00}, 1, 0}, + + {0x02, (uint8_t[]){0x00}, 1, 0}, + + {0x03, (uint8_t[]){0x73}, 1, 0}, + + {0x04, (uint8_t[]){0x00}, 1, 0}, + + {0x05, (uint8_t[]){0x00}, 1, 0}, + + {0x06, (uint8_t[]){0x08}, 1, 0}, + + {0x07, (uint8_t[]){0x00}, 1, 0}, + + {0x08, (uint8_t[]){0x00}, 1, 0}, + + {0x09, (uint8_t[]){0x1B}, 1, 0}, + + {0x0a, (uint8_t[]){0x01}, 1, 0}, + + {0x0b, (uint8_t[]){0x01}, 1, 0}, + + {0x0c, (uint8_t[]){0x0D}, 1, 0}, + + {0x0d, (uint8_t[]){0x01}, 1, 0}, + + {0x0e, (uint8_t[]){0x01}, 1, 0}, + + {0x0f, (uint8_t[]){0x26}, 1, 0}, + + {0x10, (uint8_t[]){0x26}, 1, 0}, + + {0x11, (uint8_t[]){0x00}, 1, 0}, + + {0x12, (uint8_t[]){0x00}, 1, 0}, + + {0x13, (uint8_t[]){0x02}, 1, 0}, + + {0x14, (uint8_t[]){0x00}, 1, 0}, + + {0x15, (uint8_t[]){0x00}, 1, 0}, + + {0x16, (uint8_t[]){0x00}, 1, 0}, + + {0x17, (uint8_t[]){0x00}, 1, 0}, + + {0x18, (uint8_t[]){0x00}, 1, 0}, + + {0x19, (uint8_t[]){0x00}, 1, 0}, + + {0x1a, (uint8_t[]){0x00}, 1, 0}, + + {0x1b, (uint8_t[]){0x00}, 1, 0}, + + {0x1c, (uint8_t[]){0x00}, 1, 0}, + + {0x1d, (uint8_t[]){0x00}, 1, 0}, + + {0x1e, (uint8_t[]){0x40}, 1, 0}, + + {0x1f, (uint8_t[]){0x00}, 1, 0}, + + {0x20, (uint8_t[]){0x06}, 1, 0}, + + {0x21, (uint8_t[]){0x01}, 1, 0}, + + {0x22, (uint8_t[]){0x00}, 1, 0}, + + {0x23, (uint8_t[]){0x00}, 1, 0}, + + {0x24, (uint8_t[]){0x00}, 1, 0}, + + {0x25, (uint8_t[]){0x00}, 1, 0}, + + {0x26, (uint8_t[]){0x00}, 1, 0}, + + {0x27, (uint8_t[]){0x00}, 1, 0}, + + {0x28, (uint8_t[]){0x33}, 1, 0}, + + {0x29, (uint8_t[]){0x03}, 1, 0}, + + {0x2a, (uint8_t[]){0x00}, 1, 0}, + + {0x2b, (uint8_t[]){0x00}, 1, 0}, + + {0x2c, (uint8_t[]){0x00}, 1, 0}, + + {0x2d, (uint8_t[]){0x00}, 1, 0}, + + {0x2e, (uint8_t[]){0x00}, 1, 0}, + + {0x2f, (uint8_t[]){0x00}, 1, 0}, + + {0x30, (uint8_t[]){0x00}, 1, 0}, + + {0x31, (uint8_t[]){0x00}, 1, 0}, + + {0x32, (uint8_t[]){0x00}, 1, 0}, + + {0x33, (uint8_t[]){0x00}, 1, 0}, + + {0x34, (uint8_t[]){0x00}, 1, 0}, + + {0x35, (uint8_t[]){0x00}, 1, 0}, + + {0x36, (uint8_t[]){0x00}, 1, 0}, + + {0x37, (uint8_t[]){0x00}, 1, 0}, + + {0x38, (uint8_t[]){0x00}, 1, 0}, + + {0x39, (uint8_t[]){0x00}, 1, 0}, + + {0x3a, (uint8_t[]){0x00}, 1, 0}, + + {0x3b, (uint8_t[]){0x00}, 1, 0}, + + {0x3c, (uint8_t[]){0x00}, 1, 0}, + + {0x3d, (uint8_t[]){0x00}, 1, 0}, + + {0x3e, (uint8_t[]){0x00}, 1, 0}, + + {0x3f, (uint8_t[]){0x00}, 1, 0}, + + {0x40, (uint8_t[]){0x00}, 1, 0}, + + {0x41, (uint8_t[]){0x00}, 1, 0}, + + {0x42, (uint8_t[]){0x00}, 1, 0}, + + {0x43, (uint8_t[]){0x00}, 1, 0}, + + {0x44, (uint8_t[]){0x00}, 1, 0}, + + + + {0x50, (uint8_t[]){0x01}, 1, 0}, + + {0x51, (uint8_t[]){0x23}, 1, 0}, + + {0x52, (uint8_t[]){0x45}, 1, 0}, + + {0x53, (uint8_t[]){0x67}, 1, 0}, + + {0x54, (uint8_t[]){0x89}, 1, 0}, + + {0x55, (uint8_t[]){0xab}, 1, 0}, + + {0x56, (uint8_t[]){0x01}, 1, 0}, + + {0x57, (uint8_t[]){0x23}, 1, 0}, + + {0x58, (uint8_t[]){0x45}, 1, 0}, + + {0x59, (uint8_t[]){0x67}, 1, 0}, + + {0x5a, (uint8_t[]){0x89}, 1, 0}, + + {0x5b, (uint8_t[]){0xab}, 1, 0}, + + {0x5c, (uint8_t[]){0xcd}, 1, 0}, + + {0x5d, (uint8_t[]){0xef}, 1, 0}, + + + + {0x5e, (uint8_t[]){0x11}, 1, 0}, + + {0x5f, (uint8_t[]){0x02}, 1, 0}, + + {0x60, (uint8_t[]){0x00}, 1, 0}, + + {0x61, (uint8_t[]){0x07}, 1, 0}, + + {0x62, (uint8_t[]){0x06}, 1, 0}, + + {0x63, (uint8_t[]){0x0E}, 1, 0}, + + {0x64, (uint8_t[]){0x0F}, 1, 0}, + + {0x65, (uint8_t[]){0x0C}, 1, 0}, + + {0x66, (uint8_t[]){0x0D}, 1, 0}, + + {0x67, (uint8_t[]){0x02}, 1, 0}, + + {0x68, (uint8_t[]){0x02}, 1, 0}, + + {0x69, (uint8_t[]){0x02}, 1, 0}, + + {0x6a, (uint8_t[]){0x02}, 1, 0}, + + {0x6b, (uint8_t[]){0x02}, 1, 0}, + + {0x6c, (uint8_t[]){0x02}, 1, 0}, + + {0x6d, (uint8_t[]){0x02}, 1, 0}, + + {0x6e, (uint8_t[]){0x02}, 1, 0}, + + {0x6f, (uint8_t[]){0x02}, 1, 0}, + + {0x70, (uint8_t[]){0x02}, 1, 0}, + + {0x71, (uint8_t[]){0x02}, 1, 0}, + + {0x72, (uint8_t[]){0x02}, 1, 0}, + + {0x73, (uint8_t[]){0x05}, 1, 0}, + + {0x74, (uint8_t[]){0x01}, 1, 0}, + + {0x75, (uint8_t[]){0x02}, 1, 0}, + + {0x76, (uint8_t[]){0x00}, 1, 0}, + + {0x77, (uint8_t[]){0x07}, 1, 0}, + + {0x78, (uint8_t[]){0x06}, 1, 0}, + + {0x79, (uint8_t[]){0x0E}, 1, 0}, + + {0x7a, (uint8_t[]){0x0F}, 1, 0}, + + {0x7b, (uint8_t[]){0x0C}, 1, 0}, + + {0x7c, (uint8_t[]){0x0D}, 1, 0}, + + {0x7d, (uint8_t[]){0x02}, 1, 0}, + + {0x7e, (uint8_t[]){0x02}, 1, 0}, + + {0x7f, (uint8_t[]){0x02}, 1, 0}, + + {0x80, (uint8_t[]){0x02}, 1, 0}, + + {0x81, (uint8_t[]){0x02}, 1, 0}, + + {0x82, (uint8_t[]){0x02}, 1, 0}, + + {0x83, (uint8_t[]){0x02}, 1, 0}, + + {0x84, (uint8_t[]){0x02}, 1, 0}, + + {0x85, (uint8_t[]){0x02}, 1, 0}, + + {0x86, (uint8_t[]){0x02}, 1, 0}, + + {0x87, (uint8_t[]){0x02}, 1, 0}, + + {0x88, (uint8_t[]){0x02}, 1, 0}, + + {0x89, (uint8_t[]){0x05}, 1, 0}, + + {0x8A, (uint8_t[]){0x01}, 1, 0}, + + + + /**** CMD_Page 4 ****/ + + {0xFF, (uint8_t[]){0x98, 0x81, 0x04}, 3, 0}, + + {0x38, (uint8_t[]){0x01}, 1, 0}, + + {0x39, (uint8_t[]){0x00}, 1, 0}, + + {0x6C, (uint8_t[]){0x15}, 1, 0}, + + {0x6E, (uint8_t[]){0x1A}, 1, 0}, + + {0x6F, (uint8_t[]){0x25}, 1, 0}, + + {0x3A, (uint8_t[]){0xA4}, 1, 0}, + + {0x8D, (uint8_t[]){0x20}, 1, 0}, + + {0x87, (uint8_t[]){0xBA}, 1, 0}, + + {0x3B, (uint8_t[]){0x98}, 1, 0}, + + + + /**** CMD_Page 1 ****/ + + {0xFF, (uint8_t[]){0x98, 0x81, 0x01}, 3, 0}, + + {0x22, (uint8_t[]){0x0A}, 1, 0}, + + {0x31, (uint8_t[]){0x00}, 1, 0}, + + {0x50, (uint8_t[]){0x6B}, 1, 0}, + + {0x51, (uint8_t[]){0x66}, 1, 0}, + + {0x53, (uint8_t[]){0x73}, 1, 0}, + + {0x55, (uint8_t[]){0x8B}, 1, 0}, + + {0x60, (uint8_t[]){0x1B}, 1, 0}, + + {0x61, (uint8_t[]){0x01}, 1, 0}, + + {0x62, (uint8_t[]){0x0C}, 1, 0}, + + {0x63, (uint8_t[]){0x00}, 1, 0}, + + + +// Gamma P + + {0xA0, (uint8_t[]){0x00}, 1, 0}, + + {0xA1, (uint8_t[]){0x15}, 1, 0}, + + {0xA2, (uint8_t[]){0x1F}, 1, 0}, + + {0xA3, (uint8_t[]){0x13}, 1, 0}, + + {0xA4, (uint8_t[]){0x11}, 1, 0}, + + {0xA5, (uint8_t[]){0x21}, 1, 0}, + + {0xA6, (uint8_t[]){0x17}, 1, 0}, + + {0xA7, (uint8_t[]){0x1B}, 1, 0}, + + {0xA8, (uint8_t[]){0x6B}, 1, 0}, + + {0xA9, (uint8_t[]){0x1E}, 1, 0}, + + {0xAA, (uint8_t[]){0x2B}, 1, 0}, + + {0xAB, (uint8_t[]){0x5D}, 1, 0}, + + {0xAC, (uint8_t[]){0x19}, 1, 0}, + + {0xAD, (uint8_t[]){0x14}, 1, 0}, + + {0xAE, (uint8_t[]){0x4B}, 1, 0}, + + {0xAF, (uint8_t[]){0x1D}, 1, 0}, + + {0xB0, (uint8_t[]){0x27}, 1, 0}, + + {0xB1, (uint8_t[]){0x49}, 1, 0}, + + {0xB2, (uint8_t[]){0x5D}, 1, 0}, + + {0xB3, (uint8_t[]){0x39}, 1, 0}, + + + +// Gamma N + + {0xC0, (uint8_t[]){0x00}, 1, 0}, + + {0xC1, (uint8_t[]){0x01}, 1, 0}, + + {0xC2, (uint8_t[]){0x0C}, 1, 0}, + + {0xC3, (uint8_t[]){0x11}, 1, 0}, + + {0xC4, (uint8_t[]){0x15}, 1, 0}, + + {0xC5, (uint8_t[]){0x28}, 1, 0}, + + {0xC6, (uint8_t[]){0x1B}, 1, 0}, + + {0xC7, (uint8_t[]){0x1C}, 1, 0}, + + {0xC8, (uint8_t[]){0x62}, 1, 0}, + + {0xC9, (uint8_t[]){0x1C}, 1, 0}, + + {0xCA, (uint8_t[]){0x29}, 1, 0}, + + {0xCB, (uint8_t[]){0x60}, 1, 0}, + + {0xCC, (uint8_t[]){0x16}, 1, 0}, + + {0xCD, (uint8_t[]){0x17}, 1, 0}, + + {0xCE, (uint8_t[]){0x4A}, 1, 0}, + + {0xCF, (uint8_t[]){0x23}, 1, 0}, + + {0xD0, (uint8_t[]){0x24}, 1, 0}, + + {0xD1, (uint8_t[]){0x4F}, 1, 0}, + + {0xD2, (uint8_t[]){0x5F}, 1, 0}, + + {0xD3, (uint8_t[]){0x39}, 1, 0}, + + + + /**** CMD_Page 0 ****/ + + {0xFF, (uint8_t[]){0x98, 0x81, 0x00}, 3, 0}, + + {0x35, (uint8_t[]){0x00}, 0, 0}, + +// {0x11, (uint8_t []){0x00}, 0}, + + {0xFE, (uint8_t[]){0x00}, 0, 0}, + + {0x29, (uint8_t[]){0x00}, 0, 0}, + +//============ Gamma END=========== + + +}; diff --git a/Devices/m5stack-tab5/device.properties b/Devices/m5stack-tab5/device.properties new file mode 100644 index 00000000..45461460 --- /dev/null +++ b/Devices/m5stack-tab5/device.properties @@ -0,0 +1,35 @@ +[general] +vendor=M5Stack +name=Tab5 + +[hardware] +target=ESP32P4 +flashSize=16MB +spiRam=true +spiRamMode=OCT +spiRamSpeed=200M +esptoolFlashFreq=80M + +[display] +size=5" +shape=rectangle +dpi=294 + +[lvgl] +colorDepth=16 + +[sdkconfig] +CONFIG_WIFI_PROV_SCAN_MAX_ENTRIES=16 +CONFIG_WIFI_PROV_AUTOSTOP_TIMEOUT=30 +CONFIG_WIFI_PROV_STA_ALL_CHANNEL_SCAN=y +CONFIG_SLAVE_IDF_TARGET_ESP32C6=y +CONFIG_ESP_HOSTED_ENABLED=y +CONFIG_ESP_HOSTED_SDIO_HOST_INTERFACE=y +CONFIG_ESP_HOSTED_SDIO_SLOT_1=y +CONFIG_ESP_HOSTED_PRIV_SDIO_PIN_CMD_SLOT_1=13 +CONFIG_ESP_HOSTED_PRIV_SDIO_PIN_CLK_SLOT_1=12 +CONFIG_ESP_HOSTED_PRIV_SDIO_PIN_D0_SLOT_1=11 +CONFIG_ESP_HOSTED_PRIV_SDIO_PIN_D1_4BIT_BUS_SLOT_1=10 +CONFIG_ESP_HOSTED_PRIV_SDIO_PIN_D2_4BIT_BUS_SLOT_1=9 +CONFIG_ESP_HOSTED_PRIV_SDIO_PIN_D3_4BIT_BUS_SLOT_1=8 +CONFIG_ESP_HOSTED_SDIO_GPIO_RESET_SLAVE=15 diff --git a/Devices/m5stack-tab5/devicetree.yaml b/Devices/m5stack-tab5/devicetree.yaml new file mode 100644 index 00000000..a1f5d125 --- /dev/null +++ b/Devices/m5stack-tab5/devicetree.yaml @@ -0,0 +1,3 @@ +dependencies: + - TactilityKernel +dts: ../placeholder.dts diff --git a/Firmware/Kconfig b/Firmware/Kconfig index 649bde91..157648c7 100644 --- a/Firmware/Kconfig +++ b/Firmware/Kconfig @@ -69,6 +69,8 @@ menu "Tactility App" bool "M5Stack StickC Plus" config TT_DEVICE_M5STACK_STICKC_PLUS2 bool "M5Stack StickC Plus2" + config TT_DEVICE_M5STACK_TAB5 + bool "M5Stack Tab5" config TT_DEVICE_UNPHONE bool "unPhone" config TT_DEVICE_WAVESHARE_ESP32_S3_GEEK diff --git a/Firmware/idf_component.yml b/Firmware/idf_component.yml index 8226a1d7..0d4e737f 100644 --- a/Firmware/idf_component.yml +++ b/Firmware/idf_component.yml @@ -43,6 +43,11 @@ dependencies: rules: # More hardware seems to be supported - enable as needed - if: "target in [esp32p4]" + espressif/esp_lcd_ili9881c: + version: "1.1.0" + rules: + # More hardware seems to be supported - enable as needed + - if: "target in [esp32p4]" espressif/esp_lcd_panel_io_additions: "1.0.1" espressif/esp_tinyusb: version: "1.7.6~1" diff --git a/Tactility/Source/app/appsettings/AppSettings.cpp b/Tactility/Source/app/appsettings/AppSettings.cpp index b0268378..2d2a12d2 100644 --- a/Tactility/Source/app/appsettings/AppSettings.cpp +++ b/Tactility/Source/app/appsettings/AppSettings.cpp @@ -26,7 +26,7 @@ class AppSettingsApp final : public App { public: void onShow(TT_UNUSED AppContext& app, lv_obj_t* parent) override { - auto* toolbar = lvgl::toolbar_create(parent, "External Apps"); + auto* toolbar = lvgl::toolbar_create(parent, "Installed Apps"); lv_obj_align(toolbar, LV_ALIGN_TOP_MID, 0, 0); lv_obj_t* list = lv_list_create(parent); diff --git a/Tactility/Source/hal/Hal.cpp b/Tactility/Source/hal/Hal.cpp index 4e26fb72..88d8e8b1 100644 --- a/Tactility/Source/hal/Hal.cpp +++ b/Tactility/Source/hal/Hal.cpp @@ -80,8 +80,8 @@ void init(const Configuration& configuration) { kernel::publishSystemEvent(kernel::SystemEvent::BootInitUartEnd); if (configuration.initBoot != nullptr) { - LOGGER.info("Init power"); - tt_check(configuration.initBoot(), "Init power failed"); + LOGGER.info("Init boot"); + tt_check(configuration.initBoot(), "Init boot failed"); } registerDevices(configuration);