Support for Waveshare S3 Touch LCD 4.3 (#18)

* initial changes for waveshare s3 touch support

* fix lvgl locking

* fix for lvgl locking

* cleaned up dependencies

* boards now depend on tactility instead of tactility-esp

* revert deletion

* remove component

* working touch&display driver

* added waveshare to github actions

* cleanup

* fix for driver

* fix for sim build

* build fixes

* updated docs

* updated docs

* attempt new sdl2 github action

* revert

* fixes for clion/cmdline build

environment wasn't parsed properly

* temporarily disable pc sim build
This commit is contained in:
Ken Van Hoeylandt
2024-01-26 21:36:21 +01:00
committed by GitHub
parent ed2d0cc78a
commit 14eb43211d
65 changed files with 944 additions and 437 deletions
+2 -1
View File
@@ -1,6 +1,7 @@
idf_component_register(
SRC_DIRS "."
INCLUDE_DIRS "."
REQUIRES tactility-esp esp_lcd esp_lcd_touch_gt911
REQUIRES esp_lvgl_port esp_lcd esp_lcd_touch_gt911 driver
)
target_link_libraries(${COMPONENT_LIB} ${IDF_TARGET_NAME} tactility)
+3
View File
@@ -1,10 +1,13 @@
#include "esp_log.h"
#include "driver/gpio.h"
#include "kernel.h"
#include "esp_lvgl_port.h"
#define TAG "lilygo_tdeck_bootstrap"
#define TDECK_PERI_POWERON GPIO_NUM_10
lv_disp_t* lilygo_tdeck_init_display();
static void tdeck_power_on() {
ESP_LOGI(TAG, "power on");
gpio_config_t device_power_signal_config = {
+30 -24
View File
@@ -4,7 +4,7 @@
#include "esp_lcd_panel_ops.h"
#include "esp_lcd_panel_vendor.h"
#include "esp_log.h"
#include "tactility-esp.h"
#include "esp_lvgl_port.h"
#define TAG "lilygo_tdeck_display"
@@ -57,7 +57,7 @@ static void tdeck_backlight() {
ESP_ERROR_CHECK(ledc_set_duty(LCD_BACKLIGHT_LEDC_MODE, LCD_BACKLIGHT_LEDC_CHANNEL, LCD_BACKLIGHT_LEDC_DUTY));
}
static bool create_display_device(DisplayDevice* display) {
lv_disp_t* lilygo_tdeck_init_display() {
ESP_LOGI(TAG, "creating display");
int draw_buffer_size = LCD_HORIZONTAL_RESOLUTION * LCD_DRAW_BUFFER_HEIGHT * (LCD_BITS_PER_PIXEL / 8);
@@ -96,7 +96,8 @@ static bool create_display_device(DisplayDevice* display) {
}
};
if (esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)LCD_SPI_HOST, &panel_io_config, &display->io_handle) != ESP_OK) {
esp_lcd_panel_io_handle_t io_handle;
if (esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)LCD_SPI_HOST, &panel_io_config, &io_handle) != ESP_OK) {
ESP_LOGD(TAG, "failed to create panel IO");
return false;
}
@@ -113,56 +114,61 @@ static bool create_display_device(DisplayDevice* display) {
.vendor_config = NULL
};
if (esp_lcd_new_panel_st7789(display->io_handle, &panel_config, &display->display_handle) != ESP_OK) {
esp_lcd_panel_handle_t panel_handle;
if (esp_lcd_new_panel_st7789(io_handle, &panel_config, &panel_handle) != ESP_OK) {
ESP_LOGD(TAG, "failed to create panel");
return false;
}
if (esp_lcd_panel_reset(display->display_handle) != ESP_OK) {
if (esp_lcd_panel_reset(panel_handle) != ESP_OK) {
ESP_LOGD(TAG, "failed to reset panel");
return false;
}
if (esp_lcd_panel_init(display->display_handle) != ESP_OK) {
if (esp_lcd_panel_init(panel_handle) != ESP_OK) {
ESP_LOGD(TAG, "failed to init panel");
return false;
}
if (esp_lcd_panel_invert_color(display->display_handle, true) != ESP_OK) {
if (esp_lcd_panel_invert_color(panel_handle, true) != ESP_OK) {
ESP_LOGD(TAG, "failed to init panel");
return false;
}
if (esp_lcd_panel_swap_xy(display->display_handle, true) != ESP_OK) {
if (esp_lcd_panel_swap_xy(panel_handle, true) != ESP_OK) {
ESP_LOGD(TAG, "failed to init panel");
return false;
}
if (esp_lcd_panel_mirror(display->display_handle, true, false) != ESP_OK) {
if (esp_lcd_panel_mirror(panel_handle, true, false) != ESP_OK) {
ESP_LOGD(TAG, "failed to init panel");
return false;
}
if (esp_lcd_panel_disp_on_off(display->display_handle, true) != ESP_OK) {
if (esp_lcd_panel_disp_on_off(panel_handle, true) != ESP_OK) {
ESP_LOGD(TAG, "failed to turn display on");
return false;
}
display->horizontal_resolution = LCD_HORIZONTAL_RESOLUTION;
display->vertical_resolution = LCD_VERTICAL_RESOLUTION;
display->draw_buffer_height = LCD_DRAW_BUFFER_HEIGHT;
display->bits_per_pixel = LCD_BITS_PER_PIXEL;
display->monochrome = false;
display->double_buffering = false;
const lvgl_port_display_cfg_t disp_cfg = {
.io_handle = io_handle,
.panel_handle = panel_handle,
.buffer_size = LCD_HORIZONTAL_RESOLUTION * LCD_DRAW_BUFFER_HEIGHT * (LCD_BITS_PER_PIXEL / 8),
.double_buffer = false,
.hres = LCD_HORIZONTAL_RESOLUTION,
.vres = LCD_VERTICAL_RESOLUTION,
.monochrome = false,
.rotation = {
.swap_xy = true, // TODO: check if code above is still needed
.mirror_x = true,
.mirror_y = false,
},
.flags = {
.buff_dma = true,
}
};
tdeck_backlight();
return true;
}
DisplayDriver lilygo_tdeck_display_driver() {
return (DisplayDriver) {
.name = "lilygo_tdeck_display",
.create_display_device = &create_display_device
};
return lvgl_port_add_disp(&disp_cfg);
}
+5 -2
View File
@@ -1,7 +1,10 @@
#include "lilygo_tdeck.h"
#include <stdbool.h>
bool lilygo_tdeck_bootstrap();
bool lilygo_init_lvgl();
const HardwareConfig lilygo_tdeck = {
.bootstrap = &lilygo_tdeck_bootstrap,
.display_driver = &lilygo_tdeck_display_driver,
.touch_driver = &lilygo_tdeck_touch_driver
.init_lvgl = &lilygo_init_lvgl
};
+1 -6
View File
@@ -1,16 +1,11 @@
#pragma once
#include "tactility-esp.h"
#include "hardware_config.h"
#ifdef __cplusplus
extern "C" {
#endif
// Available for HardwareConfig customizations
void lilygo_tdeck_bootstrap();
DisplayDriver lilygo_tdeck_display_driver();
TouchDriver lilygo_tdeck_touch_driver();
extern const HardwareConfig lilygo_tdeck;
#ifdef __cplusplus
+57
View File
@@ -0,0 +1,57 @@
#include "esp_lvgl_port.h"
#include "log.h"
#include "ui/lvgl_sync.h"
#include <thread.h>
#define TAG "lilygo_tdeck_lvgl"
lv_disp_t* lilygo_tdeck_init_display();
bool lilygo_tdeck_init_touch(esp_lcd_panel_io_handle_t* io_handle, esp_lcd_touch_handle_t* touch_handle);
bool lilygo_init_lvgl() {
static lv_disp_t* display = NULL;
static esp_lcd_panel_io_handle_t touch_io_handle;
static esp_lcd_touch_handle_t touch_handle;
const lvgl_port_cfg_t lvgl_cfg = {
.task_priority = ThreadPriorityHigh,
.task_stack = 8096,
.task_affinity = -1, // core pinning
.task_max_sleep_ms = 500,
.timer_period_ms = 5
};
if (lvgl_port_init(&lvgl_cfg) != ESP_OK) {
TT_LOG_E(TAG, "lvgl port init failed");
return false;
}
// Add display
display = lilygo_tdeck_init_display();
if (display == NULL) {
TT_LOG_E(TAG, "failed to add display");
return false;
}
// Add touch
if (!lilygo_tdeck_init_touch(&touch_io_handle, &touch_handle)) {
return false;
}
const lvgl_port_touch_cfg_t touch_cfg = {
.disp = display,
.handle = touch_handle,
};
lv_indev_t _Nullable* touch_indev = lvgl_port_add_touch(&touch_cfg);
if (touch_indev == NULL) {
TT_LOG_E(TAG, "failed to add touch to lvgl");
return false;
}
// Set syncing functions
tt_lvgl_sync_set(&lvgl_port_lock, &lvgl_port_unlock);
return true;
}
+2 -11
View File
@@ -1,5 +1,3 @@
#include "tactility-esp.h"
#include "esp_lcd_touch_gt911.h"
#include "esp_log.h"
#include "esp_err.h"
@@ -9,7 +7,7 @@
#define TAG "lilygo_tdeck_touch"
static bool create_touch_device(esp_lcd_panel_io_handle_t* io_handle, esp_lcd_touch_handle_t* touch_handle) {
bool lilygo_tdeck_init_touch(esp_lcd_panel_io_handle_t* io_handle, esp_lcd_touch_handle_t* touch_handle) {
ESP_LOGI(TAG, "creating touch");
const i2c_config_t i2c_conf = {
@@ -64,11 +62,4 @@ static bool create_touch_device(esp_lcd_panel_io_handle_t* io_handle, esp_lcd_to
}
return true;
}
TouchDriver lilygo_tdeck_touch_driver() {
return (TouchDriver) {
.name = "lilygo_tdeck_touch",
.create_touch_device = &create_touch_device
};
}
}
+7
View File
@@ -0,0 +1,7 @@
idf_component_register(
SRC_DIRS "."
INCLUDE_DIRS "."
REQUIRES lvgl esp_lcd esp_lcd_touch_gt911
)
target_link_libraries(${COMPONENT_LIB} ${IDF_TARGET_NAME} tactility)
+6
View File
@@ -0,0 +1,6 @@
#include <stdbool.h>
bool ws3t_bootstrap() {
// TODO: Init IO expander
return true;
}
+13
View File
@@ -0,0 +1,13 @@
#pragma once
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
bool ws3t_bootstrap();
#ifdef __cplusplus
}
#endif
+274
View File
@@ -0,0 +1,274 @@
#include "display_defines_i.h"
#include "esp_err.h"
#include "esp_lcd_panel_ops.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "lvgl_i.h"
#include "lvgl.h"
#include <esp_lcd_panel_rgb.h>
#include <esp_timer.h>
#include <sys/cdefs.h>
#include <thread.h>
#define TAG "waveshare_s3_touch_display"
SemaphoreHandle_t sem_vsync_end = NULL;
SemaphoreHandle_t sem_gui_ready = NULL;
SemaphoreHandle_t lvgl_mux = NULL;
#define WAVESHARE_LCD_PIXEL_CLOCK_HZ (12 * 1000 * 1000) // NOTE: original was 14MHz, but we had to slow it down with PSRAM frame buffer
#define WAVESHARE_PIN_NUM_HSYNC 46
#define WAVESHARE_PIN_NUM_VSYNC 3
#define WAVESHARE_PIN_NUM_DE 5
#define WAVESHARE_PIN_NUM_PCLK 7
#define WAVESHARE_PIN_NUM_DATA0 14 // B3
#define WAVESHARE_PIN_NUM_DATA1 38 // B4
#define WAVESHARE_PIN_NUM_DATA2 18 // B5
#define WAVESHARE_PIN_NUM_DATA3 17 // B6
#define WAVESHARE_PIN_NUM_DATA4 10 // B7
#define WAVESHARE_PIN_NUM_DATA5 39 // G2
#define WAVESHARE_PIN_NUM_DATA6 0 // G3
#define WAVESHARE_PIN_NUM_DATA7 45 // G4
#define WAVESHARE_PIN_NUM_DATA8 48 // G5
#define WAVESHARE_PIN_NUM_DATA9 47 // G6
#define WAVESHARE_PIN_NUM_DATA10 21 // G7
#define WAVESHARE_PIN_NUM_DATA11 1 // R3
#define WAVESHARE_PIN_NUM_DATA12 2 // R4
#define WAVESHARE_PIN_NUM_DATA13 42 // R5
#define WAVESHARE_PIN_NUM_DATA14 41 // R6
#define WAVESHARE_PIN_NUM_DATA15 40 // R7
#define WAVESHARE_PIN_NUM_DISP_EN (-1)
#define WAVESHARE_BUFFER_HEIGHT (WAVESHARE_LCD_VER_RES / 3) // How many rows of pixels to buffer - 1/3rd is about 1MB
#define WAVESHARE_LVGL_TICK_PERIOD_MS 2 // TODO: Setting it to 5 causes a crash - why?
#define WAVESHARE_USE_DOUBLE_FB true // Performance boost at the cost of about extra PSRAM(SPIRAM)
#if WAVESHARE_USE_DOUBLE_FB
#define WAVESHARE_LCD_NUM_FB 2
#else
#define WAVESHARE_LCD_NUM_FB 1
#endif // WAVESHARE_USE_DOUBLE_FB
static bool lvgl_is_running = false;
#define LVGL_MAX_SLEEP 500
bool ws3t_display_lock(uint32_t timeout_ms) {
assert(lvgl_mux && "lvgl_port_init must be called first");
const TickType_t timeout_ticks = (timeout_ms == 0) ? TtWaitForever : pdMS_TO_TICKS(timeout_ms);
return xSemaphoreTakeRecursive(lvgl_mux, timeout_ticks) == pdTRUE;
}
void ws3t_display_unlock(void) {
assert(lvgl_mux && "lvgl_port_init must be called first");
xSemaphoreGiveRecursive(lvgl_mux);
}
// Display_task should have lower priority than lvgl_tick_task below
static int32_t display_task(TT_UNUSED void* parameter) {
uint32_t task_delay_ms = LVGL_MAX_SLEEP;
ESP_LOGI(TAG, "Starting LVGL task");
lvgl_is_running = true;
while (lvgl_is_running) {
if (ws3t_display_lock(0)) {
task_delay_ms = lv_timer_handler();
ws3t_display_unlock();
}
if ((task_delay_ms > LVGL_MAX_SLEEP) || (1 == task_delay_ms)) {
task_delay_ms = LVGL_MAX_SLEEP;
} else if (task_delay_ms < 1) {
task_delay_ms = 1;
}
vTaskDelay(pdMS_TO_TICKS(task_delay_ms));
}
vTaskDelete(NULL);
return 0;
}
static bool on_vsync_event(
TT_UNUSED esp_lcd_panel_handle_t panel,
TT_UNUSED const esp_lcd_rgb_panel_event_data_t* event_data,
TT_UNUSED void* user_data
) {
BaseType_t high_task_awoken = pdFALSE;
if (xSemaphoreTakeFromISR(sem_gui_ready, &high_task_awoken) == pdTRUE) {
xSemaphoreGiveFromISR(sem_vsync_end, &high_task_awoken);
}
return high_task_awoken == pdTRUE;
}
static void lvgl_tick_task(TT_UNUSED void* arg) {
// Tell how much time has passed
lv_tick_inc(WAVESHARE_LVGL_TICK_PERIOD_MS);
}
static void display_flush_callback(lv_disp_drv_t* drv, const lv_area_t* area, lv_color_t* color_map) {
esp_lcd_panel_handle_t panel_handle = (esp_lcd_panel_handle_t)drv->user_data;
int offsetx1 = area->x1;
int offsetx2 = area->x2;
int offsety1 = area->y1;
int offsety2 = area->y2;
xSemaphoreGive(sem_gui_ready);
xSemaphoreTake(sem_vsync_end, portMAX_DELAY);
// pass the draw buffer to the driver
esp_lcd_panel_draw_bitmap(panel_handle, offsetx1, offsety1, offsetx2 + 1, offsety2 + 1, color_map);
lv_disp_flush_ready(drv);
}
lv_disp_t* ws3t_display_create() {
static lv_disp_drv_t display_driver;
static lv_disp_draw_buf_t display_buffer;
ESP_LOGI(TAG, "Create semaphores");
sem_vsync_end = xSemaphoreCreateBinary();
assert(sem_vsync_end);
sem_gui_ready = xSemaphoreCreateBinary();
assert(sem_gui_ready);
lvgl_mux = xSemaphoreCreateRecursiveMutex();
assert(lvgl_mux);
Thread* thread = tt_thread_alloc_ex("display_task", 8192, &display_task, NULL);
tt_thread_set_priority(thread, ThreadPriorityHigh);
tt_thread_start(thread);
ESP_LOGI(TAG, "Install RGB LCD panel driver");
esp_lcd_panel_handle_t panel_handle = NULL;
esp_lcd_rgb_panel_config_t panel_config = {
.clk_src = LCD_CLK_SRC_DEFAULT,
.timings = {
.pclk_hz = WAVESHARE_LCD_PIXEL_CLOCK_HZ,
.h_res = WAVESHARE_LCD_HOR_RES,
.v_res = WAVESHARE_LCD_VER_RES,
// The following parameters should refer to LCD spec
.hsync_back_porch = 10,
.hsync_front_porch = 20,
.hsync_pulse_width = 10,
.vsync_back_porch = 10,
.vsync_front_porch = 10,
.vsync_pulse_width = 10,
},
.data_width = 16, // RGB565 in parallel mode, thus 16bit in width
.bits_per_pixel = 16,
.num_fbs = WAVESHARE_LCD_NUM_FB,
.bounce_buffer_size_px = 0,
.sram_trans_align = 0,
.psram_trans_align = 64,
.hsync_gpio_num = WAVESHARE_PIN_NUM_HSYNC,
.vsync_gpio_num = WAVESHARE_PIN_NUM_VSYNC,
.de_gpio_num = WAVESHARE_PIN_NUM_DE,
.pclk_gpio_num = WAVESHARE_PIN_NUM_PCLK,
.disp_gpio_num = WAVESHARE_PIN_NUM_DISP_EN,
.data_gpio_nums = {
WAVESHARE_PIN_NUM_DATA0,
WAVESHARE_PIN_NUM_DATA1,
WAVESHARE_PIN_NUM_DATA2,
WAVESHARE_PIN_NUM_DATA3,
WAVESHARE_PIN_NUM_DATA4,
WAVESHARE_PIN_NUM_DATA5,
WAVESHARE_PIN_NUM_DATA6,
WAVESHARE_PIN_NUM_DATA7,
WAVESHARE_PIN_NUM_DATA8,
WAVESHARE_PIN_NUM_DATA9,
WAVESHARE_PIN_NUM_DATA10,
WAVESHARE_PIN_NUM_DATA11,
WAVESHARE_PIN_NUM_DATA12,
WAVESHARE_PIN_NUM_DATA13,
WAVESHARE_PIN_NUM_DATA14,
WAVESHARE_PIN_NUM_DATA15
},
.flags = {
.disp_active_low = false,
.refresh_on_demand = false,
.fb_in_psram = true,
#if WAVESHARE_USE_DOUBLE_FB
.double_fb = true,
#else
.double_fb = false,
#endif
.no_fb = false,
.bb_invalidate_cache = false
}
};
ESP_ERROR_CHECK(esp_lcd_new_rgb_panel(&panel_config, &panel_handle));
ESP_LOGI(TAG, "Register event callbacks");
esp_lcd_rgb_panel_event_callbacks_t cbs = {
.on_vsync = on_vsync_event,
.on_bounce_empty = NULL,
.on_bounce_frame_finish = NULL
};
ESP_ERROR_CHECK(esp_lcd_rgb_panel_register_event_callbacks(panel_handle, &cbs, &display_driver));
ESP_LOGI(TAG, "Initialize LCD panel");
ESP_ERROR_CHECK(esp_lcd_panel_reset(panel_handle));
ESP_ERROR_CHECK(esp_lcd_panel_init(panel_handle));
ESP_LOGI(TAG, "Initialize LVGL library");
lv_init();
void *buf1 = NULL;
void *buf2 = NULL;
#if WAVESHARE_USE_DOUBLE_FB
ESP_LOGI(TAG, "Use frame buffers as LVGL draw buffers");
buf1 = heap_caps_malloc(WAVESHARE_LCD_HOR_RES * WAVESHARE_BUFFER_HEIGHT * sizeof(lv_color_t), MALLOC_CAP_SPIRAM);
buf2 = heap_caps_malloc(WAVESHARE_LCD_HOR_RES * WAVESHARE_BUFFER_HEIGHT * sizeof(lv_color_t), MALLOC_CAP_SPIRAM);
// initialize LVGL draw buffers
lv_disp_draw_buf_init(&display_buffer, buf1, buf2, WAVESHARE_LCD_HOR_RES * WAVESHARE_BUFFER_HEIGHT);
#else
ESP_LOGI(TAG, "Allocate separate LVGL draw buffers from PSRAM");
buf1 = heap_caps_malloc(WAVESHARE_LCD_H_RES * WAVESHARE_BUFFER_HEIGHT * sizeof(lv_color_t), MALLOC_CAP_SPIRAM);
assert(buf1);
lv_disp_draw_buf_init(&display_buffer, buf1, buf2, WAVESHARE_LCD_H_RES * WAVESHARE_BUFFER_HEIGHT);
#endif // WAVESHARE_USE_DOUBLE_FB
ESP_LOGI(TAG, "Register display driver to LVGL");
lv_disp_drv_init(&display_driver);
display_driver.hor_res = WAVESHARE_LCD_HOR_RES;
display_driver.ver_res = WAVESHARE_LCD_VER_RES;
display_driver.flush_cb = display_flush_callback;
display_driver.draw_buf = &display_buffer;
display_driver.user_data = panel_handle;
display_driver.antialiasing = false;
display_driver.direct_mode = false;
display_driver.sw_rotate = false;
display_driver.rotated = 0;
display_driver.screen_transp = false;
#if WAVESHARE_USE_DOUBLE_FB
display_driver.full_refresh = true; // Maintains the synchronization between the two frame buffers
#else
display_driver.full_refresh = false;
#endif
lv_disp_t* display = lv_disp_drv_register(&display_driver);
const esp_timer_create_args_t lvgl_tick_timer_args = {
.callback = &lvgl_tick_task,
.name = "lvgl_tick"
};
esp_timer_handle_t lvgl_tick_timer = NULL;
ESP_ERROR_CHECK(esp_timer_create(&lvgl_tick_timer_args, &lvgl_tick_timer));
ESP_ERROR_CHECK(esp_timer_start_periodic(lvgl_tick_timer, WAVESHARE_LVGL_TICK_PERIOD_MS * 1000));
return display;
}
void ws3t_display_destroy() {
// TODO: de-init display, its buffer and touch, stop display tasks, stop timer
// TODO: see esp_lvlg_port.c for more info
if (lvgl_mux) {
vSemaphoreDelete(lvgl_mux);
lvgl_mux = NULL;
}
#if LV_ENABLE_GC || !LV_MEM_CUSTOM
lv_deinit();
#endif
}
@@ -0,0 +1,7 @@
/**
* The WaveShare S3 Touch uses a panel with the ST7262 display driver.
*/
#pragma once
#define WAVESHARE_LCD_HOR_RES 800
#define WAVESHARE_LCD_VER_RES 480
+19
View File
@@ -0,0 +1,19 @@
#pragma once
#include "hal/lv_hal_disp.h"
#include <stdbool.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
bool ws3t_display_lock(uint32_t timeout_ms);
void ws3t_display_unlock(void);
lv_disp_t* ws3t_display_create();
void ws3t_display_destroy();
#ifdef __cplusplus
}
#endif
+18
View File
@@ -0,0 +1,18 @@
#include "lvgl_i.h"
#include "display_i.h"
#include "touch_i.h"
#include "ui/lvgl_sync.h"
bool ws3t_init_lvgl() {
tt_lvgl_sync_set(&ws3t_display_lock, &ws3t_display_unlock);
lv_disp_t* display = ws3t_display_create();
if (display == NULL) {
return false;
}
ws3t_touch_init(display);
return true;
}
+13
View File
@@ -0,0 +1,13 @@
#pragma once
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
bool ws3t_init_lvgl();
#ifdef __cplusplus
}
#endif
+90
View File
@@ -0,0 +1,90 @@
#include "display_defines_i.h"
#include "driver/i2c.h"
#include "esp_err.h"
#include "esp_lcd_touch_gt911.h"
#include "esp_log.h"
#include "lv_api_map.h"
#define TAG "waveshare_s3_touch_i2c"
#define WAVESHARE_TOUCH_I2C_PORT 0
#define WAVESHARE_I2C_MASTER_TX_BUF_DISABLE 0
#define WAVESHARE_I2C_MASTER_RX_BUF_DISABLE 0
static esp_err_t i2c_master_init(void) {
const i2c_config_t i2c_conf = {
.mode = I2C_MODE_MASTER,
.sda_io_num = GPIO_NUM_8,
.sda_pullup_en = GPIO_PULLUP_DISABLE,
.scl_io_num = GPIO_NUM_9,
.scl_pullup_en = GPIO_PULLUP_DISABLE,
.master.clk_speed = 400000
};
i2c_param_config(WAVESHARE_TOUCH_I2C_PORT, &i2c_conf);
return i2c_driver_install(WAVESHARE_TOUCH_I2C_PORT, i2c_conf.mode, WAVESHARE_I2C_MASTER_RX_BUF_DISABLE, WAVESHARE_I2C_MASTER_TX_BUF_DISABLE, 0);
}
static esp_lcd_touch_handle_t touch_init_internal() {
ESP_ERROR_CHECK(i2c_master_init());
ESP_LOGI(TAG, "I2C initialized successfully");
static esp_lcd_panel_io_handle_t tp_io_handle = NULL;
static esp_lcd_panel_io_i2c_config_t tp_io_config = ESP_LCD_TOUCH_IO_I2C_GT911_CONFIG();
ESP_LOGI(TAG, "Initialize touch IO (I2C)");
/* Touch IO handle */
ESP_ERROR_CHECK(esp_lcd_new_panel_io_i2c((esp_lcd_i2c_bus_handle_t)WAVESHARE_TOUCH_I2C_PORT, &tp_io_config, &tp_io_handle));
esp_lcd_touch_config_t tp_cfg = {
.x_max = WAVESHARE_LCD_VER_RES,
.y_max = WAVESHARE_LCD_HOR_RES,
.rst_gpio_num = -1,
.int_gpio_num = -1,
.flags = {
.swap_xy = 0,
.mirror_x = 0,
.mirror_y = 0,
},
};
/* Initialize touch */
ESP_LOGI(TAG, "Initialize touch controller GT911");
esp_lcd_touch_handle_t tp = NULL;
ESP_ERROR_CHECK(esp_lcd_touch_new_i2c_gt911(tp_io_handle, &tp_cfg, &tp));
return tp;
}
static void touch_callback(lv_indev_drv_t* drv, lv_indev_data_t* data) {
uint16_t touchpad_x[1] = {0};
uint16_t touchpad_y[1] = {0};
uint8_t touchpad_cnt = 0;
/* Read touch controller data */
esp_lcd_touch_read_data(drv->user_data);
/* Get coordinates */
bool touchpad_pressed = esp_lcd_touch_get_coordinates(drv->user_data, touchpad_x, touchpad_y, NULL, &touchpad_cnt, 1);
if (touchpad_pressed && touchpad_cnt > 0) {
data->point.x = touchpad_x[0];
data->point.y = touchpad_y[0];
data->state = LV_INDEV_STATE_PR;
} else {
data->state = LV_INDEV_STATE_REL;
}
}
void ws3t_touch_init(lv_disp_t* display) {
esp_lcd_touch_handle_t touch_handle = touch_init_internal();
ESP_LOGI(TAG, "Register display indev to LVGL");
static lv_indev_drv_t indev_drv;
lv_indev_drv_init(&indev_drv);
indev_drv.type = LV_INDEV_TYPE_POINTER;
indev_drv.disp = display;
indev_drv.read_cb = &touch_callback;
indev_drv.user_data = touch_handle;
lv_indev_drv_register(&indev_drv); // TODO: store result for deinit purposes
}
+13
View File
@@ -0,0 +1,13 @@
#pragma once
#include "hal/lv_hal.h"
#ifdef __cplusplus
extern "C" {
#endif
void ws3t_touch_init(lv_disp_t* display);
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,10 @@
#include "waveshare_s3_touch.h"
#include "lvgl_i.h"
bool ws3t_bootstrap();
const HardwareConfig waveshare_s3_touch = {
.bootstrap = &ws3t_bootstrap,
.init_lvgl = &ws3t_init_lvgl
};
@@ -0,0 +1,14 @@
#pragma once
#include "hardware_config.h"
#ifdef __cplusplus
extern "C" {
#endif
// Waveshare S3 Touch LCD 4.3
extern const HardwareConfig waveshare_s3_touch;
#ifdef __cplusplus
}
#endif
+2 -1
View File
@@ -1,6 +1,7 @@
idf_component_register(
SRC_DIRS "."
INCLUDE_DIRS "."
REQUIRES tactility-esp esp_lcd_touch_cst816s esp_lcd_ili9341
REQUIRES esp_lvgl_port esp_lcd_touch_cst816s esp_lcd_ili9341
)
target_link_libraries(${COMPONENT_LIB} ${IDF_TARGET_NAME} tactility)
+30 -35
View File
@@ -4,14 +4,12 @@
#include "esp_lcd_ili9341.h"
#include "esp_lcd_panel_ops.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "tactility-esp.h"
#include "esp_lvgl_port.h"
#include "hal/lv_hal_disp.h"
#include <esp_lcd_panel_io.h>
#define TAG "2432s024_ili9341"
static SemaphoreHandle_t refresh_finish = NULL;
#define LCD_SPI_HOST SPI2_HOST
#define LCD_PIN_SCLK GPIO_NUM_14
#define LCD_PIN_MOSI GPIO_NUM_13
@@ -24,7 +22,7 @@ static SemaphoreHandle_t refresh_finish = NULL;
#define LCD_BITS_PER_PIXEL 16
#define LCD_DRAW_BUFFER_HEIGHT (LCD_VERTICAL_RESOLUTION / 10)
static bool create_display_device(DisplayDevice* display) {
lv_disp_t* yellow_board_init_display() {
ESP_LOGI(TAG, "creating display");
gpio_config_t io_conf = {
@@ -55,7 +53,8 @@ static bool create_display_device(DisplayDevice* display) {
NULL
);
if (esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)LCD_SPI_HOST, &panel_io_config, &display->io_handle) != ESP_OK) {
esp_lcd_panel_io_handle_t io_handle;
if (esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)LCD_SPI_HOST, &panel_io_config, &io_handle) != ESP_OK) {
ESP_LOGD(TAG, "failed to create panel");
return false;
}
@@ -67,36 +66,28 @@ static bool create_display_device(DisplayDevice* display) {
.bits_per_pixel = LCD_BITS_PER_PIXEL,
};
if (esp_lcd_new_panel_ili9341(display->io_handle, &panel_config, &display->display_handle) != ESP_OK) {
esp_lcd_panel_handle_t panel_handle;
if (esp_lcd_new_panel_ili9341(io_handle, &panel_config, &panel_handle) != ESP_OK) {
ESP_LOGD(TAG, "failed to create ili9341");
return false;
}
if (esp_lcd_panel_reset(display->display_handle) != ESP_OK) {
if (esp_lcd_panel_reset(panel_handle) != ESP_OK) {
ESP_LOGD(TAG, "failed to reset panel");
return false;
}
if (esp_lcd_panel_init(display->display_handle) != ESP_OK) {
if (esp_lcd_panel_init(panel_handle) != ESP_OK) {
ESP_LOGD(TAG, "failed to init panel");
return false;
}
if (esp_lcd_panel_mirror(display->display_handle, true, false) != ESP_OK) {
if (esp_lcd_panel_mirror(panel_handle, true, false) != ESP_OK) {
ESP_LOGD(TAG, "failed to set panel to mirror");
display->mirror_x = true;
display->mirror_y = false;
return false;
}
if (esp_lcd_panel_swap_xy(display->display_handle, false) != ESP_OK) {
ESP_LOGD(TAG, "failed to set panel xy swap");
display->swap_xy = false;
return false;
}
if (esp_lcd_panel_disp_on_off(display->display_handle, true) != ESP_OK) {
if (esp_lcd_panel_disp_on_off(panel_handle, true) != ESP_OK) {
ESP_LOGD(TAG, "failed to turn display on");
return false;
}
@@ -106,19 +97,23 @@ static bool create_display_device(DisplayDevice* display) {
return false;
}
display->horizontal_resolution = LCD_HORIZONTAL_RESOLUTION;
display->vertical_resolution = LCD_VERTICAL_RESOLUTION;
display->draw_buffer_height = LCD_DRAW_BUFFER_HEIGHT;
display->bits_per_pixel = LCD_BITS_PER_PIXEL;
display->monochrome = false;
display->double_buffering = true;
return true;
}
DisplayDriver board_2432s024_create_display_driver() {
return (DisplayDriver) {
.name = "ili9341_2432s024",
.create_display_device = &create_display_device
const lvgl_port_display_cfg_t disp_cfg = {
.io_handle = io_handle,
.panel_handle = panel_handle,
.buffer_size = LCD_HORIZONTAL_RESOLUTION * LCD_DRAW_BUFFER_HEIGHT * (LCD_BITS_PER_PIXEL / 8),
.double_buffer = false,
.hres = LCD_HORIZONTAL_RESOLUTION,
.vres = LCD_VERTICAL_RESOLUTION,
.monochrome = false,
.rotation = {
.swap_xy = false,
.mirror_x = true,
.mirror_y = false,
},
.flags = {
.buff_dma = true,
}
};
return lvgl_port_add_disp(&disp_cfg);
}
+57
View File
@@ -0,0 +1,57 @@
#include "esp_lvgl_port.h"
#include "log.h"
#include "ui/lvgl_sync.h"
#include <thread.h>
#define TAG "yellow_board_lvgl"
lv_disp_t* yellow_board_init_display();
bool yellow_board_init_touch(esp_lcd_panel_io_handle_t* io_handle, esp_lcd_touch_handle_t* touch_handle);
bool yellow_board_init_lvgl() {
static lv_disp_t* display = NULL;
static esp_lcd_panel_io_handle_t touch_io_handle;
static esp_lcd_touch_handle_t touch_handle;
const lvgl_port_cfg_t lvgl_cfg = {
.task_priority = ThreadPriorityHigh,
.task_stack = 8096,
.task_affinity = -1, // core pinning
.task_max_sleep_ms = 500,
.timer_period_ms = 5
};
if (lvgl_port_init(&lvgl_cfg) != ESP_OK) {
TT_LOG_E(TAG, "lvgl port init failed");
return false;
}
// Add display
display = yellow_board_init_display();
if (display == NULL) {
TT_LOG_E(TAG, "failed to add display");
return false;
}
// Add touch
if (!yellow_board_init_touch(&touch_io_handle, &touch_handle)) {
return false;
}
const lvgl_port_touch_cfg_t touch_cfg = {
.disp = display,
.handle = touch_handle,
};
lv_indev_t _Nullable* touch_indev = lvgl_port_add_touch(&touch_cfg);
if (touch_indev == NULL) {
TT_LOG_E(TAG, "failed to add touch to lvgl");
return false;
}
// Set syncing functions
tt_lvgl_sync_set(&lvgl_port_lock, &lvgl_port_unlock);
return true;
}
+1 -9
View File
@@ -2,13 +2,12 @@
#include "esp_err.h"
#include "esp_lcd_touch_cst816s.h"
#include "esp_log.h"
#include "tactility-esp.h"
#define TOUCH_I2C_PORT 0
#define TAG "2432s024_cst816"
static bool create_touch_device(esp_lcd_panel_io_handle_t* io_handle, esp_lcd_touch_handle_t* touch_handle) {
bool yellow_board_init_touch(esp_lcd_panel_io_handle_t* io_handle, esp_lcd_touch_handle_t* touch_handle) {
ESP_LOGI(TAG, "creating touch");
const i2c_config_t i2c_conf = {
@@ -64,10 +63,3 @@ static bool create_touch_device(esp_lcd_panel_io_handle_t* io_handle, esp_lcd_to
return true;
}
TouchDriver board_2432s024_create_touch_driver() {
return (TouchDriver) {
.name = "cst816s_2432s024",
.create_touch_device = &create_touch_device
};
}
+3 -2
View File
@@ -1,7 +1,8 @@
#include "yellow_board.h"
bool yellow_board_init_lvgl();
const HardwareConfig yellow_board_24inch_cap = {
.bootstrap = NULL,
.display_driver = &board_2432s024_create_display_driver,
.touch_driver = &board_2432s024_create_touch_driver
.init_lvgl = &yellow_board_init_lvgl
};
+1 -5
View File
@@ -1,15 +1,11 @@
#pragma once
#include "tactility-esp.h"
#include "hardware_config.h"
#ifdef __cplusplus
extern "C" {
#endif
// Available for HardwareConfig customizations
DisplayDriver board_2432s024_create_display_driver();
TouchDriver board_2432s024_create_touch_driver();
// Capacitive touch version of the 2.4" yellow board
extern const HardwareConfig yellow_board_24inch_cap;