diff --git a/CMakeLists.txt b/CMakeLists.txt index 18b78fb..1cf3c2b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,9 +11,7 @@ list(APPEND SOURCES "lvgl_tft/disp_driver.c") if(CONFIG_LV_TFT_DISPLAY_CONTROLLER_ILI9341) list(APPEND SOURCES "lvgl_tft/ili9341.c") elseif(CONFIG_LV_EPAPER_EPDIY_DISPLAY_CONTROLLER) - list(APPEND SOURCES "lvgl_tft/epdiy_epaper.cpp") -elseif(CONFIG_LV_EPAPER_CALEPD_DISPLAY_CONTROLLER) - list(APPEND SOURCES "lvgl_tft/calepd_epaper.cpp") + list(APPEND SOURCES "lvgl_tft/epdiy_epaper.c") elseif(CONFIG_LV_TFT_DISPLAY_CONTROLLER_ILI9481) list(APPEND SOURCES "lvgl_tft/ili9481.c") elseif(CONFIG_LV_TFT_DISPLAY_CONTROLLER_ILI9486) @@ -67,6 +65,7 @@ if(CONFIG_LV_TOUCH_CONTROLLER) elseif(CONFIG_LV_TOUCH_CONTROLLER_FT6X06) list(APPEND SOURCES "lvgl_touch/ft6x36.c") elseif(CONFIG_LV_TOUCH_CONTROLLER_L58) + list(APPEND SOURCES "lvgl_touch/L58/L58Touch.cpp") list(APPEND SOURCES "lvgl_touch/l58.cpp") elseif(CONFIG_LV_TOUCH_CONTROLLER_STMPE610) list(APPEND SOURCES "lvgl_touch/stmpe610.c") diff --git a/README.md b/README.md index 60fad2f..7f4abad 100644 --- a/README.md +++ b/README.md @@ -33,8 +33,10 @@ swap of RGB565 color on the LVGL configuration menuconfig (it's not handled auto | FitiPower JD79653A/ GoodDisplay GDEW0154M09 | e-Paper | SPI | 1: 1byte per pixel | No | | EPDiy supported epaper (needs PCB) | e-Paper | Parallel | 4: RGB232 16 grayscales | No -Please note that EPDiy supported epapers include also the Lilygo EPD47 that comes with it's own PCB and ESP32 WROVER. Is possible also to build your own EPDiy PCB, please find the [project KiCad source files, schematics, and documentation here](https://github.com/vroland/epdiy/tree/master/hardware/epaper-breakout) -To use an EPDiy supported epaper you need to add it [as a component](https://github.com/martinberlin/lv_port_esp32-epaper/tree/master/components) and also update the CMakeLists of lvgl component to [REQUIRE that library](https://github.com/martinberlin/lv_port_esp32-epaper/wiki). +Please note that EPDiy supported epapers include also the Lilygo EPD47 that comes with it's own PCB and ESP32 WROVER. Is possible also to build your own EPDiy PCB, please find the [project KiCad source files, schematics, and documentation here](https://github.com/vroland/epdiy/tree/master/hardware/epaper-breakout). +To use an EPDiy supported epaper you need to add it [as a component using git submodules](https://github.com/martinberlin/lv_port_esp32-epaper/tree/master/components) and also update the CMakeLists of lvgl component to [REQUIRE that library](https://github.com/martinberlin/lv_port_esp32-epaper/wiki). + + git submodule add https://github.com/martinberlin/epdiy-rotation.git components/epd_driver ## Supported indev controllers @@ -43,6 +45,7 @@ To use an EPDiy supported epaper you need to add it [as a component](https://git - other FT6X36 or the FT6206 controllers should work as well (not tested) - STMPE610 - FT81x (Single, Dual, and Quad SPI) +- L58 touch component hook (Used in Lilygo EPD47 parallel with EPDiy driver) If your display or input device (touch) controller is not supported consider contributing to this repo by adding support to it! [Contribute controller support](CONTRIBUTE_CONTROLLER_SUPPORT.md) diff --git a/lvgl_helpers.h b/lvgl_helpers.h index a7a999e..b5a3ec0 100644 --- a/lvgl_helpers.h +++ b/lvgl_helpers.h @@ -45,7 +45,7 @@ extern "C" { // IMPORTANT: This will render the screen in 10 times: #elif defined (CONFIG_LV_EPAPER_EPDIY_DISPLAY_CONTROLLER) #define DISP_BUF_SIZE LV_HOR_RES_MAX*(LV_VER_RES_MAX/10) -#elif defined (CONFIG_LV_EPAPER_CALEPD_DISPLAY_CONTROLLER) +#elif defined () #define DISP_BUF_SIZE (LV_HOR_RES_MAX * 90) #elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_HX8357 diff --git a/lvgl_tft/Kconfig b/lvgl_tft/Kconfig index a8ff5a6..10cda56 100644 --- a/lvgl_tft/Kconfig +++ b/lvgl_tft/Kconfig @@ -93,10 +93,7 @@ menu "LVGL TFT/Epaper Display controller" bool help EPDIY parallel epaper controller. - config LV_EPAPER_CALEPD_DISPLAY_CONTROLLER - bool - help - CalEPD SPI epaper controller. + config LV_TFT_DISPLAY_CONTROLLER_ILI9341 bool help @@ -283,12 +280,6 @@ menu "LVGL TFT/Epaper Display controller" bool "EPDIY_GENERIC" select LV_EPAPER_EPDIY_DISPLAY_CONTROLLER select LV_EPAPER_DISPLAY_PROTOCOL_PARALLEL - - config LV_EPAPER_DISPLAY_USER_CONTROLLER_CALEPD - bool "CALEPD_GENERIC" - # Use also Parallel to avoid LGVL SPI instantiation - select LV_EPAPER_CALEPD_DISPLAY_CONTROLLER - select LV_EPAPER_DISPLAY_PROTOCOL_PARALLEL config LV_TFT_DISPLAY_USER_CONTROLLER_ILI9341 bool "ILI9341" select LV_TFT_DISPLAY_CONTROLLER_ILI9341 diff --git a/lvgl_tft/calepd_epaper.cpp b/lvgl_tft/calepd_epaper.cpp deleted file mode 100644 index 2de1830..0000000 --- a/lvgl_tft/calepd_epaper.cpp +++ /dev/null @@ -1,84 +0,0 @@ -#include "esp_log.h" -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" - -#include "calepd_epaper.h" - -// NOTE: This needs Epdiy component https://github.com/vroland/epdiy -// Run idf.py menuconfig-> Component Config -> E-Paper driver and select: -// Display type: LILIGO 4.7 ED047TC1 -// Board: LILIGO T5-4.7 Epaper -// In the same section Component Config -> ESP32 Specifics -> Enable PSRAM -//#include "parallel/ED047TC1.h" -//Ed047TC1 display; - -// SPI Generic epapers (Goodisplay/ Waveshare) -// Select the right class for your SPI epaper: https://github.com/martinberlin/cale-idf/wiki -//#include -#include -Gdew027w3 display(io); -EpdSpi io; -//Gdew0583T7 display(io); - -/** test Display dimensions - * Do not forget to set: menuconfig -> Components -> LVGL configuration - * Max. Horizontal resolution 264 -> WIDTH of your epaper - * Max. Vertical resolution 176 -> HEIGHT - */ - -/********************* - * DEFINES - *********************/ -#define TAG "EPDIY" - -uint16_t flushcalls = 0; - -/* Display initialization routine */ -void calepd_init(void) -{ - printf("calepd_init\n"); - display.init(); - display.setRotation(0); - // Clear screen - //display.update(); -} - -/* Required by LVGL */ -void calepd_flush(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_map) -{ - ++flushcalls; - printf("flush %d x:%d y:%d w:%d h:%d\n", flushcalls,area->x1,area->y1,lv_area_get_width(area),lv_area_get_height(area)); - - // Full update - if (lv_area_get_width(area)==display.width() && lv_area_get_height(area)==display.height()) { - display.update(); - } else { - // Partial update: - display.update(); // Uncomment to disable partial update - //display.updateWindow(area->x1,area->y1,lv_area_get_width(area),lv_area_get_height(area), true); - //display.updateWindow(area->x1,area->y1,lv_area_get_width(area),lv_area_get_height(area)); - } - - /* IMPORTANT!!! - * Inform the graphics library that you are ready with the flushing */ - lv_disp_flush_ready(drv); -} - -/* Called for each pixel */ -void calepd_set_px_cb(lv_disp_drv_t * disp_drv, uint8_t* buf, - lv_coord_t buf_w, lv_coord_t x, lv_coord_t y, - lv_color_t color, lv_opa_t opa) -{ - //If not drawing anything: Debug to see if this function is called: - //printf("set_px %d %d\n",(int16_t)x,(int16_t)y); - - // Test using RGB232 - int16_t epd_color = EPD_WHITE; - - // Color setting use: RGB232 - // Only monochrome:All what is not white, turn black - if ((int16_t)color.full<254) { - epd_color = EPD_BLACK; - } - display.drawPixel((int16_t)x, (int16_t)y, epd_color); -} diff --git a/lvgl_tft/calepd_epaper.h b/lvgl_tft/calepd_epaper.h deleted file mode 100644 index ea5be61..0000000 --- a/lvgl_tft/calepd_epaper.h +++ /dev/null @@ -1,36 +0,0 @@ -/** - * Display class for generic e-Paper driven by EPDiy class -*/ -#ifndef CALEPD_H -#define CALEPD_H - -#define EPDIY_COLUMNS (LV_HOR_RES_MAX / 8) - -#ifdef __cplusplus -extern "C" { -#endif - - -#ifdef LV_LVGL_H_INCLUDE_SIMPLE -#include "lvgl.h" -#else - #include "lvgl/lvgl.h" -#endif -#include "sdkconfig.h" - -/* Configure your display */ -void calepd_init(void); - -/* LVGL callbacks */ -void calepd_flush(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_map); - -/* Only for monochrome displays. But we use epdiy_set_px also for epapers */ -//void epdiy_rounder(lv_disp_drv_t *disp_drv, lv_area_t *area); -void calepd_set_px_cb(lv_disp_drv_t *disp_drv, uint8_t *buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y, lv_color_t color, lv_opa_t opa); - -#ifdef __cplusplus -} /* extern "C" */ -#endif - - -#endif /* EPDIY_H */ \ No newline at end of file diff --git a/lvgl_tft/disp_driver.c b/lvgl_tft/disp_driver.c index 0acacd6..e70504f 100644 --- a/lvgl_tft/disp_driver.c +++ b/lvgl_tft/disp_driver.c @@ -12,8 +12,6 @@ void disp_driver_init(void) ili9341_init(); #elif defined CONFIG_LV_EPAPER_EPDIY_DISPLAY_CONTROLLER epdiy_init(); -#elif defined CONFIG_LV_EPAPER_CALEPD_DISPLAY_CONTROLLER - calepd_init(); #elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_ILI9481 ili9481_init(); #elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_ILI9488 @@ -54,9 +52,7 @@ void disp_driver_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * #if defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_ILI9341 ili9341_flush(drv, area, color_map); #elif defined CONFIG_LV_EPAPER_EPDIY_DISPLAY_CONTROLLER - epdiy_flush(drv, area, color_map); -#elif defined CONFIG_LV_EPAPER_CALEPD_DISPLAY_CONTROLLER - calepd_flush(drv, area, color_map); + epdiy_flush(drv, area, color_map); #elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_ILI9481 ili9481_flush(drv, area, color_map); #elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_ILI9488 @@ -115,8 +111,6 @@ void disp_driver_set_px(lv_disp_drv_t * disp_drv, uint8_t * buf, lv_coord_t buf_ ssd1306_set_px_cb(disp_drv, buf, buf_w, x, y, color, opa); #elif defined CONFIG_LV_EPAPER_EPDIY_DISPLAY_CONTROLLER epdiy_set_px_cb(disp_drv, buf, buf_w, x, y, color, opa); -#elif defined CONFIG_LV_EPAPER_CALEPD_DISPLAY_CONTROLLER - calepd_set_px_cb(disp_drv, buf, buf_w, x, y, color, opa); #elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_SH1107 sh1107_set_px_cb(disp_drv, buf, buf_w, x, y, color, opa); #elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_IL3820 diff --git a/lvgl_tft/disp_driver.h b/lvgl_tft/disp_driver.h index 74255f5..28e0f22 100644 --- a/lvgl_tft/disp_driver.h +++ b/lvgl_tft/disp_driver.h @@ -22,8 +22,6 @@ extern "C" { #include "ili9341.h" #elif defined CONFIG_LV_EPAPER_EPDIY_DISPLAY_CONTROLLER #include "lvgl_tft/epdiy_epaper.h" -#elif defined CONFIG_LV_EPAPER_CALEPD_DISPLAY_CONTROLLER -#include "lvgl_tft/calepd_epaper.h" #elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_ILI9481 #include "ili9481.h" #elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_ILI9488 diff --git a/lvgl_tft/epdiy_epaper.cpp b/lvgl_tft/epdiy_epaper.c similarity index 100% rename from lvgl_tft/epdiy_epaper.cpp rename to lvgl_tft/epdiy_epaper.c diff --git a/lvgl_tft/epdiy_epaper_v1.cpp b/lvgl_tft/epdiy_epaper_v1.cpp deleted file mode 100644 index 38cd948..0000000 --- a/lvgl_tft/epdiy_epaper_v1.cpp +++ /dev/null @@ -1,92 +0,0 @@ -#include "esp_log.h" -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" - -#include "epdiy_epaper.h" - -#include "epd_driver.h" -#include "epd_highlevel.h" - -/************************************************************************************************** - * NOTE: This file iis the first version that writes directly on the set_px callback - * each pixel into the epaper display buffer. The second version is not epdiy_epaper.cpp - * It writes *buf and then it comes as *color_map on the flush callback. - * Feel free to experiment with this 2. epdiy_epaper.cpp works better to make a small UX - **************************************************************************************************/ -#define TAG "EPDIY" -EpdiyHighlevelState hl; -uint16_t flushcalls = 0; -uint8_t * framebuffer; -uint8_t temperature = 25; - -/* Display initialization routine */ -void epdiy_init(void) -{ - epd_init(EPD_OPTIONS_DEFAULT); - hl = epd_hl_init(EPD_BUILTIN_WAVEFORM); - framebuffer = epd_hl_get_framebuffer(&hl); - epd_poweron(); - //Clear all always in init? - //epd_fullclear(&hl, temperature); -} - -uint16_t xo = 0; -uint16_t yo = 0; - -/* Required by LVGL */ -void epdiy_flush(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_map) -{ - ++flushcalls; - xo = area->x1; - yo = area->y1; - uint16_t w = lv_area_get_width(area); - uint16_t h = lv_area_get_height(area); - - EpdRect update_area = { - .x = xo, - .y = yo, - .width = w, - .height = h, - }; - - epd_hl_update_area(&hl, MODE_GC16, temperature, update_area); //update_area - - printf("epdiy_flush %d x:%d y:%d w:%d h:%d\n", flushcalls,xo,yo,w,h); - /* Inform the graphics library that you are ready with the flushing */ - lv_disp_flush_ready(drv); -} - -/* - * Called for each pixel. Designed with the idea to fill the buffer directly, not to set each pixel, see: - * https://forum.lvgl.io/t/lvgl-port-to-be-used-with-epaper-displays/5630/3 -*/ -void epdiy_set_px_cb(lv_disp_drv_t * disp_drv, uint8_t* buf, - lv_coord_t buf_w, lv_coord_t x, lv_coord_t y, - lv_color_t color, lv_opa_t opa) -{ - // Debug where x y is printed, not all otherwise is too much Serial - /* if ((int16_t)y%10==0 && flushcalls>0){ - if ((int16_t)x%2==0){ - printf("x%d y%d\n", (int16_t)x, (int16_t)y); - } - } - */ - - // Test using RGB232 - int16_t epd_color = 255; - if ((int16_t)color.full<250) { - epd_color = (int16_t)color.full/3; - } - - int16_t x1 = (int16_t)x; - int16_t y1 = (int16_t)y; - - //Instead of using epd_draw_pixel: Set pixel directly in buffer - //epd_draw_pixel(x1, y1, epd_color, framebuffer); - uint8_t *buf_ptr = &framebuffer[y1 * buf_w / 2 + x1 / 2]; - if (x % 2) { - *buf_ptr = (*buf_ptr & 0x0F) | (epd_color & 0xF0); - } else { - *buf_ptr = (*buf_ptr & 0xF0) | (epd_color >> 4); - } -} diff --git a/lvgl_touch/L58/L58Touch.cpp b/lvgl_touch/L58/L58Touch.cpp new file mode 100644 index 0000000..cbd733f --- /dev/null +++ b/lvgl_touch/L58/L58Touch.cpp @@ -0,0 +1,316 @@ +// This is the first experimental Touch component for the LILYGO EPD47 touch overlay +// Controller: L58 -> https://github.com/Xinyuan-LilyGO/LilyGo-EPD47/files/6059098/L58.V1.0.pdf +// Note: Rotation is only working for certain angles (0 works alright, 2 also) Others still need to be corrected +#include "L58Touch.h" + +#define CONFIG_L58_DEBUG 0 + +L58Touch *L58Touch::_instance = nullptr; +static const char *TAG = "i2c-touch"; + +L58Touch::L58Touch(int8_t intPin) +{ + _instance = this; + printf("I2C sda:%d scl:%d int:%d\n\n", + CONFIG_LV_TOUCH_I2C_SDA, CONFIG_LV_TOUCH_I2C_SCL, intPin); + i2c_config_t conf; + conf.mode = I2C_MODE_MASTER; + conf.sda_io_num = (gpio_num_t)CONFIG_LV_TOUCH_I2C_SDA; + conf.sda_pullup_en = GPIO_PULLUP_ENABLE; + conf.scl_io_num = (gpio_num_t)CONFIG_LV_TOUCH_I2C_SCL; + conf.scl_pullup_en = GPIO_PULLUP_ENABLE; + conf.master.clk_speed = 50000; + + #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 3, 0) + // !< Optional, you can use I2C_SCLK_SRC_FLAG_* flags to choose i2c source clock here. + conf.clk_flags = 0; + #endif + + i2c_param_config(I2C_NUM_0, &conf); + esp_err_t i2c_driver = i2c_driver_install(I2C_NUM_0, conf.mode, I2C_MASTER_RX_BUF_DISABLE, I2C_MASTER_TX_BUF_DISABLE, 0); + if (i2c_driver == ESP_OK) { + printf("i2c_driver started correctly\n"); + } else { + printf("i2c_driver error: %d\n", i2c_driver); + } + _intPin = intPin; +} + +// Destructor does nothing for now +L58Touch::~L58Touch() +{ + +} + +bool L58Touch::begin(uint16_t width, uint16_t height) +{ + _touch_width = width; + _touch_height = height; + if (width == 0 || height ==0) { + ESP_LOGE(TAG,"begin(uint8_t threshold, uint16_t width, uint16_t height) did not receive the width / height so touch cannot be rotation aware"); + } + + // INT pin triggers the callback function on the Falling edge of the GPIO + gpio_config_t io_conf; + io_conf.intr_type = GPIO_INTR_POSEDGE; + io_conf.pin_bit_mask = 1ULL<< CONFIG_LV_TOUCH_INT; + io_conf.mode = GPIO_MODE_INPUT; + io_conf.pull_down_en = (gpio_pulldown_t) 0; // disable pull-down mode + io_conf.pull_up_en = (gpio_pullup_t) 1; // pull-up mode + gpio_config(&io_conf); + /* INT gpio is not declared as an interrupt PIN in this touch version since we cannot do + blocking functions in LVGL: + */ + uint8_t buf[2] = {0xD1, 0X06}; + writeData(buf, sizeof(buf)); + return true; +} + +void L58Touch::registerTouchHandler(void (*fn)(TPoint point, TEvent e)) +{ + _touchHandler = fn; + if (CONFIG_L58_DEBUG) printf("Touch handler function registered\n"); +} + +TPoint L58Touch::loop() +{ + _point = processTouch(); + return _point; +} + +TPoint L58Touch::processTouch() +{ + TPoint point; + point.x = lastX; + point.y = lastY; + point.event = lastEvent; + + if (gpio_get_level((gpio_num_t)CONFIG_LV_TOUCH_INT) == 0) { + TPoint point = scanPoint(); + lastX = point.x; + lastY = point.y; + lastEvent = point.event; + } + + return point; +} + +uint8_t L58Touch::read8(uint8_t regName) { + uint8_t buf; + readRegister8(regName, &buf); + return buf; +} + +TPoint L58Touch::scanPoint() +{ + TPoint point{0,0,0}; + uint8_t pointIdx = 0; + uint8_t buffer[40] = {0}; + uint32_t sumL = 0, sumH = 0; + + buffer[0] = 0xD0; + buffer[1] = 0x00; + readBytes(buffer, 7); + + if (buffer[0] == 0xAB) { + clearFlags(); + return point; + } + + pointIdx = buffer[5] & 0xF; + + if (pointIdx == 1) { + buffer[5] = 0xD0; + buffer[6] = 0x07; + readBytes( &buffer[5], 2); + sumL = buffer[5] << 8 | buffer [6]; + + } else if (pointIdx > 1) { + buffer[5] = 0xD0; + buffer[6] = 0x07; + readBytes( &buffer[5], 5 * (pointIdx - 1) + 3); + sumL = buffer[5 * pointIdx + 1] << 8 | buffer[5 * pointIdx + 2]; + } + clearFlags(); + + for (int i = 0 ; i < 5 * pointIdx; ++i) { + sumH += buffer[i]; + } + + if (sumH != sumL) { + pointIdx = 0; + } + if (pointIdx) { + uint8_t offset; + for (int i = 0; i < pointIdx; ++i) { + if (i == 0) { + offset = 0; + } else { + offset = 4; + } + data[i].id = (buffer[i * 5 + offset] >> 4) & 0x0F; + data[i].event = buffer[i * 5 + offset] & 0x0F; + data[i].y = (uint16_t)((buffer[i * 5 + 1 + offset] << 4) | ((buffer[i * 5 + 3 + offset] >> 4) & 0x0F)); + data[i].x = (uint16_t)((buffer[i * 5 + 2 + offset] << 4) | (buffer[i * 5 + 3 + offset] & 0x0F)); + + //printf("X[%d]:%d Y:%d E:%d\n", i, data[i].x, data[i].y, data[i].event); + } + + } else { + // Only this one seems to be working (even pressing with 2 fingers) + pointIdx = 1; + data[0].id = (buffer[0] >> 4) & 0x0F; + data[0].event = (buffer[0] & 0x0F) >>1; + data[0].y = (uint16_t)((buffer[0 * 5 + 1] << 4) | ((buffer[0 * 5 + 3] >> 4) & 0x0F)); + data[0].x = (uint16_t)((buffer[0 * 5 + 2] << 4) | (buffer[0 * 5 + 3] & 0x0F)); + if (data[0].event == 3) { /** Press */ + _touchStartTime = esp_timer_get_time()/1000; + } + if (data[0].event == 0) { /** Lift up */ + _touchEndTime = esp_timer_get_time()/1000; + } + + #if defined(CONFIG_L58_DEBUG) && CONFIG_L58_DEBUG==1 + printf("X:%d Y:%d E:%d\n", data[0].x, data[0].y, data[0].event); + #endif + } + + uint16_t x = data[0].x; + uint16_t y = data[0].y; + + // Had some hope that state was event, but always come: + // id:1 st:6 + // printf("id:%d st:%d\n", data[0].id, data[0].state); + // Make touch rotation aware + switch (_rotation) + { + // 0- no rotation: Works OK inverting Y axis + case 0: + y = _touch_height - y; + break; + + case 1: + swap(x, y); + y = _touch_width - y; + x = _touch_height - x; + break; + + case 2: + x = _touch_width - x; + break; + + case 3: + swap(x, y); + break; + } + + point = {x, y, data[0].event}; + return point; +} + +void L58Touch::writeRegister8(uint8_t reg, uint8_t value) +{ + i2c_cmd_handle_t cmd = i2c_cmd_link_create(); + i2c_master_start(cmd); + i2c_master_write_byte(cmd, L58_ADDR << 1 | I2C_MASTER_WRITE, ACK_CHECK_EN); + i2c_master_write_byte(cmd, reg , ACK_CHECK_EN); + i2c_master_write_byte(cmd, value , ACK_CHECK_EN); + i2c_master_stop(cmd); + i2c_master_cmd_begin(I2C_NUM_0, cmd, 1000 / portTICK_RATE_MS); + i2c_cmd_link_delete(cmd); +} + +void L58Touch::writeData(uint8_t *data, int len) +{ + if (len==0) return; + i2c_cmd_handle_t cmd = i2c_cmd_link_create(); + i2c_master_start(cmd); + i2c_master_write(cmd, data, len, ACK_CHECK_EN); + i2c_master_stop(cmd); + i2c_cmd_link_delete(cmd); +} + +uint8_t L58Touch::readRegister8(uint8_t reg, uint8_t *data_buf) +{ + i2c_cmd_handle_t cmd = i2c_cmd_link_create(); + i2c_master_start(cmd); + i2c_master_write_byte(cmd, L58_ADDR << 1 | I2C_MASTER_WRITE, ACK_CHECK_EN); + i2c_master_write_byte(cmd, reg, I2C_MASTER_ACK); + // Research: Why it's started a 2nd time here + i2c_master_start(cmd); + i2c_master_write_byte(cmd, (L58_ADDR << 1) | I2C_MASTER_READ, true); + + i2c_master_read_byte(cmd, data_buf, I2C_MASTER_NACK); + i2c_master_stop(cmd); + esp_err_t ret = i2c_master_cmd_begin(I2C_NUM_0, cmd, 1000 / portTICK_RATE_MS); + i2c_cmd_link_delete(cmd); + +#if defined(CONFIG_L58_DEBUG) && CONFIG_L58_DEBUG==1 + printf("REG 0x%x: 0x%x\n",reg,ret); +#endif + + return ret; +} + +void L58Touch::readBytes(uint8_t *data, int len) { + if (len==0) return; + i2c_cmd_handle_t cmd = i2c_cmd_link_create(); + i2c_master_start(cmd); + i2c_master_write_byte(cmd, L58_ADDR << 1 | I2C_MASTER_WRITE, ACK_CHECK_EN); + i2c_master_write(cmd, data, 2, ACK_CHECK_EN); + + i2c_master_start(cmd); + + i2c_master_write_byte(cmd, L58_ADDR << 1 | I2C_MASTER_READ, ACK_CHECK_EN); + i2c_master_read(cmd, data, len, (i2c_ack_type_t) ACK_VAL); + i2c_master_stop(cmd); + esp_err_t ret = i2c_master_cmd_begin(I2C_NUM_0, cmd, 1000 / portTICK_RATE_MS); + i2c_cmd_link_delete(cmd); + + if (ret == ESP_OK) { + for (int i = 0; i < len; i++) { + printf("0x%02x ", data[i]); + if ((i + 1) % 16 == 0) { + printf("\r\n"); + } + } + if (len % 16) { + printf("\r\n"); + } + } else if (ret == ESP_ERR_TIMEOUT) { + // Getting a lot of this! + //ESP_LOGW(TAG, "Bus is busy"); + } else { + ESP_LOGW(TAG, "Read failed"); + } +} + +void L58Touch::fireEvent(TPoint point, TEvent e) +{ + if (_touchHandler) + _touchHandler(point, e); +} + +void L58Touch::setRotation(uint8_t rotation) { + _rotation = rotation; +} + +void L58Touch::setTouchWidth(uint16_t width) { + printf("touch w:%d\n",width); + _touch_width = width; +} + +void L58Touch::setTouchHeight(uint16_t height) { + printf("touch h:%d\n",height); + _touch_height = height; +} + +void L58Touch::clearFlags() { + uint8_t buf[3] = {0xD0, 0X00, 0XAB}; + writeData(buf, sizeof(buf)); +} + +void L58Touch::sleep() { + uint8_t buf[2] = {0xD1, 0X05}; + writeData(buf, sizeof(buf)); +} diff --git a/lvgl_touch/L58/include/L58Touch.h b/lvgl_touch/L58/include/L58Touch.h new file mode 100644 index 0000000..1063a85 --- /dev/null +++ b/lvgl_touch/L58/include/L58Touch.h @@ -0,0 +1,125 @@ +// This is the first experimental Touch component for the LILYGO EPD47 touch overlay +// NOTE: As in LVGL we cannot use blocking functions this is a variation of original library here: +// https://github.com/martinberlin/FT6X36-IDF +// More info about this epaper: +// https://github.com/martinberlin/cale-idf/wiki/Model-parallel-ED047TC1.h +#include +//#include +#include "driver/gpio.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/semphr.h" +#include +#include "esp_log.h" +#include "driver/i2c.h" +#include "sdkconfig.h" +#include "esp_idf_version.h" +#ifndef touch_ttgo_h +#define touch_ttgo_h +// I2C Constants +#define I2C_MASTER_TX_BUF_DISABLE 0 /*!< I2C master doesn't need buffer */ +#define I2C_MASTER_RX_BUF_DISABLE 0 /*!< I2C master doesn't need buffer */ + +#define ACK_CHECK_EN 0x1 /*!< I2C master will check ack from slave*/ +#define ACK_CHECK_DIS 0x0 /*!< I2C master will not check ack from slave */ +#define ACK_VAL 0x0 /*!< I2C ack value */ +#define NACK_VAL 0x1 /*!< I2C nack value */ + +#define L58_ADDR 0x5A + +// Note: We still could not read proper events, so we simulate Tap + enum class TEvent + { + None, + TouchStart, + TouchMove, + TouchEnd, + Tap + }; + + struct TPoint + { + uint16_t x; + uint16_t y; + uint8_t event; + }; + +class L58Touch +{ + + typedef struct { + uint8_t id; + uint8_t event; + uint16_t x; + uint16_t y; + } TouchData_t; + + + +public: + // TwoWire * wire will be replaced by ESP-IDF https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/i2c.html + L58Touch(int8_t intPin); + ~L58Touch(); + + bool begin(uint16_t width = 0, uint16_t height = 0); + void registerTouchHandler(void(*fn)(TPoint point, TEvent e)); + uint8_t touched(); + TPoint loop(); + TPoint processTouch(); + // Helper functions to make the touch display aware + void setRotation(uint8_t rotation); + void setTouchWidth(uint16_t width); + void setTouchHeight(uint16_t height); + // Pending implementation. How much x->touch y↓touch is placed (In case is smaller than display) + void setXoffset(uint16_t x_offset); + void setYoffset(uint16_t y_offset); + void sleep(); + // Smart template from EPD to swap x,y: + template static inline void + swap(T& a, T& b) + { + T t = a; + a = b; + b = t; + } + + void(*_touchHandler)(TPoint point, TEvent e) = nullptr; + TouchData_t data[5]; + // Tap detection is enabled by default + bool tapDetectionEnabled = true; + // Only if the time difference between press and release is minor than this milliseconds a Tap even is triggered + uint16_t tapDetectionMillisDiff = 100; + +private: + TPoint scanPoint(); + void writeRegister8(uint8_t reg, uint8_t val); + void writeData(uint8_t *data, int len); + void readBytes(uint8_t *data, int len); + uint8_t readRegister8(uint8_t reg, uint8_t *data_buf); + void fireEvent(TPoint point, TEvent e); + uint8_t read8(uint8_t regName); + void clearFlags(); + + static L58Touch * _instance; + uint8_t _intPin; + + // Make touch rotation aware: + uint8_t _rotation = 0; + uint16_t _touch_width = 0; + uint16_t _touch_height = 0; + + uint8_t _touches; + uint16_t _touchX[2], _touchY[2], _touchEvent[2]; + TPoint _points[10]; + TPoint _point; + uint8_t _pointIdx = 0; + unsigned long _touchStartTime = 0; + unsigned long _touchEndTime = 0; + uint8_t lastEvent = 3; // No event + uint16_t lastX = 0; + uint16_t lastY = 0; + bool _dragMode = false; + const uint8_t maxDeviation = 5; +}; + +#endif \ No newline at end of file