Driver improvements (#226)

- Created driver subprojects: `FT5x06`, `FT6x36`, `CST816S`.
- Refactored existing projects to use new drivers.
- Improve `PwmBacklight` driver: expose frequency, channel id and timer id
- Update `build-and-release-all.sh` for recent board addition
This commit is contained in:
Ken Van Hoeylandt 2025-02-20 22:41:56 +01:00 committed by GitHub
parent 6e8fbae62b
commit 933bc5fb97
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
49 changed files with 429 additions and 413 deletions

View File

@ -3,5 +3,5 @@ file(GLOB_RECURSE SOURCE_FILES Source/*.c*)
idf_component_register(
SRCS ${SOURCE_FILES}
INCLUDE_DIRS "Source"
REQUIRES Tactility esp_lvgl_port esp_lcd_touch_cst816s ILI934x driver vfs fatfs
REQUIRES Tactility esp_lvgl_port ILI934x CST816S PwmBacklight driver vfs fatfs
)

View File

@ -1,14 +1,19 @@
#include "CYD2432S024C.h"
#include "Tactility/lvgl/LvglSync.h"
#include "hal/YellowDisplay.h"
#include "hal/YellowDisplayConstants.h"
#include "hal/YellowSdCard.h"
#include <Tactility/lvgl/LvglSync.h>
#include <PwmBacklight.h>
#define CYD_SPI_TRANSFER_SIZE_LIMIT (TWODOTFOUR_LCD_DRAW_BUFFER_SIZE * LV_COLOR_DEPTH / 8)
bool twodotfour_lvgl_init();
bool initBoot() {
return driver::pwmbacklight::init(TWODOTFOUR_LCD_PIN_BACKLIGHT);
}
const tt::hal::Configuration cyd_2432S024c_config = {
.initBoot = initBoot,
.createDisplay = createDisplay,
.sdcard = createYellowSdCard(),
.power = nullptr,

View File

@ -1,79 +1,24 @@
#include "YellowDisplay.h"
#include "Ili934xDisplay.h"
#include "Cst816Touch.h"
#include "YellowDisplayConstants.h"
#include "YellowTouch.h"
#include <Tactility/Log.h>
#include <Tactility/TactilityCore.h>
#include <esp_lcd_panel_commands.h>
#include <Ili934xDisplay.h>
#include <PwmBacklight.h>
#include <driver/gpio.h>
#include <driver/ledc.h>
#include <esp_err.h>
#include <esp_lcd_ili9341.h>
#include <esp_lcd_panel_ops.h>
#include <esp_lvgl_port.h>
static std::shared_ptr<tt::hal::touch::TouchDevice> createTouch() {
// Note: GPIO 25 for reset and GPIO 21 for interrupt?
auto configuration = std::make_unique<Cst816sTouch::Configuration>(
I2C_NUM_0,
240,
320
);
#define TAG "yellow_display"
static bool isBacklightInitialized = false;
static bool initBacklight() {
ledc_timer_config_t ledc_timer = {
.speed_mode = TWODOTFOUR_LCD_BACKLIGHT_LEDC_MODE,
.duty_resolution = TWODOTFOUR_LCD_BACKLIGHT_LEDC_DUTY_RES,
.timer_num = TWODOTFOUR_LCD_BACKLIGHT_LEDC_TIMER,
.freq_hz = TWODOTFOUR_LCD_BACKLIGHT_LEDC_FREQUENCY,
.clk_cfg = LEDC_AUTO_CLK,
.deconfigure = false
};
if (ledc_timer_config(&ledc_timer) != ESP_OK) {
TT_LOG_E(TAG, "Backlight led timer config failed");
return false;
}
return true;
return std::make_shared<Cst816sTouch>(std::move(configuration));
}
static bool setBacklight(uint8_t duty) {
ledc_channel_config_t ledc_channel = {
.gpio_num = TWODOTFOUR_LCD_PIN_BACKLIGHT,
.speed_mode = TWODOTFOUR_LCD_BACKLIGHT_LEDC_MODE,
.channel = TWODOTFOUR_LCD_BACKLIGHT_LEDC_CHANNEL,
.intr_type = LEDC_INTR_DISABLE,
.timer_sel = TWODOTFOUR_LCD_BACKLIGHT_LEDC_TIMER,
.duty = duty,
.hpoint = 0,
.sleep_mode = LEDC_SLEEP_MODE_NO_ALIVE_NO_PD,
.flags = {
.output_invert = false
}
};
if (ledc_channel_config(&ledc_channel) != ESP_OK) {
TT_LOG_E(TAG, "Backlight init failed");
return false;
}
return true;
}
void setBacklightDuty(uint8_t backlightDuty) {
if (!isBacklightInitialized) {
tt_check(initBacklight());
isBacklightInitialized = true;
}
if (!setBacklight(backlightDuty)) {
TT_LOG_E(TAG, "Failed to configure display backlight");
}
}
std::shared_ptr<tt::hal::display::DisplayDevice> createDisplay() {
auto touch = std::make_shared<YellowTouch>();
auto touch = createTouch();
auto configuration = std::make_unique<Ili934xDisplay::Configuration>(
TWODOTFOUR_LCD_SPI_HOST,
@ -85,7 +30,7 @@ std::shared_ptr<tt::hal::display::DisplayDevice> createDisplay() {
);
configuration->mirrorX = true;
configuration->backlightDutyFunction = ::setBacklightDuty;
configuration->backlightDutyFunction = driver::pwmbacklight::setBacklightDuty;
return std::make_shared<Ili934xDisplay>(std::move(configuration));
}

View File

@ -1,19 +1,11 @@
#pragma once
// Display backlight (PWM)
#define TWODOTFOUR_LCD_BACKLIGHT_LEDC_TIMER LEDC_TIMER_0
#define TWODOTFOUR_LCD_BACKLIGHT_LEDC_MODE LEDC_LOW_SPEED_MODE
#define TWODOTFOUR_LCD_BACKLIGHT_LEDC_CHANNEL LEDC_CHANNEL_0
#define TWODOTFOUR_LCD_BACKLIGHT_LEDC_DUTY_RES LEDC_TIMER_8_BIT
#define TWODOTFOUR_LCD_BACKLIGHT_LEDC_FREQUENCY (1000)
#define TWODOTFOUR_LCD_PIN_BACKLIGHT GPIO_NUM_27
// Display
#define TWODOTFOUR_LCD_SPI_HOST SPI2_HOST
#define TWODOTFOUR_LCD_HORIZONTAL_RESOLUTION 240
#define TWODOTFOUR_LCD_VERTICAL_RESOLUTION 320
#define TWODOTFOUR_LCD_BITS_PER_PIXEL 16
#define TWODOTFOUR_LCD_DRAW_BUFFER_HEIGHT (TWODOTFOUR_LCD_VERTICAL_RESOLUTION / 10)
#define TWODOTFOUR_LCD_DRAW_BUFFER_SIZE (TWODOTFOUR_LCD_HORIZONTAL_RESOLUTION * TWODOTFOUR_LCD_DRAW_BUFFER_HEIGHT)
#define TWODOTFOUR_LCD_PIN_CS GPIO_NUM_15

View File

@ -1,25 +0,0 @@
#pragma once
#include "Tactility/hal/touch/TouchDevice.h"
#include <Tactility/TactilityCore.h>
#include <esp_lcd_touch.h>
class YellowTouch : public tt::hal::touch::TouchDevice {
private:
esp_lcd_panel_io_handle_t ioHandle = nullptr;
esp_lcd_touch_handle_t touchHandle = nullptr;
lv_indev_t* _Nullable deviceHandle = nullptr;
void cleanup();
public:
std::string getName() const final { return "CST816S"; }
std::string getDescription() const final { return "I2C touch driver"; }
bool start(lv_display_t* display) override;
bool stop() override;
lv_indev_t* _Nullable getLvglIndev() override { return deviceHandle; }
};

View File

@ -3,5 +3,5 @@ file(GLOB_RECURSE SOURCE_FILES Source/*.c*)
idf_component_register(
SRCS ${SOURCE_FILES}
INCLUDE_DIRS "Source"
REQUIRES Tactility esp_lvgl_port esp_lcd esp_lcd_touch_ft5x06 ST7789 PwmBacklight driver esp_adc
REQUIRES Tactility esp_lvgl_port FT5x06 ST7789 PwmBacklight driver
)

View File

@ -6,7 +6,7 @@
#include <Tactility/hal/Configuration.h>
#define CROWPANEL_SPI_TRANSFER_SIZE_LIMIT (CROWPANEL_LCD_HORIZONTAL_RESOLUTION * CROWPANEL_LCD_SPI_TRANSFER_HEIGHT * (CROWPANEL_LCD_BITS_PER_PIXEL / 8))
#define CROWPANEL_SPI_TRANSFER_SIZE_LIMIT (CROWPANEL_LCD_HORIZONTAL_RESOLUTION * CROWPANEL_LCD_SPI_TRANSFER_HEIGHT * (LV_COLOR_DEPTH / 8))
using namespace tt::hal;

View File

@ -1,16 +1,28 @@
#include "CrowPanelDisplay.h"
#include "CrowPanelDisplayConstants.h"
#include "CrowPanelTouch.h"
#include <St7789Display.h>
#include <Ft5x06Touch.h>
#include <PwmBacklight.h>
#include <Tactility/Log.h>
#include <St7789Display.h>
#define TAG "crowpanel_display"
static std::shared_ptr<tt::hal::touch::TouchDevice> createTouch() {
// Note for future changes: Reset pin is 48 and interrupt pin is 47
auto configuration = std::make_unique<Ft5x06Touch::Configuration>(
I2C_NUM_0,
240,
320,
true,
true,
false
);
return std::make_shared<Ft5x06Touch>(std::move(configuration));
}
std::shared_ptr<tt::hal::display::DisplayDevice> createDisplay() {
auto touch = std::make_shared<CrowPanelTouch>();
auto touch = createTouch();
auto configuration = std::make_unique<St7789Display::Configuration>(
CROWPANEL_LCD_SPI_HOST,

View File

@ -5,13 +5,4 @@
#define CROWPANEL_LCD_PIN_DC GPIO_NUM_41 // RS
#define CROWPANEL_LCD_HORIZONTAL_RESOLUTION 320
#define CROWPANEL_LCD_VERTICAL_RESOLUTION 240
#define CROWPANEL_LCD_BITS_PER_PIXEL 16
#define CROWPANEL_LCD_SPI_TRANSFER_HEIGHT (CROWPANEL_LCD_VERTICAL_RESOLUTION / 10)
// Backlight (PWM)
#define CROWPANEL_LCD_BACKLIGHT_LEDC_TIMER LEDC_TIMER_0
#define CROWPANEL_LCD_BACKLIGHT_LEDC_MODE LEDC_LOW_SPEED_MODE
#define CROWPANEL_LCD_BACKLIGHT_LEDC_CHANNEL LEDC_CHANNEL_0
#define CROWPANEL_LCD_BACKLIGHT_LEDC_DUTY_RES LEDC_TIMER_8_BIT
#define CROWPANEL_LCD_BACKLIGHT_LEDC_FREQUENCY (4000)

View File

@ -1,25 +0,0 @@
#pragma once
#include "Tactility/hal/touch/TouchDevice.h"
#include <Tactility/TactilityCore.h>
#include <esp_lcd_panel_io_interface.h>
#include <esp_lcd_touch.h>
class CrowPanelTouch : public tt::hal::touch::TouchDevice {
private:
std::string getName() const final { return "GT911"; }
std::string getDescription() const final { return "I2C Touch Driver"; }
esp_lcd_panel_io_handle_t _Nullable ioHandle = nullptr;
esp_lcd_touch_handle_t _Nullable touchHandle = nullptr;
lv_indev_t* _Nullable deviceHandle = nullptr;
void cleanup();
public:
bool start(lv_display_t* display) override;
bool stop() override;
lv_indev_t* _Nullable getLvglIndev() override { return deviceHandle; }
};

View File

@ -3,5 +3,5 @@ file(GLOB_RECURSE SOURCE_FILES Source/*.c*)
idf_component_register(
SRCS ${SOURCE_FILES}
INCLUDE_DIRS "Source"
REQUIRES Tactility esp_lvgl_port esp_lcd ILI934x XPT2046 PwmBacklight driver esp_adc
REQUIRES Tactility esp_lvgl_port ILI934x XPT2046 PwmBacklight driver
)

View File

@ -7,7 +7,7 @@
#include <Xpt2046Power.h>
#include <Tactility/hal/Configuration.h>
#define CROWPANEL_SPI_TRANSFER_SIZE_LIMIT (CROWPANEL_LCD_HORIZONTAL_RESOLUTION * CROWPANEL_LCD_SPI_TRANSFER_HEIGHT * (CROWPANEL_LCD_BITS_PER_PIXEL / 8))
#define CROWPANEL_SPI_TRANSFER_SIZE_LIMIT (CROWPANEL_LCD_HORIZONTAL_RESOLUTION * CROWPANEL_LCD_SPI_TRANSFER_HEIGHT * (LV_COLOR_DEPTH / 8))
using namespace tt::hal;

View File

@ -1,13 +1,24 @@
#include "CrowPanelDisplay.h"
#include "CrowPanelDisplayConstants.h"
#include "CrowPanelTouch.h"
#include "Ili934xDisplay.h"
#include <Ili934xDisplay.h>
#include <Xpt2046Touch.h>
#include <PwmBacklight.h>
#include <Tactility/Log.h>
std::shared_ptr<Xpt2046Touch> createTouch() {
auto configuration = std::make_unique<Xpt2046Touch::Configuration>(
CROWPANEL_LCD_SPI_HOST,
CROWPANEL_TOUCH_PIN_CS,
240,
320,
false,
true,
false
);
#define TAG "crowpanel_display"
return std::make_shared<Xpt2046Touch>(std::move(configuration));
}
std::shared_ptr<tt::hal::display::DisplayDevice> createDisplay() {
auto touch = createTouch();

View File

@ -6,13 +6,4 @@
#define CROWPANEL_LCD_PIN_DC GPIO_NUM_2 // RS
#define CROWPANEL_LCD_HORIZONTAL_RESOLUTION 320
#define CROWPANEL_LCD_VERTICAL_RESOLUTION 240
#define CROWPANEL_LCD_BITS_PER_PIXEL 16
#define CROWPANEL_LCD_SPI_TRANSFER_HEIGHT (CROWPANEL_LCD_VERTICAL_RESOLUTION / 10)
// Backlight (PWM)
#define CROWPANEL_LCD_BACKLIGHT_LEDC_TIMER LEDC_TIMER_0
#define CROWPANEL_LCD_BACKLIGHT_LEDC_MODE LEDC_LOW_SPEED_MODE
#define CROWPANEL_LCD_BACKLIGHT_LEDC_CHANNEL LEDC_CHANNEL_0
#define CROWPANEL_LCD_BACKLIGHT_LEDC_DUTY_RES LEDC_TIMER_8_BIT
#define CROWPANEL_LCD_BACKLIGHT_LEDC_FREQUENCY (4000)

View File

@ -1,16 +0,0 @@
#include "CrowPanelTouch.h"
#include "CrowPanelDisplayConstants.h"
std::shared_ptr<Xpt2046Touch> createTouch() {
auto configuration = std::make_unique<Xpt2046Touch::Configuration>(
CROWPANEL_LCD_SPI_HOST,
GPIO_NUM_33,
240,
320,
false,
true,
false
);
return std::make_shared<Xpt2046Touch>(std::move(configuration));
}

View File

@ -1,6 +0,0 @@
#pragma once
#include <memory>
#include <Xpt2046Touch.h>
std::shared_ptr<Xpt2046Touch> createTouch();

View File

@ -34,7 +34,10 @@ bool tdeckInit() {
return false;
}
if (!driver::pwmbacklight::init(GPIO_NUM_42)) {
/* 32 Khz and higher gives an issue where the screen starts dimming again above 80% brightness
* when moving the brightness slider rapidly from a lower setting to 100%.
* This is not a slider bug (data was debug-traced) */
if (!driver::pwmbacklight::init(GPIO_NUM_42, 30000)) {
TT_LOG_E(TAG, "Backlight init failed");
return false;
}

View File

@ -7,7 +7,7 @@
#include <Tactility/hal/Configuration.h>
#define TDECK_SPI_TRANSFER_SIZE_LIMIT (TDECK_LCD_HORIZONTAL_RESOLUTION * TDECK_LCD_SPI_TRANSFER_HEIGHT * (TDECK_LCD_BITS_PER_PIXEL / 8))
#define TDECK_SPI_TRANSFER_SIZE_LIMIT (TDECK_LCD_HORIZONTAL_RESOLUTION * TDECK_LCD_SPI_TRANSFER_HEIGHT * (LV_COLOR_DEPTH / 8))
bool tdeckInit();

View File

@ -5,5 +5,4 @@
#define TDECK_LCD_PIN_DC GPIO_NUM_11 // RS
#define TDECK_LCD_HORIZONTAL_RESOLUTION 320
#define TDECK_LCD_VERTICAL_RESOLUTION 240
#define TDECK_LCD_BITS_PER_PIXEL 16
#define TDECK_LCD_SPI_TRANSFER_HEIGHT (TDECK_LCD_VERTICAL_RESOLUTION / 10)

View File

@ -3,5 +3,5 @@ file(GLOB_RECURSE SOURCE_FILES Source/*.c*)
idf_component_register(
SRCS ${SOURCE_FILES}
INCLUDE_DIRS "Source"
REQUIRES Tactility esp_lvgl_port esp_lcd ILI934x driver vfs fatfs
REQUIRES Tactility esp_lvgl_port esp_lcd ILI934x FT6x36 driver vfs fatfs
)

View File

@ -1,10 +1,19 @@
#include "Core2Display.h"
#include "Core2Touch.h"
#include <Ft6x36Touch.h>
#include <Ili934xDisplay.h>
std::shared_ptr<tt::hal::touch::TouchDevice> createTouch() {
auto configuration = std::make_unique<Ft6x36Touch::Configuration>(
I2C_NUM_0,
GPIO_NUM_39
);
return std::make_shared<Ft6x36Touch>(std::move(configuration));
}
std::shared_ptr<tt::hal::display::DisplayDevice> createDisplay() {
auto touch = std::make_shared<Core2Touch>();
auto touch = createTouch();
auto configuration = std::make_unique<Ili934xDisplay::Configuration>(
CORE2_LCD_SPI_HOST,
@ -12,10 +21,12 @@ std::shared_ptr<tt::hal::display::DisplayDevice> createDisplay() {
CORE2_LCD_PIN_DC,
CORE2_LCD_HORIZONTAL_RESOLUTION,
CORE2_LCD_VERTICAL_RESOLUTION,
touch
touch,
false,
false,
false,
true
);
configuration->mirrorX = true;
return std::make_shared<Ili934xDisplay>(std::move(configuration));
}

View File

@ -1,35 +0,0 @@
#pragma once
#include "Tactility/hal/touch/TouchDevice.h"
#include "ft6x36/FT6X36.h"
#include <Tactility/TactilityCore.h>
class Core2Touch : public tt::hal::touch::TouchDevice {
private:
lv_indev_t* _Nullable deviceHandle = nullptr;
FT6X36 driver = FT6X36(I2C_NUM_0, GPIO_NUM_39);
tt::Thread driverThread;
bool interruptDriverThread = false;
tt::Mutex mutex;
lv_point_t lastPoint = { .x = 0, .y = 0 };
lv_indev_state_t lastState = LV_INDEV_STATE_RELEASED;
bool shouldInterruptDriverThread();
public:
Core2Touch();
std::string getName() const final { return "FT6336U"; }
std::string getDescription() const final { return "I2C touch driver"; }
bool start(lv_display_t* display) override;
bool stop() override;
void readLast(lv_indev_data_t* data);
lv_indev_t* _Nullable getLvglIndev() override { return deviceHandle; }
void driverThreadMain();
};

View File

@ -1,5 +1,5 @@
idf_component_register(
SRC_DIRS "Source" "Source/hal"
INCLUDE_DIRS "Source"
REQUIRES Tactility esp_lvgl_port esp_lcd esp_lcd_ili9341 ILI934x AXP2101 AW9523 esp_lcd_touch_ft5x06 driver vfs fatfs
REQUIRES Tactility esp_lvgl_port ILI934x FT5x06 AXP2101 AW9523 driver vfs fatfs
)

View File

@ -1,25 +1,35 @@
#include "CoreS3Display.h"
#include "CoreS3Constants.h"
#include "CoreS3Touch.h"
#include <Ft5x06Touch.h>
#include <Ili934xDisplay.h>
#include <Tactility/Log.h>
#include <Tactility/hal/i2c/I2c.h>
#include <Ili934xDisplay.h>
#define TAG "cores3"
static void setBacklightDuty(uint8_t backlightDuty) {
const uint8_t voltage = 20 + ((8 * backlightDuty) / 255); // [0b00000, 0b11100] - under 20 is too dark
// TODO: Refactor to use Axp2102 class with https://github.com/m5stack/M5Unified/blob/b8cfec7fed046242da7f7b8024a4e92004a51ff7/src/utility/AXP2101_Class.cpp#L42
// TODO: Refactor to use Axp2102 driver subproject. Reference: https://github.com/m5stack/M5Unified/blob/b8cfec7fed046242da7f7b8024a4e92004a51ff7/src/utility/AXP2101_Class.cpp#L42
if (!tt::hal::i2c::masterWriteRegister(I2C_NUM_0, AXP2101_ADDRESS, 0x99, &voltage, 1, 1000)) { // Sets DLD01
TT_LOG_E(TAG, "Failed to set display backlight voltage");
}
}
static std::shared_ptr<tt::hal::touch::TouchDevice> createTouch() {
// Note for future changes: Reset pin is 48 and interrupt pin is 47
auto configuration = std::make_unique<Ft5x06Touch::Configuration>(
I2C_NUM_0,
320,
240
);
return std::make_shared<Ft5x06Touch>(std::move(configuration));
}
std::shared_ptr<tt::hal::display::DisplayDevice> createDisplay() {
auto touch = std::make_shared<CoreS3Touch>();
auto touch = createTouch();
auto configuration = std::make_unique<Ili934xDisplay::Configuration>(
SPI3_HOST,
@ -27,7 +37,11 @@ std::shared_ptr<tt::hal::display::DisplayDevice> createDisplay() {
GPIO_NUM_35,
320,
240,
touch
touch,
false,
false,
false,
true
);
configuration->backlightDutyFunction = ::setBacklightDuty;

View File

@ -6,6 +6,5 @@
#define CORES3_LCD_PIN_DC GPIO_NUM_35
#define CORES3_LCD_HORIZONTAL_RESOLUTION 320
#define CORES3_LCD_VERTICAL_RESOLUTION 240
#define CORES3_LCD_BITS_PER_PIXEL 16
#define CORES3_LCD_DRAW_BUFFER_HEIGHT (CORES3_LCD_VERTICAL_RESOLUTION / 10)
#define CORES3_LCD_DRAW_BUFFER_SIZE (CORES3_LCD_HORIZONTAL_RESOLUTION * CORES3_LCD_DRAW_BUFFER_HEIGHT)

View File

@ -1,83 +0,0 @@
#include "CoreS3Touch.h"
#include <Tactility/Log.h>
#include "driver/i2c.h"
#include "esp_err.h"
#include "esp_lcd_touch_ft5x06.h"
#include "esp_lcd_touch.h"
#include "esp_lvgl_port.h"
#define TAG "cores3"
bool CoreS3Touch::start(lv_display_t* display) {
TT_LOG_I(TAG, "Touch start");
esp_lcd_panel_io_i2c_config_t touch_io_config = ESP_LCD_TOUCH_IO_I2C_FT5x06_CONFIG();
if (esp_lcd_new_panel_io_i2c(I2C_NUM_0, &touch_io_config, &ioHandle) != ESP_OK) {
TT_LOG_E(TAG, "Touch I2C IO init failed");
return false;
}
esp_lcd_touch_config_t config = {
.x_max = 320,
.y_max = 240,
.rst_gpio_num = GPIO_NUM_NC,
.int_gpio_num = GPIO_NUM_NC,
.levels = {
.reset = 0,
.interrupt = 0,
},
.flags = {
.swap_xy = 0,
.mirror_x = 0,
.mirror_y = 0,
},
.process_coordinates = nullptr,
.interrupt_callback = nullptr,
.user_data = nullptr,
.driver_data = nullptr
};
if (esp_lcd_touch_new_i2c_ft5x06(ioHandle, &config, &touchHandle) != ESP_OK) {
TT_LOG_E(TAG, "Touch driver init failed");
cleanup();
return false;
}
const lvgl_port_touch_cfg_t touch_cfg = {
.disp = display,
.handle = touchHandle,
};
deviceHandle = lvgl_port_add_touch(&touch_cfg);
if (deviceHandle == nullptr) {
TT_LOG_E(TAG, "Touch lvgl port failure");
cleanup();
return false;
}
TT_LOG_I(TAG, "Finished");
return true;
}
bool CoreS3Touch::stop() {
cleanup();
return true;
}
void CoreS3Touch::cleanup() {
if (deviceHandle != nullptr) {
lv_indev_delete(deviceHandle);
deviceHandle = nullptr;
}
if (touchHandle != nullptr) {
esp_lcd_touch_del(touchHandle);
touchHandle = nullptr;
}
if (ioHandle != nullptr) {
esp_lcd_panel_io_del(ioHandle);
ioHandle = nullptr;
}
}

View File

@ -1,25 +0,0 @@
#pragma once
#include "Tactility/hal/touch/TouchDevice.h"
#include <Tactility/TactilityCore.h>
#include <esp_lcd_touch.h>
class CoreS3Touch : public tt::hal::touch::TouchDevice {
private:
esp_lcd_panel_io_handle_t ioHandle = nullptr;
esp_lcd_touch_handle_t touchHandle = nullptr;
lv_indev_t* _Nullable deviceHandle = nullptr;
void cleanup();
public:
std::string getName() const final { return "FT6336U"; }
std::string getDescription() const final { return "I2C touch driver"; }
bool start(lv_display_t* display) override;
bool stop() override;
lv_indev_t* _Nullable getLvglIndev() override { return deviceHandle; }
};

View File

@ -17,6 +17,9 @@ SECONDS=0
build elecrow-crowpanel-advance-28
release elecrow-crowpanel-advance-28
build elecrow-crowpanel-basic-28
release elecrow-crowpanel-basic-28
build lilygo-tdeck
release lilygo-tdeck

View File

@ -32,6 +32,7 @@
- External app loading: Check version of Tactility and check ESP target hardware, to check for compatibility.
- Scanning SD card for external apps and auto-register them (in a temporary register?)
- Support hot-plugging SD card
- All drivers (e.g. display, touch, etc.) should call stop() in their destructor, or at least assert that they should not be running.
# Nice-to-haves
- CoreS3 has a hardware issue that prevents mounting SD cards while using the display too: allow USB Mass Storage to use `/data` instead? Perhaps give the USB settings app a drop down to select the root filesystem to attach.

View File

@ -0,0 +1,5 @@
idf_component_register(
SRC_DIRS "Source"
INCLUDE_DIRS "Source"
REQUIRES Tactility esp_lvgl_port esp_lcd_touch esp_lcd_touch_cst816s driver
)

View File

@ -0,0 +1,3 @@
# CST816S
I2C touch driver for Tactility

View File

@ -0,0 +1,69 @@
#pragma once
#include <Tactility/hal/touch/TouchDevice.h>
#include <esp_lcd_touch.h>
class Cst816sTouch final : public tt::hal::touch::TouchDevice {
public:
class Configuration {
public:
Configuration(
i2c_port_t port,
uint16_t xMax,
uint16_t yMax,
bool swapXy = false,
bool mirrorX = false,
bool mirrorY = false,
gpio_num_t pinReset = GPIO_NUM_NC,
gpio_num_t pinInterrupt = GPIO_NUM_NC,
unsigned int pinResetLevel = 0,
unsigned int pinInterruptLevel = 0
) : port(port),
xMax(xMax),
yMax(yMax),
swapXY(swapXy),
mirrorX(mirrorX),
mirrorY(mirrorY),
pinReset(pinReset),
pinInterrupt(pinInterrupt),
pinResetLevel(pinResetLevel),
pinInterruptLevel(pinInterruptLevel)
{}
i2c_port_t port;
uint16_t xMax;
uint16_t yMax;
bool swapXY;
bool mirrorX;
bool mirrorY;
gpio_num_t pinReset;
gpio_num_t pinInterrupt;
unsigned int pinResetLevel;
unsigned int pinInterruptLevel;
};
private:
std::unique_ptr<Configuration> configuration;
esp_lcd_panel_io_handle_t ioHandle = nullptr;
esp_lcd_touch_handle_t touchHandle = nullptr;
lv_indev_t* _Nullable deviceHandle = nullptr;
void cleanup();
public:
explicit Cst816sTouch(std::unique_ptr<Configuration> inConfiguration) : configuration(std::move(inConfiguration)) {
assert(configuration != nullptr);
}
std::string getName() const final { return "CST816S"; }
std::string getDescription() const final { return "I2C touch driver"; }
bool start(lv_display_t* display) override;
bool stop() override;
lv_indev_t* _Nullable getLvglIndev() override { return deviceHandle; }
};

View File

@ -1,36 +1,37 @@
#include "YellowTouch.h"
#include "YellowTouchConstants.h"
#include "Cst816Touch.h"
#include <Tactility/Log.h>
#include "driver/i2c.h"
#include "esp_err.h"
#include "esp_lcd_touch_cst816s.h"
#include "esp_lcd_touch.h"
#include "esp_lvgl_port.h"
#define TAG "twodotfour_touch"
#include <driver/i2c.h>
#include <esp_err.h>
#include <esp_lcd_touch.h>
#include <esp_lcd_touch_cst816s.h>
#include <esp_lvgl_port.h>
bool YellowTouch::start(lv_display_t* display) {
#define TAG "cst816s"
bool Cst816sTouch::start(lv_display_t* display) {
TT_LOG_I(TAG, "Starting");
const esp_lcd_panel_io_i2c_config_t touch_io_config = ESP_LCD_TOUCH_IO_I2C_CST816S_CONFIG();
if (esp_lcd_new_panel_io_i2c((esp_lcd_i2c_bus_handle_t)TWODOTFOUR_TOUCH_I2C_PORT, &touch_io_config, &ioHandle) != ESP_OK) {
if (esp_lcd_new_panel_io_i2c((esp_lcd_i2c_bus_handle_t)configuration->port, &touch_io_config, &ioHandle) != ESP_OK) {
TT_LOG_E(TAG, "Touch I2C IO init failed");
return false;
}
esp_lcd_touch_config_t config = {
.x_max = 240,
.y_max = 320,
.rst_gpio_num = GPIO_NUM_NC, //GPIO_NUM_25,
.int_gpio_num = GPIO_NUM_NC, //GPIO_NUM_21,
.x_max = configuration->xMax,
.y_max = configuration->yMax,
.rst_gpio_num = configuration->pinReset,
.int_gpio_num = configuration->pinInterrupt,
.levels = {
.reset = 0,
.interrupt = 0,
.reset = configuration->pinResetLevel,
.interrupt = configuration->pinInterruptLevel,
},
.flags = {
.swap_xy = 0,
.mirror_x = 0,
.mirror_y = 0,
.swap_xy = configuration->swapXY,
.mirror_x = configuration->mirrorX,
.mirror_y = configuration->mirrorY,
},
.process_coordinates = nullptr,
.interrupt_callback = nullptr,
@ -60,12 +61,12 @@ bool YellowTouch::start(lv_display_t* display) {
return true;
}
bool YellowTouch::stop() {
bool Cst816sTouch::stop() {
cleanup();
return true;
}
void YellowTouch::cleanup() {
void Cst816sTouch::cleanup() {
if (deviceHandle != nullptr) {
lv_indev_delete(deviceHandle);
deviceHandle = nullptr;

View File

@ -0,0 +1,5 @@
idf_component_register(
SRC_DIRS "Source"
INCLUDE_DIRS "Source"
REQUIRES Tactility esp_lvgl_port esp_lcd_touch esp_lcd_touch_ft5x06 driver
)

3
Drivers/FT5x06/README.md Normal file
View File

@ -0,0 +1,3 @@
# FT5x06
A Tactility driver for FT5x06 touch.

View File

@ -1,37 +1,34 @@
#include "CrowPanelTouch.h"
#include "esp_lcd_touch_ft5x06.h"
#include "Ft5x06Touch.h"
#include <Tactility/Log.h>
#include <esp_lcd_touch_ft5x06.h>
#include <esp_err.h>
#include <esp_lvgl_port.h>
#define TAG "crowpanel_touch"
#define TAG "ft5x06"
#define CROWPANEL_TOUCH_I2C_BUS_HANDLE I2C_NUM_0
#define CROWPANEL_TOUCH_X_MAX 240
#define CROWPANEL_TOUCH_Y_MAX 320
bool CrowPanelTouch::start(lv_display_t* display) {
bool Ft5x06Touch::start(lv_display_t* display) {
esp_lcd_panel_io_i2c_config_t io_config = ESP_LCD_TOUCH_IO_I2C_FT5x06_CONFIG();
if (esp_lcd_new_panel_io_i2c(CROWPANEL_TOUCH_I2C_BUS_HANDLE, &io_config, &ioHandle) != ESP_OK) {
TT_LOG_E(TAG, "touch io i2c creation failed");
if (esp_lcd_new_panel_io_i2c(configuration->port, &io_config, &ioHandle) != ESP_OK) {
TT_LOG_E(TAG, "Touch IO I2C creation failed");
return false;
}
esp_lcd_touch_config_t config = {
.x_max = CROWPANEL_TOUCH_X_MAX,
.y_max = CROWPANEL_TOUCH_Y_MAX,
.rst_gpio_num = GPIO_NUM_NC, // GPIO_NUM_48,
.int_gpio_num = GPIO_NUM_NC, // GPIO_NUM_47,
.x_max = configuration->xMax,
.y_max = configuration->yMax,
.rst_gpio_num = configuration->pinReset,
.int_gpio_num = configuration->pinInterrupt,
.levels = {
.reset = 0,
.interrupt = 0,
.reset = configuration->pinResetLevel,
.interrupt = configuration->pinInterruptLevel,
},
.flags = {
.swap_xy = 1,
.mirror_x = 1,
.mirror_y = 0,
.swap_xy = configuration->swapXy,
.mirror_x = configuration->mirrorX,
.mirror_y = configuration->mirrorY,
},
.process_coordinates = nullptr,
.interrupt_callback = nullptr,
@ -40,7 +37,7 @@ bool CrowPanelTouch::start(lv_display_t* display) {
};
if (esp_lcd_touch_new_i2c_ft5x06(ioHandle, &config, &touchHandle) != ESP_OK) {
TT_LOG_E(TAG, "GT911 driver init failed");
TT_LOG_E(TAG, "Driver init failed");
cleanup();
return false;
}
@ -61,12 +58,12 @@ bool CrowPanelTouch::start(lv_display_t* display) {
return true;
}
bool CrowPanelTouch::stop() {
bool Ft5x06Touch::stop() {
cleanup();
return true;
}
void CrowPanelTouch::cleanup() {
void Ft5x06Touch::cleanup() {
if (deviceHandle != nullptr) {
lv_indev_delete(deviceHandle);
deviceHandle = nullptr;

View File

@ -0,0 +1,73 @@
#pragma once
#include <Tactility/hal/touch/TouchDevice.h>
#include <Tactility/TactilityCore.h>
#include <driver/i2c.h>
#include <esp_lcd_panel_io_interface.h>
#include <esp_lcd_touch.h>
class Ft5x06Touch final : public tt::hal::touch::TouchDevice {
public:
class Configuration {
public:
Configuration(
i2c_port_t port,
uint16_t xMax,
uint16_t yMax,
bool swapXy = false,
bool mirrorX = false,
bool mirrorY = false,
gpio_num_t pinReset = GPIO_NUM_NC,
gpio_num_t pinInterrupt = GPIO_NUM_NC,
unsigned int pinResetLevel = 0,
unsigned int pinInterruptLevel = 0
) : port(port),
xMax(xMax),
yMax(yMax),
swapXy(swapXy),
mirrorX(mirrorX),
mirrorY(mirrorY),
pinReset(pinReset),
pinInterrupt(pinInterrupt),
pinResetLevel(pinResetLevel),
pinInterruptLevel(pinInterruptLevel)
{}
i2c_port_t port;
uint16_t xMax;
uint16_t yMax;
bool swapXy;
bool mirrorX;
bool mirrorY;
gpio_num_t pinReset;
gpio_num_t pinInterrupt;
unsigned int pinResetLevel;
unsigned int pinInterruptLevel;
};
private:
std::unique_ptr<Configuration> configuration;
esp_lcd_panel_io_handle_t _Nullable ioHandle = nullptr;
esp_lcd_touch_handle_t _Nullable touchHandle = nullptr;
lv_indev_t* _Nullable deviceHandle = nullptr;
void cleanup();
public:
explicit Ft5x06Touch(std::unique_ptr<Configuration> inConfiguration) : configuration(std::move(inConfiguration)) {
assert(configuration != nullptr);
}
bool start(lv_display_t* display) override;
bool stop() override;
lv_indev_t* _Nullable getLvglIndev() override { return deviceHandle; }
std::string getName() const final { return "FT5x06"; }
std::string getDescription() const final { return "I2C Touch Driver"; }
};

View File

@ -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 driver
)

3
Drivers/FT6x36/README.md Normal file
View File

@ -0,0 +1,3 @@
# FT6x36
A Tactility driver for FT6x36 touch.

View File

@ -1,24 +1,35 @@
#include "Core2Touch.h"
#include "Ft6x36Touch.h"
#include <Tactility/Log.h>
#include <esp_err.h>
#include <esp_lvgl_port.h>
#define TAG "core2_touch"
#define TAG "ft6x36"
static void touchReadCallback(lv_indev_t* indev, lv_indev_data_t* data) {
auto* touch = (Core2Touch*)lv_indev_get_driver_data(indev);
auto* touch = (Ft6x36Touch*)lv_indev_get_driver_data(indev);
touch->readLast(data);
}
static int32_t threadCallback(void* context) {
auto* touch = (Core2Touch*)context;
auto* touch = (Ft6x36Touch*)context;
touch->driverThreadMain();
return 0;
}
Core2Touch::Core2Touch() :
driverThread(tt::Thread("core2_touch", 4096, threadCallback, this))
{ }
Ft6x36Touch::Ft6x36Touch(std::unique_ptr<Configuration> inConfiguration) :
configuration(std::move(inConfiguration)),
driverThread(tt::Thread("ft6x36", 4096, threadCallback, this))
{}
void Core2Touch::driverThreadMain() {
Ft6x36Touch::~Ft6x36Touch() {
if (driverThread.getState() != tt::Thread::State::Stopped) {
stop();
}
}
void Ft6x36Touch::driverThreadMain() {
TPoint point = { .x = 0, .y = 0 };
TEvent event = TEvent::None;
@ -51,7 +62,7 @@ void Core2Touch::driverThreadMain() {
}
}
bool Core2Touch::shouldInterruptDriverThread() {
bool Ft6x36Touch::shouldInterruptDriverThread() {
bool interrupt = false;
if (mutex.lock(50 / portTICK_PERIOD_MS)) {
interrupt = interruptDriverThread;
@ -60,7 +71,7 @@ bool Core2Touch::shouldInterruptDriverThread() {
return interrupt;
}
bool Core2Touch::start(lv_display_t* display) {
bool Ft6x36Touch::start(lv_display_t* display) {
TT_LOG_I(TAG, "start");
driverThread.start();
@ -81,14 +92,14 @@ bool Core2Touch::start(lv_display_t* display) {
return true;
}
bool Core2Touch::stop() {
bool Ft6x36Touch::stop() {
lv_indev_delete(deviceHandle);
interruptDriverThread = true;
driverThread.join();
return true;
}
void Core2Touch::readLast(lv_indev_data_t* data) {
void Ft6x36Touch::readLast(lv_indev_data_t* data) {
data->point = lastPoint;
data->state = lastState;
}

View File

@ -0,0 +1,55 @@
#pragma once
#include <Tactility/hal/touch/TouchDevice.h>
#include <Tactility/TactilityCore.h>
#include <driver/i2c.h>
#include "ft6x36/FT6X36.h"
class Ft6x36Touch final : public tt::hal::touch::TouchDevice {
public:
class Configuration {
public:
Configuration(
i2c_port_t port,
gpio_num_t pinInterrupt
) : port(port),
pinInterrupt(pinInterrupt)
{}
i2c_port_t port;
gpio_num_t pinInterrupt;
};
private:
std::unique_ptr<Configuration> configuration;
lv_indev_t* _Nullable deviceHandle = nullptr;
FT6X36 driver = FT6X36(configuration->port, configuration->pinInterrupt);
tt::Thread driverThread;
bool interruptDriverThread = false;
tt::Mutex mutex;
lv_point_t lastPoint = { .x = 0, .y = 0 };
lv_indev_state_t lastState = LV_INDEV_STATE_RELEASED;
bool shouldInterruptDriverThread();
public:
explicit Ft6x36Touch(std::unique_ptr<Configuration> inConfiguration);
~Ft6x36Touch() final;
std::string getName() const final { return "FT6x36"; }
std::string getDescription() const final { return "I2C touch driver"; }
bool start(lv_display_t* display) override;
bool stop() override;
void readLast(lv_indev_data_t* data);
lv_indev_t* _Nullable getLvglIndev() override { return deviceHandle; }
void driverThreadMain();
};

View File

@ -1,10 +1,10 @@
#include <stdint.h>
#include <cstdio>
#include <cstdlib>
#include "driver/gpio.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include <stdio.h>
#include "esp_log.h"
#include "driver/i2c.h"
#include "sdkconfig.h"

View File

@ -8,7 +8,6 @@
#define TAG "ili934x"
bool Ili934xDisplay::start() {
TT_LOG_I(TAG, "Starting");
@ -67,6 +66,11 @@ bool Ili934xDisplay::start() {
return false;
}
if (esp_lcd_panel_swap_xy(panelHandle, configuration->swapXY) != ESP_OK) {
TT_LOG_E(TAG, "Failed to swap XY ");
return false;
}
if (esp_lcd_panel_mirror(panelHandle, configuration->mirrorX, configuration->mirrorY) != ESP_OK) {
TT_LOG_E(TAG, "Failed to set panel to mirror");
return false;
@ -81,6 +85,7 @@ bool Ili934xDisplay::start() {
TT_LOG_E(TAG, "Failed to turn display on");
return false;
}
uint32_t buffer_size;
if (configuration->bufferSize == 0) {
buffer_size = configuration->horizontalResolution * configuration->verticalResolution / 10;
@ -99,7 +104,7 @@ bool Ili934xDisplay::start() {
.vres = configuration->verticalResolution,
.monochrome = false,
.rotation = {
.swap_xy = false,
.swap_xy = configuration->swapXY,
.mirror_x = configuration->mirrorX,
.mirror_y = configuration->mirrorY,
},
@ -115,6 +120,7 @@ bool Ili934xDisplay::start() {
};
displayHandle = lvgl_port_add_disp(&disp_cfg);
TT_LOG_I(TAG, "Finished");
return displayHandle != nullptr;
}

View File

@ -23,12 +23,22 @@ public:
gpio_num_t dcPin,
unsigned int horizontalResolution,
unsigned int verticalResolution,
std::shared_ptr<tt::hal::touch::TouchDevice> touch
std::shared_ptr<tt::hal::touch::TouchDevice> touch,
bool swapXY = false,
bool mirrorX = false,
bool mirrorY = false,
bool invertColor = false,
uint32_t bufferSize = 0 // Size in pixel count. 0 means default, which is 1/10 of the screen size
) : spiBusHandle(spi_bus_handle),
csPin(csPin),
dcPin(dcPin),
horizontalResolution(horizontalResolution),
verticalResolution(verticalResolution),
swapXY(swapXY),
mirrorX(mirrorX),
mirrorY(mirrorY),
invertColor(invertColor),
bufferSize(bufferSize),
touch(std::move(touch))
{}
@ -40,6 +50,7 @@ public:
size_t transactionQueueDepth = 10;
unsigned int horizontalResolution;
unsigned int verticalResolution;
bool swapXY = false;
bool mirrorX = false;
bool mirrorY = false;
bool invertColor = false;

View File

@ -1,6 +1,6 @@
#include "PwmBacklight.h"
#include <Tactility/Log.h>
#include <driver/ledc.h>
#include <driver/gpio.h>
#define TAG "pwm_backlight"
@ -8,16 +8,20 @@ namespace driver::pwmbacklight {
static bool isBacklightInitialized = false;
static gpio_num_t backlightPin = GPIO_NUM_NC;
static ledc_timer_t backlightTimer;
static ledc_channel_t backlightChannel;
bool init(gpio_num_t pin) {
bool init(gpio_num_t pin, uint32_t frequencyHz, ledc_timer_t timer, ledc_channel_t channel) {
backlightPin = pin;
backlightTimer = timer;
backlightChannel = channel;
TT_LOG_I(TAG, "Init");
ledc_timer_config_t ledc_timer = {
.speed_mode = LEDC_LOW_SPEED_MODE,
.duty_resolution = LEDC_TIMER_8_BIT,
.timer_num = LEDC_TIMER_0,
.freq_hz = 4000,
.timer_num = backlightTimer,
.freq_hz = frequencyHz,
.clk_cfg = LEDC_AUTO_CLK,
.deconfigure = false
};
@ -30,9 +34,9 @@ bool init(gpio_num_t pin) {
ledc_channel_config_t ledc_channel = {
.gpio_num = backlightPin,
.speed_mode = LEDC_LOW_SPEED_MODE,
.channel = LEDC_CHANNEL_0,
.channel = backlightChannel,
.intr_type = LEDC_INTR_DISABLE,
.timer_sel = LEDC_TIMER_0,
.timer_sel = backlightTimer,
.duty = 0,
.hpoint = 0,
.sleep_mode = LEDC_SLEEP_MODE_NO_ALIVE_NO_PD,
@ -55,8 +59,8 @@ bool setBacklightDuty(uint8_t duty) {
TT_LOG_E(TAG, "Not initialized");
return false;
}
return ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, duty) == ESP_OK &&
ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0) == ESP_OK;
return ledc_set_duty(LEDC_LOW_SPEED_MODE, backlightChannel, duty) == ESP_OK &&
ledc_update_duty(LEDC_LOW_SPEED_MODE, backlightChannel) == ESP_OK;
}
}

View File

@ -1,11 +1,12 @@
#pragma once
#include <driver/ledc.h>
#include <driver/gpio.h>
namespace driver::pwmbacklight {
bool init(gpio_num_t pin);
bool init(gpio_num_t pin, uint32_t frequencyHz = 40000, ledc_timer_t timer = LEDC_TIMER_0, ledc_channel_t channel = LEDC_CHANNEL_0);
void setBacklightDuty(uint8_t duty);
bool setBacklightDuty(uint8_t duty);
}