mirror of
https://github.com/ByteWelder/Tactility.git
synced 2026-02-18 19:03:16 +00:00
M5Stack PaperS3 implementation (#478)
Selectively imported code from @juicecultus [fork](https://github.com/juicecultus/Tactility) with some changes/additions from me.
This commit is contained in:
parent
a935410f82
commit
9cc96fd32b
1
.github/workflows/build.yml
vendored
1
.github/workflows/build.yml
vendored
@ -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 },
|
||||
|
||||
6
Devices/m5stack-papers3/CMakeLists.txt
Normal file
6
Devices/m5stack-papers3/CMakeLists.txt
Normal file
@ -0,0 +1,6 @@
|
||||
file(GLOB_RECURSE SOURCE_FILES Source/*.c*)
|
||||
|
||||
idf_component_register(SRCS ${SOURCE_FILES}
|
||||
INCLUDE_DIRS "Source"
|
||||
REQUIRES FastEpdDisplay GT911 TactilityCore
|
||||
)
|
||||
45
Devices/m5stack-papers3/Source/Configuration.cpp
Normal file
45
Devices/m5stack-papers3/Source/Configuration.cpp
Normal file
@ -0,0 +1,45 @@
|
||||
#include "devices/Display.h"
|
||||
#include "devices/SdCard.h"
|
||||
|
||||
#include <Tactility/hal/Configuration.h>
|
||||
#include <Tactility/lvgl/LvglSync.h>
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
||||
};
|
||||
34
Devices/m5stack-papers3/Source/devices/Display.cpp
Normal file
34
Devices/m5stack-papers3/Source/devices/Display.cpp
Normal file
@ -0,0 +1,34 @@
|
||||
#include "Display.h"
|
||||
#include <Gt911Touch.h>
|
||||
#include <FastEpdDisplay.h>
|
||||
#include <Tactility/lvgl/LvglSync.h>
|
||||
|
||||
std::shared_ptr<tt::hal::touch::TouchDevice> createTouch() {
|
||||
auto configuration = std::make_unique<Gt911Touch::Configuration>(
|
||||
I2C_NUM_0,
|
||||
540,
|
||||
960,
|
||||
false, // swapXy
|
||||
false, // mirrorX
|
||||
false, // mirrorY
|
||||
GPIO_NUM_NC, // pinReset
|
||||
GPIO_NUM_NC // pinInterrupt
|
||||
);
|
||||
|
||||
auto touch = std::make_shared<Gt911Touch>(std::move(configuration));
|
||||
return std::static_pointer_cast<tt::hal::touch::TouchDevice>(touch);
|
||||
}
|
||||
|
||||
std::shared_ptr<tt::hal::display::DisplayDevice> createDisplay(std::shared_ptr<tt::hal::touch::TouchDevice> touch) {
|
||||
FastEpdDisplay::Configuration configuration = {
|
||||
.horizontalResolution = 540,
|
||||
.verticalResolution = 960,
|
||||
.touch = std::move(touch),
|
||||
.busSpeedHz = 20000000,
|
||||
.rotationDegrees = 90,
|
||||
.use4bppGrayscale = false,
|
||||
.fullRefreshEveryNFlushes = 40,
|
||||
};
|
||||
|
||||
return std::make_shared<FastEpdDisplay>(configuration, tt::lvgl::getSyncLock());
|
||||
}
|
||||
7
Devices/m5stack-papers3/Source/devices/Display.h
Normal file
7
Devices/m5stack-papers3/Source/devices/Display.h
Normal file
@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <Tactility/hal/display/DisplayDevice.h>
|
||||
#include <Tactility/hal/touch/TouchDevice.h>
|
||||
|
||||
std::shared_ptr<tt::hal::touch::TouchDevice> createTouch();
|
||||
std::shared_ptr<tt::hal::display::DisplayDevice> createDisplay(std::shared_ptr<tt::hal::touch::TouchDevice> touch);
|
||||
25
Devices/m5stack-papers3/Source/devices/SdCard.cpp
Normal file
25
Devices/m5stack-papers3/Source/devices/SdCard.cpp
Normal file
@ -0,0 +1,25 @@
|
||||
#include "SdCard.h"
|
||||
|
||||
#include <Tactility/lvgl/LvglSync.h>
|
||||
#include <Tactility/hal/sdcard/SpiSdCardDevice.h>
|
||||
|
||||
constexpr auto PAPERS3_SDCARD_PIN_CS = GPIO_NUM_47;
|
||||
|
||||
using tt::hal::sdcard::SpiSdCardDevice;
|
||||
|
||||
std::shared_ptr<SdCardDevice> createSdCard() {
|
||||
auto configuration = std::make_unique<SpiSdCardDevice::Config>(
|
||||
PAPERS3_SDCARD_PIN_CS,
|
||||
GPIO_NUM_NC,
|
||||
GPIO_NUM_NC,
|
||||
GPIO_NUM_NC,
|
||||
SdCardDevice::MountBehaviour::AtBoot,
|
||||
tt::lvgl::getSyncLock(),
|
||||
std::vector<gpio_num_t>{},
|
||||
SPI2_HOST
|
||||
);
|
||||
|
||||
return std::make_shared<SpiSdCardDevice>(
|
||||
std::move(configuration)
|
||||
);
|
||||
}
|
||||
7
Devices/m5stack-papers3/Source/devices/SdCard.h
Normal file
7
Devices/m5stack-papers3/Source/devices/SdCard.h
Normal file
@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "Tactility/hal/sdcard/SdCardDevice.h"
|
||||
|
||||
using tt::hal::sdcard::SdCardDevice;
|
||||
|
||||
std::shared_ptr<SdCardDevice> createSdCard();
|
||||
23
Devices/m5stack-papers3/Source/module.cpp
Normal file
23
Devices/m5stack-papers3/Source/module.cpp
Normal file
@ -0,0 +1,23 @@
|
||||
#include <tactility/module.h>
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
}
|
||||
27
Devices/m5stack-papers3/device.properties
Normal file
27
Devices/m5stack-papers3/device.properties
Normal file
@ -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
|
||||
|
||||
|
||||
3
Devices/m5stack-papers3/devicetree.yaml
Normal file
3
Devices/m5stack-papers3/devicetree.yaml
Normal file
@ -0,0 +1,3 @@
|
||||
dependencies:
|
||||
- Platforms/PlatformEsp32
|
||||
dts: m5stack,papers3.dts
|
||||
25
Devices/m5stack-papers3/m5stack,papers3.dts
Normal file
25
Devices/m5stack-papers3/m5stack,papers3.dts
Normal file
@ -0,0 +1,25 @@
|
||||
/dts-v1/;
|
||||
|
||||
#include <tactility/bindings/root.h>
|
||||
#include <tactility/bindings/esp32_gpio.h>
|
||||
#include <tactility/bindings/esp32_i2c.h>
|
||||
|
||||
/ {
|
||||
compatible = "root";
|
||||
model = "M5Stack PaperS3";
|
||||
|
||||
gpio0 {
|
||||
compatible = "espressif,esp32-gpio";
|
||||
gpio-count = <49>;
|
||||
};
|
||||
|
||||
i2c_internal {
|
||||
compatible = "espressif,esp32-i2c";
|
||||
port = <I2C_NUM_0>;
|
||||
clock-frequency = <400000>;
|
||||
pin-sda = <41>;
|
||||
pin-scl = <42>;
|
||||
pin-sda-pullup;
|
||||
pin-scl-pullup;
|
||||
};
|
||||
};
|
||||
5
Drivers/FastEpdDisplay/CMakeLists.txt
Normal file
5
Drivers/FastEpdDisplay/CMakeLists.txt
Normal file
@ -0,0 +1,5 @@
|
||||
idf_component_register(
|
||||
SRC_DIRS "Source"
|
||||
INCLUDE_DIRS "Source"
|
||||
REQUIRES FastEPD TactilityCore Tactility
|
||||
)
|
||||
256
Drivers/FastEpdDisplay/Source/FastEpdDisplay.cpp
Normal file
256
Drivers/FastEpdDisplay/Source/FastEpdDisplay.cpp
Normal file
@ -0,0 +1,256 @@
|
||||
#include "FastEpdDisplay.h"
|
||||
|
||||
#include <tactility/log.h>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
#include <esp_heap_caps.h>
|
||||
#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<FastEpdDisplay*>(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;
|
||||
}
|
||||
65
Drivers/FastEpdDisplay/Source/FastEpdDisplay.h
Normal file
65
Drivers/FastEpdDisplay/Source/FastEpdDisplay.h
Normal file
@ -0,0 +1,65 @@
|
||||
#pragma once
|
||||
|
||||
#include <Tactility/Lock.h>
|
||||
#include <Tactility/hal/display/DisplayDevice.h>
|
||||
#include <Tactility/hal/touch/TouchDevice.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <FastEPD.h>
|
||||
#include <lvgl.h>
|
||||
|
||||
class FastEpdDisplay final : public tt::hal::display::DisplayDevice {
|
||||
public:
|
||||
struct Configuration final {
|
||||
int horizontalResolution;
|
||||
int verticalResolution;
|
||||
std::shared_ptr<tt::hal::touch::TouchDevice> touch;
|
||||
uint32_t busSpeedHz = 20000000;
|
||||
int rotationDegrees = 90;
|
||||
bool use4bppGrayscale = false;
|
||||
uint32_t fullRefreshEveryNFlushes = 0;
|
||||
};
|
||||
|
||||
private:
|
||||
Configuration configuration;
|
||||
std::shared_ptr<tt::Lock> 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<tt::Lock> 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<tt::hal::display::DisplayDriver> getDisplayDriver() override { return nullptr; }
|
||||
|
||||
std::shared_ptr<tt::hal::touch::TouchDevice> getTouchDevice() override {
|
||||
return configuration.touch;
|
||||
}
|
||||
};
|
||||
@ -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
|
||||
|
||||
@ -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'
|
||||
|
||||
|
||||
@ -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<touch::TouchDevice> getTouchDevice() = 0;
|
||||
|
||||
|
||||
@ -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")
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user