diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2c38b320..13328eff 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -61,6 +61,7 @@ jobs: { id: m5stack-cardputer-adv, arch: esp32s3 }, { id: m5stack-core2, arch: esp32 }, { id: m5stack-cores3, arch: esp32s3 }, + { id: m5stack-papers3, arch: esp32s3 }, { id: m5stack-stickc-plus, arch: esp32 }, { id: m5stack-stickc-plus2, arch: esp32 }, { id: m5stack-tab5, arch: esp32p4 }, diff --git a/Devices/m5stack-papers3/CMakeLists.txt b/Devices/m5stack-papers3/CMakeLists.txt new file mode 100644 index 00000000..87c39fcc --- /dev/null +++ b/Devices/m5stack-papers3/CMakeLists.txt @@ -0,0 +1,6 @@ +file(GLOB_RECURSE SOURCE_FILES Source/*.c*) + +idf_component_register(SRCS ${SOURCE_FILES} + INCLUDE_DIRS "Source" + REQUIRES FastEpdDisplay GT911 TactilityCore +) diff --git a/Devices/m5stack-papers3/Source/Configuration.cpp b/Devices/m5stack-papers3/Source/Configuration.cpp new file mode 100644 index 00000000..922de920 --- /dev/null +++ b/Devices/m5stack-papers3/Source/Configuration.cpp @@ -0,0 +1,45 @@ +#include "devices/Display.h" +#include "devices/SdCard.h" + +#include +#include + +using namespace tt::hal; + +static DeviceVector createDevices() { + auto touch = createTouch(); + return { + createSdCard(), + createDisplay(touch) + }; +} + +extern const Configuration hardwareConfiguration = { + .initBoot = nullptr, + .createDevices = createDevices, + .spi { + spi::Configuration { + .device = SPI2_HOST, + .dma = SPI_DMA_CH_AUTO, + .config = { + .mosi_io_num = GPIO_NUM_38, + .miso_io_num = GPIO_NUM_40, + .sclk_io_num = GPIO_NUM_39, + .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 = 4096, + .flags = 0, + .isr_cpu_id = ESP_INTR_CPU_AFFINITY_AUTO, + .intr_flags = 0 + }, + .initMode = spi::InitMode::ByTactility, + .isMutable = false, + .lock = tt::lvgl::getSyncLock() + } + } +}; diff --git a/Devices/m5stack-papers3/Source/devices/Display.cpp b/Devices/m5stack-papers3/Source/devices/Display.cpp new file mode 100644 index 00000000..af02b558 --- /dev/null +++ b/Devices/m5stack-papers3/Source/devices/Display.cpp @@ -0,0 +1,34 @@ +#include "Display.h" +#include +#include +#include + +std::shared_ptr createTouch() { + auto configuration = std::make_unique( + I2C_NUM_0, + 540, + 960, + false, // swapXy + false, // mirrorX + false, // mirrorY + GPIO_NUM_NC, // pinReset + GPIO_NUM_NC // pinInterrupt + ); + + auto touch = std::make_shared(std::move(configuration)); + return std::static_pointer_cast(touch); +} + +std::shared_ptr createDisplay(std::shared_ptr touch) { + FastEpdDisplay::Configuration configuration = { + .horizontalResolution = 540, + .verticalResolution = 960, + .touch = std::move(touch), + .busSpeedHz = 20000000, + .rotationDegrees = 90, + .use4bppGrayscale = false, + .fullRefreshEveryNFlushes = 40, + }; + + return std::make_shared(configuration, tt::lvgl::getSyncLock()); +} diff --git a/Devices/m5stack-papers3/Source/devices/Display.h b/Devices/m5stack-papers3/Source/devices/Display.h new file mode 100644 index 00000000..bac7fd00 --- /dev/null +++ b/Devices/m5stack-papers3/Source/devices/Display.h @@ -0,0 +1,7 @@ +#pragma once + +#include +#include + +std::shared_ptr createTouch(); +std::shared_ptr createDisplay(std::shared_ptr touch); diff --git a/Devices/m5stack-papers3/Source/devices/SdCard.cpp b/Devices/m5stack-papers3/Source/devices/SdCard.cpp new file mode 100644 index 00000000..4c477dd0 --- /dev/null +++ b/Devices/m5stack-papers3/Source/devices/SdCard.cpp @@ -0,0 +1,25 @@ +#include "SdCard.h" + +#include +#include + +constexpr auto PAPERS3_SDCARD_PIN_CS = GPIO_NUM_47; + +using tt::hal::sdcard::SpiSdCardDevice; + +std::shared_ptr createSdCard() { + auto configuration = std::make_unique( + PAPERS3_SDCARD_PIN_CS, + GPIO_NUM_NC, + GPIO_NUM_NC, + GPIO_NUM_NC, + SdCardDevice::MountBehaviour::AtBoot, + tt::lvgl::getSyncLock(), + std::vector{}, + SPI2_HOST + ); + + return std::make_shared( + std::move(configuration) + ); +} diff --git a/Devices/m5stack-papers3/Source/devices/SdCard.h b/Devices/m5stack-papers3/Source/devices/SdCard.h new file mode 100644 index 00000000..5cb65a73 --- /dev/null +++ b/Devices/m5stack-papers3/Source/devices/SdCard.h @@ -0,0 +1,7 @@ +#pragma once + +#include "Tactility/hal/sdcard/SdCardDevice.h" + +using tt::hal::sdcard::SdCardDevice; + +std::shared_ptr createSdCard(); diff --git a/Devices/m5stack-papers3/Source/module.cpp b/Devices/m5stack-papers3/Source/module.cpp new file mode 100644 index 00000000..507ff816 --- /dev/null +++ b/Devices/m5stack-papers3/Source/module.cpp @@ -0,0 +1,23 @@ +#include + +extern "C" { + +static error_t start() { + // Empty for now + return ERROR_NONE; +} + +static error_t stop() { + // Empty for now + return ERROR_NONE; +} + +/** @warning The variable name must be exactly "device_module" */ +struct Module device_module = { + .name = "m5stack-papers3", + .start = start, + .stop = stop, + .symbols = nullptr +}; + +} diff --git a/Devices/m5stack-papers3/device.properties b/Devices/m5stack-papers3/device.properties new file mode 100644 index 00000000..83cdb996 --- /dev/null +++ b/Devices/m5stack-papers3/device.properties @@ -0,0 +1,27 @@ +[general] +vendor=M5Stack +name=Paper S3 +incubating=true + +[hardware] +target=esp32s3 +flashSize=16MB +spiRam=true +spiRamMode=OPI +spiRamSpeed=80M +esptoolFlashFreq=80M +tinyUsb=true + +[display] +size=4.7" +shape=rectangle +dpi=235 + +[lvgl] +colorDepth=8 +theme=Mono + +[sdkconfig] +CONFIG_EPD_DISPLAY_TYPE_ED047TC2=y + + diff --git a/Devices/m5stack-papers3/devicetree.yaml b/Devices/m5stack-papers3/devicetree.yaml new file mode 100644 index 00000000..867ba7af --- /dev/null +++ b/Devices/m5stack-papers3/devicetree.yaml @@ -0,0 +1,3 @@ +dependencies: + - Platforms/PlatformEsp32 +dts: m5stack,papers3.dts diff --git a/Devices/m5stack-papers3/m5stack,papers3.dts b/Devices/m5stack-papers3/m5stack,papers3.dts new file mode 100644 index 00000000..9b0a43df --- /dev/null +++ b/Devices/m5stack-papers3/m5stack,papers3.dts @@ -0,0 +1,25 @@ +/dts-v1/; + +#include +#include +#include + +/ { + compatible = "root"; + model = "M5Stack PaperS3"; + + gpio0 { + compatible = "espressif,esp32-gpio"; + gpio-count = <49>; + }; + + i2c_internal { + compatible = "espressif,esp32-i2c"; + port = ; + clock-frequency = <400000>; + pin-sda = <41>; + pin-scl = <42>; + pin-sda-pullup; + pin-scl-pullup; + }; +}; diff --git a/Drivers/FastEpdDisplay/CMakeLists.txt b/Drivers/FastEpdDisplay/CMakeLists.txt new file mode 100644 index 00000000..19f73375 --- /dev/null +++ b/Drivers/FastEpdDisplay/CMakeLists.txt @@ -0,0 +1,5 @@ +idf_component_register( + SRC_DIRS "Source" + INCLUDE_DIRS "Source" + REQUIRES FastEPD TactilityCore Tactility +) diff --git a/Drivers/FastEpdDisplay/Source/FastEpdDisplay.cpp b/Drivers/FastEpdDisplay/Source/FastEpdDisplay.cpp new file mode 100644 index 00000000..600d25e2 --- /dev/null +++ b/Drivers/FastEpdDisplay/Source/FastEpdDisplay.cpp @@ -0,0 +1,256 @@ +#include "FastEpdDisplay.h" + +#include + +#include + +#ifdef ESP_PLATFORM +#include +#endif + +#define TAG "FastEpdDisplay" + +FastEpdDisplay::~FastEpdDisplay() { + stop(); +} + +void FastEpdDisplay::flush_cb(lv_display_t* disp, const lv_area_t* area, uint8_t* px_map) { + auto* self = static_cast(lv_display_get_user_data(disp)); + + static uint32_t s_flush_log_counter = 0; + + const int32_t width = area->x2 - area->x1 + 1; + const bool grayscale4bpp = self->configuration.use4bppGrayscale; + + // LVGL logical resolution is portrait (540x960). FastEPD PaperS3 native is landscape (960x540). + // Keep FastEPD at rotation 0 and do the coordinate transform ourselves. + // For a 90° clockwise transform: + // x_native = y + // y_native = (native_height - 1) - x + const int native_width = self->epd.width(); + const int native_height = self->epd.height(); + + // Compute the native line range that will be affected by this flush. + // With our mapping y_native = (native_height - 1) - x + // So x range maps to y_native range. + int start_line = (native_height - 1) - (int)area->x2; + int end_line = (native_height - 1) - (int)area->x1; + if (start_line > end_line) { + const int tmp = start_line; + start_line = end_line; + end_line = tmp; + } + if (start_line < 0) start_line = 0; + if (end_line >= native_height) end_line = native_height - 1; + + for (int32_t y = area->y1; y <= area->y2; y++) { + for (int32_t x = area->x1; x <= area->x2; x++) { + const uint8_t gray8 = px_map[(y - area->y1) * width + (x - area->x1)]; + const uint8_t color = grayscale4bpp ? (uint8_t)(gray8 >> 4) : (uint8_t)((gray8 > 127) ? BBEP_BLACK : BBEP_WHITE); + + const int x_native = y; + const int y_native = (native_height - 1) - x; + + // Be defensive: any out-of-range drawPixelFast will corrupt memory. + if (x_native < 0 || x_native >= native_width || y_native < 0 || y_native >= native_height) { + continue; + } + self->epd.drawPixelFast(x_native, y_native, color); + } + } + + if (start_line <= end_line) { + (void)self->epd.einkPower(1); + self->flushCount++; + const uint32_t cadence = self->configuration.fullRefreshEveryNFlushes; + const bool requested_full = self->forceNextFullRefresh.exchange(false); + const bool do_full = requested_full || ((cadence > 0) && (self->flushCount % cadence == 0)); + + const bool should_log = ((++s_flush_log_counter % 25U) == 0U); + if (should_log) { + LOG_I(TAG, "flush #%lu area=(%ld,%ld)-(%ld,%ld) lines=[%d..%d] full=%d", + (unsigned long)self->flushCount, + (long)area->x1, (long)area->y1, (long)area->x2, (long)area->y2, + start_line, end_line, (int)do_full); + } + + if (do_full) { + const int rc = self->epd.fullUpdate(CLEAR_FAST, true, nullptr); + if (should_log) { + LOG_I(TAG, "fullUpdate rc=%d", rc); + } + + // After a full update, keep FastEPD's previous/current buffers in sync so that + // subsequent partial updates compute correct diffs. + const int w = self->epd.width(); + const int h = self->epd.height(); + const size_t bytes_per_row = grayscale4bpp + ? (size_t)(w + 1) / 2 + : (size_t)(w + 7) / 8; + const size_t plane_size = bytes_per_row * (size_t)h; + if (self->epd.currentBuffer() && self->epd.previousBuffer()) { + memcpy(self->epd.previousBuffer(), self->epd.currentBuffer(), plane_size); + } + } else { + if (grayscale4bpp) { + // FastEPD partialUpdate only supports 1bpp mode. + // For 4bpp we currently do a fullUpdate. Region-based updates are tricky here because + // we also manually rotate/transform pixels in flush_cb; a mismatched rect can refresh + // the wrong strip of the panel (seen as "split" buttons on the final refresh). + const int rc = self->epd.fullUpdate(CLEAR_FAST, true, nullptr); + if (should_log) { + LOG_I(TAG, "fullUpdate(4bpp) rc=%d", rc); + } + } else { + const int rc = self->epd.partialUpdate(true, start_line, end_line); + + // Keep FastEPD's previous/current buffers in sync after partial updates as well. + // This avoids stale diffs where subsequent updates don't visibly apply. + const int w = self->epd.width(); + const int h = self->epd.height(); + const size_t bytes_per_row = (size_t)(w + 7) / 8; + const size_t plane_size = bytes_per_row * (size_t)h; + if (rc == BBEP_SUCCESS && self->epd.currentBuffer() && self->epd.previousBuffer()) { + memcpy(self->epd.previousBuffer(), self->epd.currentBuffer(), plane_size); + } + + if (should_log) { + LOG_I(TAG, "partialUpdate rc=%d", rc); + } + } + } + } + + lv_display_flush_ready(disp); +} + +bool FastEpdDisplay::start() { + if (initialized) { + return true; + } + + const int rc = epd.initPanel(BB_PANEL_M5PAPERS3, configuration.busSpeedHz); + if (rc != BBEP_SUCCESS) { + LOG_E(TAG, "FastEPD initPanel failed rc=%d", rc); + return false; + } + + LOG_I(TAG, "FastEPD native size %dx%d", epd.width(), epd.height()); + + const int desired_mode = configuration.use4bppGrayscale ? BB_MODE_4BPP : BB_MODE_1BPP; + if (epd.setMode(desired_mode) != BBEP_SUCCESS) { + LOG_E(TAG, "FastEPD setMode(%d) failed", desired_mode); + epd.deInit(); + return false; + } + + // Keep FastEPD at rotation 0. LVGL-to-native mapping is handled in flush_cb. + + // Ensure previous/current buffers are in sync and the panel starts from a known state. + if (epd.einkPower(1) != BBEP_SUCCESS) { + LOG_W(TAG, "FastEPD einkPower(1) failed"); + } else { + epd.fillScreen(configuration.use4bppGrayscale ? 0x0F : BBEP_WHITE); + + const int native_width = epd.width(); + const int native_height = epd.height(); + const size_t bytes_per_row = configuration.use4bppGrayscale + ? (size_t)(native_width + 1) / 2 + : (size_t)(native_width + 7) / 8; + const size_t plane_size = bytes_per_row * (size_t)native_height; + + if (epd.currentBuffer() && epd.previousBuffer()) { + memcpy(epd.previousBuffer(), epd.currentBuffer(), plane_size); + } + + if (epd.fullUpdate(CLEAR_FAST, true, nullptr) != BBEP_SUCCESS) { + LOG_W(TAG, "FastEPD fullUpdate failed"); + } + } + + initialized = true; + return true; +} + +bool FastEpdDisplay::stop() { + if (lvglDisplay) { + stopLvgl(); + } + + if (initialized) { + epd.deInit(); + initialized = false; + } + + return true; +} + +bool FastEpdDisplay::startLvgl() { + if (lvglDisplay != nullptr) { + return true; + } + + lvglDisplay = lv_display_create(configuration.horizontalResolution, configuration.verticalResolution); + if (lvglDisplay == nullptr) { + return false; + } + + lv_display_set_color_format(lvglDisplay, LV_COLOR_FORMAT_L8); + + if (lv_display_get_rotation(lvglDisplay) != LV_DISPLAY_ROTATION_0) { + lv_display_set_rotation(lvglDisplay, LV_DISPLAY_ROTATION_0); + } + + const uint32_t pixel_count = (uint32_t)(configuration.horizontalResolution * configuration.verticalResolution / 10); + const uint32_t buf_size = pixel_count * (uint32_t)lv_color_format_get_size(LV_COLOR_FORMAT_L8); + lvglBufSize = buf_size; + +#ifdef ESP_PLATFORM + lvglBuf1 = heap_caps_malloc(buf_size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); +#else + lvglBuf1 = malloc(buf_size); +#endif + + if (lvglBuf1 == nullptr) { + lv_display_delete(lvglDisplay); + lvglDisplay = nullptr; + return false; + } + + lvglBuf2 = nullptr; + lv_display_set_buffers(lvglDisplay, lvglBuf1, lvglBuf2, buf_size, LV_DISPLAY_RENDER_MODE_PARTIAL); + + lv_display_set_user_data(lvglDisplay, this); + lv_display_set_flush_cb(lvglDisplay, FastEpdDisplay::flush_cb); + + if (configuration.touch && configuration.touch->supportsLvgl()) { + configuration.touch->startLvgl(lvglDisplay); + } + + return true; +} + +bool FastEpdDisplay::stopLvgl() { + if (lvglDisplay) { + if (configuration.touch) { + configuration.touch->stopLvgl(); + } + + lv_display_delete(lvglDisplay); + lvglDisplay = nullptr; + } + + if (lvglBuf1 != nullptr) { + free(lvglBuf1); + lvglBuf1 = nullptr; + } + + if (lvglBuf2 != nullptr) { + free(lvglBuf2); + lvglBuf2 = nullptr; + } + + lvglBufSize = 0; + + return true; +} diff --git a/Drivers/FastEpdDisplay/Source/FastEpdDisplay.h b/Drivers/FastEpdDisplay/Source/FastEpdDisplay.h new file mode 100644 index 00000000..22d9218d --- /dev/null +++ b/Drivers/FastEpdDisplay/Source/FastEpdDisplay.h @@ -0,0 +1,65 @@ +#pragma once + +#include +#include +#include + +#include +#include +#include + +class FastEpdDisplay final : public tt::hal::display::DisplayDevice { +public: + struct Configuration final { + int horizontalResolution; + int verticalResolution; + std::shared_ptr touch; + uint32_t busSpeedHz = 20000000; + int rotationDegrees = 90; + bool use4bppGrayscale = false; + uint32_t fullRefreshEveryNFlushes = 0; + }; + +private: + Configuration configuration; + std::shared_ptr lock; + + lv_display_t* lvglDisplay = nullptr; + void* lvglBuf1 = nullptr; + void* lvglBuf2 = nullptr; + uint32_t lvglBufSize = 0; + + FASTEPD epd; + bool initialized = false; + uint32_t flushCount = 0; + std::atomic_bool forceNextFullRefresh{false}; + + static void flush_cb(lv_display_t* disp, const lv_area_t* area, uint8_t* px_map); + +public: + FastEpdDisplay(Configuration configuration, std::shared_ptr lock) + : configuration(std::move(configuration)), lock(std::move(lock)) {} + + ~FastEpdDisplay() override; + + void requestFullRefresh() override { forceNextFullRefresh.store(true); } + + std::string getName() const override { return "FastEpdDisplay"; } + std::string getDescription() const override { return "FastEPD (bitbank2) E-Ink display driver"; } + + bool start() override; + bool stop() override; + + bool supportsLvgl() const override { return true; } + bool startLvgl() override; + bool stopLvgl() override; + + lv_display_t* getLvglDisplay() const override { return lvglDisplay; } + + bool supportsDisplayDriver() const override { return false; } + std::shared_ptr getDisplayDriver() override { return nullptr; } + + std::shared_ptr getTouchDevice() override { + return configuration.touch; + } +}; diff --git a/Firmware/Kconfig b/Firmware/Kconfig index c77f0570..393e75e2 100644 --- a/Firmware/Kconfig +++ b/Firmware/Kconfig @@ -6,93 +6,6 @@ menu "Tactility App" config TT_DEVICE_ID string "Device Identifier" default "" - choice - prompt "Device" - default TT_DEVICE_CUSTOM - config TT_DEVICE_CUSTOM - bool "Custom" - config TT_DEVICE_BTT_PANDA_TOUCH - bool "BigTreeTech Panda Touch" - config TT_DEVICE_CYD_2432S024C - bool "CYD 2432S024C" - config TT_DEVICE_CYD_2432S028R - bool "CYD 2432S028R" - config TT_DEVICE_CYD_2432S028RV3 - bool "CYD 2432S028RV3" - config TT_DEVICE_CYD_E32R28T - bool "CYD E32R28T" - config TT_DEVICE_CYD_E32R32P - bool "CYD E32R32P" - config TT_DEVICE_CYD_2432S032C - bool "CYD 2432S032C" - config TT_DEVICE_CYD_8048S043C - bool "CYD 8048S043C" - config TT_DEVICE_CYD_4848S040C - bool "CYD 4848S040C" - config TT_DEVICE_ELECROW_CROWPANEL_ADVANCE_28 - bool "Elecrow CrowPanel Advance 2.8" - config TT_DEVICE_ELECROW_CROWPANEL_ADVANCE_35 - bool "Elecrow CrowPanel Advance 3.5" - config TT_DEVICE_ELECROW_CROWPANEL_ADVANCE_50 - bool "Elecrow CrowPanel Advance 5.0" - config TT_DEVICE_ELECROW_CROWPANEL_BASIC_28 - bool "Elecrow CrowPanel Basic 2.8" - config TT_DEVICE_ELECROW_CROWPANEL_BASIC_35 - bool "Elecrow CrowPanel Basic 3.5" - config TT_DEVICE_ELECROW_CROWPANEL_BASIC_50 - bool "Elecrow CrowPanel Basic 5.0" - config TT_DEVICE_GUITION_JC1060P470CIWY - bool "Guition JC1060P470CIWY" - config TT_DEVICE_GUITION_JC2432W328C - bool "Guition JC2432W328C" - config TT_DEVICE_GUITION_JC3248W535C - bool "Guition JC3248W535C" - config TT_DEVICE_GUITION_JC8048W550C - bool "Guition JC8048W550C" - config TT_DEVICE_HELTEC_V3 - bool "Heltec v3" - config TT_DEVICE_LILYGO_TDECK - bool "LilyGo T-Deck" - config TT_DEVICE_LILYGO_TDONGLE_S3 - bool "LilyGo T-Dongle S3" - config TT_DEVICE_LILYGO_TLORA_PAGER - bool "LilyGo T-Lora Pager" - config TT_DEVICE_LILYGO_TDISPLAY - bool "LilyGo T-Display" - config TT_DEVICE_M5STACK_CARDPUTER - bool "M5Stack Cardputer" - config TT_DEVICE_M5STACK_CARDPUTER_ADV - bool "M5Stack Cardputer Adv" - config TT_DEVICE_M5STACK_CORE2 - bool "M5Stack Core2" - config TT_DEVICE_M5STACK_CORES3 - bool "M5Stack CoreS3" - config TT_DEVICE_M5STACK_STICKC_PLUS - 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 - bool "Waveshare ESP32 S3 GEEK" - config TT_DEVICE_WAVESHARE_S3_TOUCH_43 - bool "Waveshare ESP32 S3 Touch LCD 4.3" - config TT_DEVICE_WAVESHARE_S3_TOUCH_LCD_147 - bool "Waveshare ESP32 S3 Touch LCD 1.47" - config TT_DEVICE_WAVESHARE_S3_TOUCH_LCD_128 - bool "Waveshare ESP32 S3 Touch LCD 1.28" - config TT_DEVICE_WAVESHARE_S3_LCD_13 - bool "Waveshare ESP32 S3 LCD 1.3" - config TT_DEVICE_WIRELESS_TAG_WT32_SC01_PLUS - bool "Wireless Tag WT32-SC01 Plus" - - help - Select a device. - Use TT_DEVICE_CUSTOM if you will manually configure the device in your project. - endchoice - config TT_SPLASH_DURATION int "Splash Duration (ms)" default 1000 diff --git a/Firmware/idf_component.yml b/Firmware/idf_component.yml index 5fabc624..2e6fd9ab 100644 --- a/Firmware/idf_component.yml +++ b/Firmware/idf_component.yml @@ -54,4 +54,11 @@ dependencies: version: "1.7.6~1" rules: - if: "target == esp32s3" + FastEPD: + git: https://github.com/bitbank2/FastEPD.git + version: 1.4.2 + rules: + # More hardware might be supported - enable as needed + - if: "target in [esp32s3]" idf: '5.5' + diff --git a/Tactility/Include/Tactility/hal/display/DisplayDevice.h b/Tactility/Include/Tactility/hal/display/DisplayDevice.h index 7620dfd8..64c243c7 100644 --- a/Tactility/Include/Tactility/hal/display/DisplayDevice.h +++ b/Tactility/Include/Tactility/hal/display/DisplayDevice.h @@ -26,6 +26,9 @@ public: virtual bool isPoweredOn() const { return true; } virtual bool supportsPowerControl() const { return false; } + /** For e-paper screens */ + virtual void requestFullRefresh() {} + /** Could return nullptr if not started */ virtual std::shared_ptr getTouchDevice() = 0; diff --git a/device.py b/device.py index 7c207e4f..3048fcc0 100644 --- a/device.py +++ b/device.py @@ -148,6 +148,8 @@ def write_spiram_variables(output_file, device_properties: ConfigParser): output_file.write("CONFIG_SPIRAM=y\n") output_file.write(f"CONFIG_{idf_target.upper()}_SPIRAM_SUPPORT=y\n") mode = get_property_or_exit(device_properties, "hardware", "spiRamMode") + if mode == "OPI": + mode = "OCT" # Mode if mode != "AUTO": output_file.write(f"CONFIG_SPIRAM_MODE_{mode}=y\n")