From a0113e0d5cc59415ac03273ed2eb97a3c2c23aac Mon Sep 17 00:00:00 2001 From: martinberlin Date: Fri, 28 May 2021 20:53:08 +0200 Subject: [PATCH 01/31] Setup epdiy_epaper generic driver REF: https://github.com/martinberlin/lv_port_esp32-epaper/issues/2 Flushing too often, drawing only 40 px on top of display --- CMakeLists.txt | 2 ++ CONTRIBUTE_CONTROLLER_SUPPORT.md | 6 ++++ lvgl_helpers.c | 7 +++- lvgl_helpers.h | 2 ++ lvgl_tft/Kconfig | 17 ++++++++- lvgl_tft/disp_driver.c | 11 ++++++ lvgl_tft/epdiy_epaper.cpp | 62 ++++++++++++++++++++++++++++++++ lvgl_tft/epdiy_epaper.h | 37 +++++++++++++++++++ lvgl_tft/il3820.c | 4 +-- 9 files changed, 144 insertions(+), 4 deletions(-) create mode 100644 lvgl_tft/epdiy_epaper.cpp create mode 100644 lvgl_tft/epdiy_epaper.h diff --git a/CMakeLists.txt b/CMakeLists.txt index d86bd33f..ffd28714 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,6 +10,8 @@ list(APPEND SOURCES "lvgl_tft/disp_driver.c") # display controller. 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_TFT_DISPLAY_CONTROLLER_ILI9481) list(APPEND SOURCES "lvgl_tft/ili9481.c") elseif(CONFIG_LV_TFT_DISPLAY_CONTROLLER_ILI9486) diff --git a/CONTRIBUTE_CONTROLLER_SUPPORT.md b/CONTRIBUTE_CONTROLLER_SUPPORT.md index db4c6474..fa7af3cc 100644 --- a/CONTRIBUTE_CONTROLLER_SUPPORT.md +++ b/CONTRIBUTE_CONTROLLER_SUPPORT.md @@ -27,6 +27,12 @@ For more information on the function callbacks check LVGL documentation: (Displa Add your display functions on `disp_driver_init`, `disp_driver_flush`, `disp_driver_rounder` and `disp_driver_set_px` on the `disp_driver.c` file. +**Additional notes** + +New drivers should be also have some defines added in: +lvgl_helpers.h +(follow existing ones to add yours) + ## Input device driver. To enable LVGL to work with your touch controller you would need to implement an initialization function and one function to get the data out from your touch controller. diff --git a/lvgl_helpers.c b/lvgl_helpers.c index 41253307..dc83c990 100644 --- a/lvgl_helpers.c +++ b/lvgl_helpers.c @@ -123,9 +123,14 @@ void lvgl_driver_init(void) DISP_I2C_SDA, DISP_I2C_SCL, DISP_I2C_SPEED_HZ); + disp_driver_init(); +#elif defined (CONFIG_LV_EPAPER_DISPLAY_PROTOCOL_PARALLEL) + // Do not initialize SPI. Uses EPDiy + ESP_LOGI(TAG, "Initializing Parallel driver for display"); + // Check how not to initialize SPI. disp_driver_init() call is needed: disp_driver_init(); #else -#error "No protocol defined for display controller" + #error "No protocol defined for display controller" #endif /* Touch controller initialization */ diff --git a/lvgl_helpers.h b/lvgl_helpers.h index 70ef3534..0fe84874 100644 --- a/lvgl_helpers.h +++ b/lvgl_helpers.h @@ -42,6 +42,8 @@ extern "C" { #define DISP_BUF_SIZE (LV_HOR_RES_MAX * 40) #elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_ST7796S #define DISP_BUF_SIZE (LV_HOR_RES_MAX * 40) +#elif defined (CONFIG_LV_EPAPER_EPDIY_DISPLAY_CONTROLLER) +#define DISP_BUF_SIZE (LV_HOR_RES_MAX * 40) #elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_HX8357 #define DISP_BUF_SIZE (LV_HOR_RES_MAX * 40) #elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_SH1107 diff --git a/lvgl_tft/Kconfig b/lvgl_tft/Kconfig index ddd7f516..4d651141 100644 --- a/lvgl_tft/Kconfig +++ b/lvgl_tft/Kconfig @@ -1,7 +1,7 @@ # NOTES: # - default <> if <> work only when no prompt is available for the user -menu "LVGL TFT Display controller" +menu "LVGL TFT/Epaper Display controller" # Predefined display configurations for multiple # evaluation/development boards. @@ -85,6 +85,11 @@ menu "LVGL TFT Display controller" # # If you add support for a new display controller to the repository # you must add a config option for it on this helper symbols section. + config LV_EPAPER_EPDIY_DISPLAY_CONTROLLER + bool + help + EPDIY parallel epaper controller. + config LV_TFT_DISPLAY_CONTROLLER_ILI9341 bool help @@ -173,6 +178,11 @@ menu "LVGL TFT Display controller" # - Know what peripherals to initialize. # - Know if the touch and display controllers share the same peripheral. # - Etc. + config LV_EPAPER_DISPLAY_PROTOCOL_PARALLEL + bool + help + Epaper controller protocol Parallel based on EPDiy 8 data lines + config LV_TFT_DISPLAY_PROTOCOL_SPI bool help @@ -257,6 +267,11 @@ menu "LVGL TFT Display controller" prompt "Select a display controller model." if LV_PREDEFINED_DISPLAY_NONE help Select the controller for your display. + config LV_EPAPER_DISPLAY_USER_CONTROLLER_EPDIY + bool "EPDIY_GENERIC" + select LV_EPAPER_EPDIY_DISPLAY_CONTROLLER + select LV_EPAPER_DISPLAY_PROTOCOL_PARALLEL + #select LV_TFT_DISPLAY_PROTOCOL_SPI config LV_TFT_DISPLAY_USER_CONTROLLER_ILI9341 bool "ILI9341" diff --git a/lvgl_tft/disp_driver.c b/lvgl_tft/disp_driver.c index 9f8e8579..e0d636b9 100644 --- a/lvgl_tft/disp_driver.c +++ b/lvgl_tft/disp_driver.c @@ -4,11 +4,15 @@ #include "disp_driver.h" #include "disp_spi.h" +// This should be included with CMakeLists but is not +#include "lvgl_tft/epdiy_epaper.h" void disp_driver_init(void) { #if defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_ILI9341 ili9341_init(); +#elif defined CONFIG_LV_EPAPER_EPDIY_DISPLAY_CONTROLLER + epdiy_init(); #elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_ILI9481 ili9481_init(); #elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_ILI9488 @@ -46,6 +50,8 @@ 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_TFT_DISPLAY_CONTROLLER_ILI9481 ili9481_flush(drv, area, color_map); #elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_ILI9488 @@ -81,8 +87,11 @@ void disp_driver_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * void disp_driver_rounder(lv_disp_drv_t * disp_drv, lv_area_t * area) { + // Does not apply so far to epdiy #if defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_SSD1306 ssd1306_rounder(disp_drv, area); +#elif defined CONFIG_LV_EPAPER_EPDIY_DISPLAY_CONTROLLER + epdiy_rounder(disp_drv, area); #elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_SH1107 sh1107_rounder(disp_drv, area); #elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_IL3820 @@ -99,6 +108,8 @@ void disp_driver_set_px(lv_disp_drv_t * disp_drv, uint8_t * buf, lv_coord_t buf_ { #if defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_SSD1306 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_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/epdiy_epaper.cpp b/lvgl_tft/epdiy_epaper.cpp new file mode 100644 index 00000000..5359dff6 --- /dev/null +++ b/lvgl_tft/epdiy_epaper.cpp @@ -0,0 +1,62 @@ +#include "esp_log.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +#include "epdiy_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; + +/********************* + * DEFINES + *********************/ +#define TAG "EPDIY" + +uint16_t flushcalls = 0; + +/* Display initialization routine */ +void epdiy_init(void) +{ + printf("epdiy_init\n"); + display.init(); + display.setRotation(0); + //display.clearScreen(); +} + +/* Required by LVGL */ +void epdiy_flush(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_map) +{ + ++flushcalls; + printf("epdiy_flush %d\n", flushcalls); + display.update(); + /* IMPORTANT!!! + * Inform the graphics library that you are ready with the flushing */ + lv_disp_flush_ready(drv); +} + +/* Called for each pixel */ +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) +{ + // Is printing Y axis only till 40 px: And flushing too many times + //printf("%d ", (int16_t)y); // Works and prints "Hello world" + //printf("%d ",(int16_t)color.full); // Debug colors + // Test using RGB232 + int16_t epd_color = EPD_WHITE; + + // Color setting use: RGB232 + if ((int16_t)color.full<250) { + epd_color = (int16_t)color.full; + } + display.drawPixel((int16_t)x, (int16_t)y, epd_color); +} + +/* Required by LVGL. Not used in this implementation - deprecated, will be removed */ +void epdiy_rounder(lv_disp_drv_t * disp_drv, lv_area_t *area) { +} diff --git a/lvgl_tft/epdiy_epaper.h b/lvgl_tft/epdiy_epaper.h new file mode 100644 index 00000000..1cad34f4 --- /dev/null +++ b/lvgl_tft/epdiy_epaper.h @@ -0,0 +1,37 @@ +/** + * Display class for generic e-Paper driven by EPDiy class +*/ +#ifndef EPDIY_H +#define EPDIY_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 epdiy_init(void); + +/* LVGL callbacks */ +void epdiy_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 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); + +void epdiy_rounder(lv_disp_drv_t * disp_drv, lv_area_t *area); +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* EPDIY_H */ \ No newline at end of file diff --git a/lvgl_tft/il3820.c b/lvgl_tft/il3820.c index 45ae2762..4295ae0f 100644 --- a/lvgl_tft/il3820.c +++ b/lvgl_tft/il3820.c @@ -160,7 +160,7 @@ void il3820_set_px_cb(lv_disp_drv_t * disp_drv, uint8_t* buf, uint16_t byte_index = 0; uint8_t bit_index = 0; -#if defined (CONFIG_LV_DISPLAY_ORIENTATION_PORTRAIT) +#if defined (CONFIG_DISPLAY_ORIENTATION_PORTRAIT) byte_index = x + ((y >> 3) * EPD_PANEL_HEIGHT); bit_index = y & 0x7; @@ -170,7 +170,7 @@ void il3820_set_px_cb(lv_disp_drv_t * disp_drv, uint8_t* buf, uint16_t mirrored_idx = (EPD_PANEL_HEIGHT - x) + ((y >> 3) * EPD_PANEL_HEIGHT); BIT_CLEAR(buf[mirrored_idx], 7 - bit_index); } -#elif defined (CONFIG_LV_DISPLAY_ORIENTATION_LANDSCAPE) +#elif defined (CONFIG_DISPLAY_ORIENTATION_LANDSCAPE) byte_index = y + ((x >> 3) * EPD_PANEL_HEIGHT); bit_index = x & 0x7; From 2d3a1fa7c30cccce413db5da7942f6fded9a9057 Mon Sep 17 00:00:00 2001 From: martinberlin Date: Fri, 28 May 2021 21:07:46 +0200 Subject: [PATCH 02/31] Make grays darker --- lvgl_tft/epdiy_epaper.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lvgl_tft/epdiy_epaper.cpp b/lvgl_tft/epdiy_epaper.cpp index 5359dff6..da91ffcc 100644 --- a/lvgl_tft/epdiy_epaper.cpp +++ b/lvgl_tft/epdiy_epaper.cpp @@ -33,6 +33,7 @@ void epdiy_flush(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_ma { ++flushcalls; printf("epdiy_flush %d\n", flushcalls); + display.update(); /* IMPORTANT!!! * Inform the graphics library that you are ready with the flushing */ @@ -52,11 +53,13 @@ void epdiy_set_px_cb(lv_disp_drv_t * disp_drv, uint8_t* buf, // Color setting use: RGB232 if ((int16_t)color.full<250) { - epd_color = (int16_t)color.full; + epd_color = (int16_t)color.full/3; } display.drawPixel((int16_t)x, (int16_t)y, epd_color); } /* Required by LVGL. Not used in this implementation - deprecated, will be removed */ void epdiy_rounder(lv_disp_drv_t * disp_drv, lv_area_t *area) { + area->x1 = area->x1 & ~(0x7); + area->x2 = area->x2 | (0x7); } From f4a760d4823b0a5d0d5926bc11ce21775ea71dbc Mon Sep 17 00:00:00 2001 From: martinberlin Date: Fri, 28 May 2021 22:28:14 +0200 Subject: [PATCH 03/31] Enlarge DISP_BUF_SIZE. Remove epdiy_rounder callback since is not used --- lvgl_helpers.h | 3 ++- lvgl_tft/disp_driver.c | 2 -- lvgl_tft/epdiy_epaper.cpp | 8 +------- lvgl_tft/epdiy_epaper.h | 1 - 4 files changed, 3 insertions(+), 11 deletions(-) diff --git a/lvgl_helpers.h b/lvgl_helpers.h index 0fe84874..0a7a415f 100644 --- a/lvgl_helpers.h +++ b/lvgl_helpers.h @@ -42,8 +42,9 @@ extern "C" { #define DISP_BUF_SIZE (LV_HOR_RES_MAX * 40) #elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_ST7796S #define DISP_BUF_SIZE (LV_HOR_RES_MAX * 40) +// Here is the issue that it does not draw full epaper. Insufficient buffer: #elif defined (CONFIG_LV_EPAPER_EPDIY_DISPLAY_CONTROLLER) -#define DISP_BUF_SIZE (LV_HOR_RES_MAX * 40) +#define DISP_BUF_SIZE (LV_HOR_RES_MAX * 70) #elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_HX8357 #define DISP_BUF_SIZE (LV_HOR_RES_MAX * 40) #elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_SH1107 diff --git a/lvgl_tft/disp_driver.c b/lvgl_tft/disp_driver.c index e0d636b9..07a6b2ba 100644 --- a/lvgl_tft/disp_driver.c +++ b/lvgl_tft/disp_driver.c @@ -90,8 +90,6 @@ void disp_driver_rounder(lv_disp_drv_t * disp_drv, lv_area_t * area) // Does not apply so far to epdiy #if defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_SSD1306 ssd1306_rounder(disp_drv, area); -#elif defined CONFIG_LV_EPAPER_EPDIY_DISPLAY_CONTROLLER - epdiy_rounder(disp_drv, area); #elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_SH1107 sh1107_rounder(disp_drv, area); #elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_IL3820 diff --git a/lvgl_tft/epdiy_epaper.cpp b/lvgl_tft/epdiy_epaper.cpp index da91ffcc..5729a05f 100644 --- a/lvgl_tft/epdiy_epaper.cpp +++ b/lvgl_tft/epdiy_epaper.cpp @@ -25,7 +25,7 @@ void epdiy_init(void) printf("epdiy_init\n"); display.init(); display.setRotation(0); - //display.clearScreen(); + display.clearScreen(); } /* Required by LVGL */ @@ -57,9 +57,3 @@ void epdiy_set_px_cb(lv_disp_drv_t * disp_drv, uint8_t* buf, } display.drawPixel((int16_t)x, (int16_t)y, epd_color); } - -/* Required by LVGL. Not used in this implementation - deprecated, will be removed */ -void epdiy_rounder(lv_disp_drv_t * disp_drv, lv_area_t *area) { - area->x1 = area->x1 & ~(0x7); - area->x2 = area->x2 | (0x7); -} diff --git a/lvgl_tft/epdiy_epaper.h b/lvgl_tft/epdiy_epaper.h index 1cad34f4..247ceea0 100644 --- a/lvgl_tft/epdiy_epaper.h +++ b/lvgl_tft/epdiy_epaper.h @@ -28,7 +28,6 @@ void epdiy_flush(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_ma //void epdiy_rounder(lv_disp_drv_t *disp_drv, lv_area_t *area); 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); -void epdiy_rounder(lv_disp_drv_t * disp_drv, lv_area_t *area); #ifdef __cplusplus } /* extern "C" */ #endif From 7d339be14aa910c31a66fcdb574d40566d64e193 Mon Sep 17 00:00:00 2001 From: martinberlin Date: Sat, 29 May 2021 02:03:04 +0200 Subject: [PATCH 04/31] Attempt to add partial update when flush area is not full screen --- lvgl_helpers.h | 2 +- lvgl_tft/epdiy_epaper.cpp | 11 +++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/lvgl_helpers.h b/lvgl_helpers.h index 0a7a415f..8699ec7d 100644 --- a/lvgl_helpers.h +++ b/lvgl_helpers.h @@ -44,7 +44,7 @@ extern "C" { #define DISP_BUF_SIZE (LV_HOR_RES_MAX * 40) // Here is the issue that it does not draw full epaper. Insufficient buffer: #elif defined (CONFIG_LV_EPAPER_EPDIY_DISPLAY_CONTROLLER) -#define DISP_BUF_SIZE (LV_HOR_RES_MAX * 70) +#define DISP_BUF_SIZE (LV_HOR_RES_MAX * 90) #elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_HX8357 #define DISP_BUF_SIZE (LV_HOR_RES_MAX * 40) #elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_SH1107 diff --git a/lvgl_tft/epdiy_epaper.cpp b/lvgl_tft/epdiy_epaper.cpp index 5729a05f..4ea6c897 100644 --- a/lvgl_tft/epdiy_epaper.cpp +++ b/lvgl_tft/epdiy_epaper.cpp @@ -32,9 +32,16 @@ void epdiy_init(void) void epdiy_flush(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_map) { ++flushcalls; - printf("epdiy_flush %d\n", flushcalls); + printf("epdiy_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)); - display.update(); + // Full update + if (lv_area_get_width(area)==display.width() && lv_area_get_height(area)==display.height()) { + display.update(); + } else { + // Partial update: Looks nice but should find a way to clear that area first. Mode: MODE_EPDIY_WHITE_TO_GL16 + display.updateWindow(area->x1,area->y1,lv_area_get_width(area),lv_area_get_height(area),MODE_GC16); + } + /* IMPORTANT!!! * Inform the graphics library that you are ready with the flushing */ lv_disp_flush_ready(drv); From c9660bd69f12d12fc1428259d273741fc6d29724 Mon Sep 17 00:00:00 2001 From: martinberlin Date: Sun, 30 May 2021 19:51:59 +0200 Subject: [PATCH 05/31] #3 Start adding L58: Find a way to instantiate existing class or refactor it to C --- CMakeLists.txt | 2 ++ lvgl_helpers.c | 8 ++++-- lvgl_touch/Kconfig | 39 +++++++++++++++++++++++++- lvgl_touch/l58.cpp | 55 +++++++++++++++++++++++++++++++++++++ lvgl_touch/l58.h | 58 +++++++++++++++++++++++++++++++++++++++ lvgl_touch/touch_driver.c | 8 +++++- 6 files changed, 165 insertions(+), 5 deletions(-) create mode 100644 lvgl_touch/l58.cpp create mode 100644 lvgl_touch/l58.h diff --git a/CMakeLists.txt b/CMakeLists.txt index ffd28714..bd01af92 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -62,6 +62,8 @@ if(CONFIG_LV_TOUCH_CONTROLLER) list(APPEND SOURCES "lvgl_touch/xpt2046.c") 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.cpp") elseif(CONFIG_LV_TOUCH_CONTROLLER_STMPE610) list(APPEND SOURCES "lvgl_touch/stmpe610.c") elseif(CONFIG_LV_TOUCH_CONTROLLER_ADCRAW) diff --git a/lvgl_helpers.c b/lvgl_helpers.c index dc83c990..b611e9f9 100644 --- a/lvgl_helpers.c +++ b/lvgl_helpers.c @@ -147,19 +147,21 @@ void lvgl_driver_init(void) touch_driver_init(); #elif defined (CONFIG_LV_TOUCH_DRIVER_PROTOCOL_I2C) + // Why initializing this when I said is only CONFIG_LV_TOUCH_DRIVER_DISPLAY ESP_LOGI(TAG, "Initializing I2C master for touch"); lvgl_i2c_driver_init(TOUCH_I2C_PORT, TOUCH_I2C_SDA, TOUCH_I2C_SCL, - TOUCH_I2C_SPEED_HZ); + TOUCH_I2C_SPEED_HZ); touch_driver_init(); #elif defined (CONFIG_LV_TOUCH_DRIVER_ADC) touch_driver_init(); - #elif defined (CONFIG_LV_TOUCH_DRIVER_DISPLAY) + #elif defined (CONFIG_LV_TOUCH_DRIVER_DISPLAY) || defined (CONFIG_LV_TOUCH_CONTROLLER_L58) touch_driver_init(); #else - #error "No protocol defined for touch controller" + #error "No protocol defined for touch controller" + #endif #else #endif diff --git a/lvgl_touch/Kconfig b/lvgl_touch/Kconfig index edd1dab0..ad6f4f3b 100644 --- a/lvgl_touch/Kconfig +++ b/lvgl_touch/Kconfig @@ -9,7 +9,7 @@ menu "LVGL Touch controller" default 4 if LV_TOUCH_CONTROLLER_ADCRAW default 5 if LV_TOUCH_CONTROLLER_FT81X default 6 if LV_TOUCH_CONTROLLER_RA8875 - + default 7 if LV_TOUCH_CONTROLLER_L58 choice prompt "Select a touch panel controller model." default LV_TOUCH_CONTROLLER_NONE @@ -24,6 +24,12 @@ menu "LVGL Touch controller" config LV_TOUCH_CONTROLLER_FT6X06 select LV_TOUCH_DRIVER_PROTOCOL_I2C bool "FT6X06" + + config LV_TOUCH_CONTROLLER_L58 + # Start only touch without protocol: + select CONFIG_LV_TOUCH_DRIVER_DISPLAY + bool "L58" + config LV_TOUCH_CONTROLLER_STMPE610 select LV_TOUCH_DRIVER_PROTOCOL_SPI bool "STMPE610" @@ -90,6 +96,37 @@ menu "LVGL Touch controller" bool "FSPI" if IDF_TARGET_ESP32S2 endchoice + menu "Touchpanel (L58) Lilygo Pin Assignments" + depends on LV_TOUCH_CONTROLLER_L58 + + config LV_TOUCH_I2C_SDA + int + prompt "GPIO for SDA (I2C)" + range 0 39 if IDF_TARGET_ESP32 + range 0 43 if IDF_TARGET_ESP32S2 + + default 15 + help + Configure the I2C touchpanel SDA pin here. + + config LV_TOUCH_I2C_SCL + int "GPIO for clock signal SCL (I2C)" + range 0 39 if IDF_TARGET_ESP32 + range 0 43 if IDF_TARGET_ESP32S2 + + default 14 + help + Configure the I2C touchpanel SCL pin here. + config LV_TOUCH_INT + int "GPIO for Interrupt pin (INT)" + range 0 39 if IDF_TARGET_ESP32 + range 0 43 if IDF_TARGET_ESP32S2 + + default 13 + help + Configure the INT Pin (Low on event) + endmenu + menu "Touchpanel (XPT2046) Pin Assignments" depends on LV_TOUCH_CONTROLLER_XPT2046 diff --git a/lvgl_touch/l58.cpp b/lvgl_touch/l58.cpp new file mode 100644 index 00000000..875fe74c --- /dev/null +++ b/lvgl_touch/l58.cpp @@ -0,0 +1,55 @@ +/* +* Copyright © 2020 Martin Fasani +* Permission is hereby granted, free of charge, to any person obtaining a copy of this +* software and associated documentation files (the “Software”), to deal in the Software +* without restriction, including without limitation the rights to use, copy, modify, merge, +* publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +* to whom the Software is furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all copies or +* substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +* FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +#include +#include +#ifdef LV_LVGL_H_INCLUDE_SIMPLE +#include +#else +#include +#endif +#include "l58.h" +#include "tp_i2c.h" +#include "../lvgl_i2c_conf.h" + +#define TAG "L58" + + + +/** + * @brief Initialize for FT6x36 communication via I2C + * @param dev_addr: Device address on communication Bus (I2C slave address of FT6X36). + * @retval None + */ +void l58_init(uint16_t dev_addr) { + ESP_LOGI(TAG, "l58_init()"); + +} + +/** + * @brief Get the touch screen X and Y positions values. Ignores multi touch + * @param drv: + * @param data: Store data here + * @retval Always false + */ +bool l58_read(lv_indev_drv_t *drv, lv_indev_data_t *data) { + //printf("Touch event %d\n", gpio_get_level(CONFIG_LV_TOUCH_INT)); // Working + + return false; +} diff --git a/lvgl_touch/l58.h b/lvgl_touch/l58.h new file mode 100644 index 00000000..4d5897e1 --- /dev/null +++ b/lvgl_touch/l58.h @@ -0,0 +1,58 @@ +#ifndef __L58_H +/* +* Copyright © 2020 Martin Fasani. Refectored from original driver in https://github.com/martinberlin/FT6X36-IDF (C++) +* +* Permission is hereby granted, free of charge, to any person obtaining a copy of this +* software and associated documentation files (the “Software”), to deal in the Software +* without restriction, including without limitation the rights to use, copy, modify, merge, +* publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +* to whom the Software is furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all copies or +* substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +* FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +#define __L58_H + +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/semphr.h" + +#ifdef LV_LVGL_H_INCLUDE_SIMPLE +#include "lvgl.h" +#else +#include "lvgl/lvgl.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Initialize for FT6x36 communication via I2C + * @param dev_addr: Device address on communication Bus (I2C slave address of FT6X36). + * @retval None + */ +void l58_init(uint16_t dev_addr); + +/** + * @brief Get the touch screen X and Y positions values. Ignores multi touch + * @param drv: + * @param data: Store data here + * @retval Always false + */ +bool l58_read(lv_indev_drv_t *drv, lv_indev_data_t *data); + +#ifdef __cplusplus +} +#endif +#endif /* __FT6X06_H */ diff --git a/lvgl_touch/touch_driver.c b/lvgl_touch/touch_driver.c index b0aed881..d22c1d64 100644 --- a/lvgl_touch/touch_driver.c +++ b/lvgl_touch/touch_driver.c @@ -5,7 +5,8 @@ #include "touch_driver.h" #include "tp_spi.h" #include "tp_i2c.h" - +// Is not being included in CMakeLists.txt (Research why) +#include "l58.cpp" void touch_driver_init(void) { @@ -13,6 +14,8 @@ void touch_driver_init(void) xpt2046_init(); #elif defined (CONFIG_LV_TOUCH_CONTROLLER_FT6X06) ft6x06_init(FT6236_I2C_SLAVE_ADDR); +#elif defined (CONFIG_LV_TOUCH_CONTROLLER_L58) + // Do nothing for now #elif defined (CONFIG_LV_TOUCH_CONTROLLER_STMPE610) stmpe610_init(); #elif defined (CONFIG_LV_TOUCH_CONTROLLER_ADCRAW) @@ -32,6 +35,9 @@ bool touch_driver_read(lv_indev_drv_t *drv, lv_indev_data_t *data) res = xpt2046_read(drv, data); #elif defined (CONFIG_LV_TOUCH_CONTROLLER_FT6X06) res = ft6x36_read(drv, data); +#elif defined (CONFIG_LV_TOUCH_CONTROLLER_L58) + res = l58_read(drv, data); + #elif defined (CONFIG_LV_TOUCH_CONTROLLER_STMPE610) res = stmpe610_read(drv, data); #elif defined (CONFIG_LV_TOUCH_CONTROLLER_ADCRAW) From debae0b8145c4ead1c18568cc46075e25f1691e4 Mon Sep 17 00:00:00 2001 From: martinberlin Date: Sun, 30 May 2021 20:13:32 +0200 Subject: [PATCH 06/31] #3 Add touch hook for Lilygo L58 --- lvgl_helpers.c | 2 -- lvgl_touch/l58.cpp | 23 +++++++++++++++-------- lvgl_touch/l58.h | 3 +-- lvgl_touch/touch_driver.c | 4 ++-- 4 files changed, 18 insertions(+), 14 deletions(-) diff --git a/lvgl_helpers.c b/lvgl_helpers.c index b611e9f9..237267d1 100644 --- a/lvgl_helpers.c +++ b/lvgl_helpers.c @@ -147,9 +147,7 @@ void lvgl_driver_init(void) touch_driver_init(); #elif defined (CONFIG_LV_TOUCH_DRIVER_PROTOCOL_I2C) - // Why initializing this when I said is only CONFIG_LV_TOUCH_DRIVER_DISPLAY ESP_LOGI(TAG, "Initializing I2C master for touch"); - lvgl_i2c_driver_init(TOUCH_I2C_PORT, TOUCH_I2C_SDA, TOUCH_I2C_SCL, TOUCH_I2C_SPEED_HZ); diff --git a/lvgl_touch/l58.cpp b/lvgl_touch/l58.cpp index 875fe74c..de4329d8 100644 --- a/lvgl_touch/l58.cpp +++ b/lvgl_touch/l58.cpp @@ -25,21 +25,22 @@ #include #endif #include "l58.h" -#include "tp_i2c.h" #include "../lvgl_i2c_conf.h" - +// Cale touch implementation +#include "L58Touch.h" +L58Touch Touch(CONFIG_LV_TOUCH_INT); #define TAG "L58" - +TPoint point; /** * @brief Initialize for FT6x36 communication via I2C * @param dev_addr: Device address on communication Bus (I2C slave address of FT6X36). * @retval None */ -void l58_init(uint16_t dev_addr) { - ESP_LOGI(TAG, "l58_init()"); - +void l58_init() { + ESP_LOGI(TAG, "l58_init() Touch initialized"); + Touch.begin(960, 540); } /** @@ -49,7 +50,13 @@ void l58_init(uint16_t dev_addr) { * @retval Always false */ bool l58_read(lv_indev_drv_t *drv, lv_indev_data_t *data) { - //printf("Touch event %d\n", gpio_get_level(CONFIG_LV_TOUCH_INT)); // Working - + point = Touch.loop(); + data->point.x = point.x; + data->point.y = point.y; + if (point.event == 3) { + data->state = LV_INDEV_STATE_PR; + } else { + data->state = LV_INDEV_STATE_REL; + } return false; } diff --git a/lvgl_touch/l58.h b/lvgl_touch/l58.h index 4d5897e1..89725b85 100644 --- a/lvgl_touch/l58.h +++ b/lvgl_touch/l58.h @@ -39,10 +39,9 @@ extern "C" { /** * @brief Initialize for FT6x36 communication via I2C - * @param dev_addr: Device address on communication Bus (I2C slave address of FT6X36). * @retval None */ -void l58_init(uint16_t dev_addr); +void l58_init(); /** * @brief Get the touch screen X and Y positions values. Ignores multi touch diff --git a/lvgl_touch/touch_driver.c b/lvgl_touch/touch_driver.c index d22c1d64..4508810c 100644 --- a/lvgl_touch/touch_driver.c +++ b/lvgl_touch/touch_driver.c @@ -6,7 +6,7 @@ #include "tp_spi.h" #include "tp_i2c.h" // Is not being included in CMakeLists.txt (Research why) -#include "l58.cpp" +#include "l58.h" void touch_driver_init(void) { @@ -15,7 +15,7 @@ void touch_driver_init(void) #elif defined (CONFIG_LV_TOUCH_CONTROLLER_FT6X06) ft6x06_init(FT6236_I2C_SLAVE_ADDR); #elif defined (CONFIG_LV_TOUCH_CONTROLLER_L58) - // Do nothing for now + l58_init(); #elif defined (CONFIG_LV_TOUCH_CONTROLLER_STMPE610) stmpe610_init(); #elif defined (CONFIG_LV_TOUCH_CONTROLLER_ADCRAW) From 19b1ecde22425defd4a61fb0a6e718d5c7755119 Mon Sep 17 00:00:00 2001 From: Martin Fasani Date: Tue, 1 Jun 2021 16:10:59 +0200 Subject: [PATCH 07/31] Update epdiy driver using it standalone, without CalEPD. Previous is not epdiy_cale.cpp --- lvgl_tft/epdiy_epaper.cpp | 88 ++++++++++++++++++++++++++------------- 1 file changed, 59 insertions(+), 29 deletions(-) diff --git a/lvgl_tft/epdiy_epaper.cpp b/lvgl_tft/epdiy_epaper.cpp index 4ea6c897..d85fe45c 100644 --- a/lvgl_tft/epdiy_epaper.cpp +++ b/lvgl_tft/epdiy_epaper.cpp @@ -4,63 +4,93 @@ #include "epdiy_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; +#include "epd_driver.h" +#include "epd_highlevel.h" /********************* * DEFINES *********************/ #define TAG "EPDIY" - +EpdiyHighlevelState hl; uint16_t flushcalls = 0; +uint8_t * framebuffer; +uint8_t temperature = 25; /* Display initialization routine */ void epdiy_init(void) { - printf("epdiy_init\n"); - display.init(); - display.setRotation(0); - display.clearScreen(); + epd_init(EPD_OPTIONS_DEFAULT); + hl = epd_hl_init(EPD_BUILTIN_WAVEFORM); + framebuffer = epd_hl_get_framebuffer(&hl); + epd_fullclear(&hl, temperature); + epd_poweron(); } +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; - printf("epdiy_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)); + xo = area->x1; + yo = area->y1; + uint16_t w = lv_area_get_width(area); + uint16_t h = 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: Looks nice but should find a way to clear that area first. Mode: MODE_EPDIY_WHITE_TO_GL16 - display.updateWindow(area->x1,area->y1,lv_area_get_width(area),lv_area_get_height(area),MODE_GC16); - } - - /* IMPORTANT!!! - * Inform the graphics library that you are ready with the flushing */ + EpdRect update_area = { + .x = xo, + .y = yo, + .width = w, + .height = h, + }; + + // Debug test: Draw box x:232 y:78 w:496 h:198. Flush coords are correct: + /* EpdRect rect_area = { + .x = 232, + .y = 78, + .width = 496, + .height = 198, + }; + epd_draw_rect(rect_area, 0, framebuffer); */ + 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 */ +/* + * 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) { - // Is printing Y axis only till 40 px: And flushing too many times - //printf("%d ", (int16_t)y); // Works and prints "Hello world" - //printf("%d ",(int16_t)color.full); // Debug colors + // 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 = EPD_WHITE; + int16_t epd_color = 255; // Color setting use: RGB232 if ((int16_t)color.full<250) { epd_color = (int16_t)color.full/3; } - display.drawPixel((int16_t)x, (int16_t)y, epd_color); + + int16_t x1 = (int16_t)x; + int16_t y1 = (int16_t)y; + // Add offsets from last flush test. Why is drawing in wrong place? + // Bad idea: But is just writing in different area. And I don't understand why: + /* if (flushcalls>0) { + x1 = x1 + xo; + y1 = y1 + yo; + } */ + epd_draw_pixel(x1, y1, epd_color, framebuffer); } From 18350e6fd760519e448029dd3697a9abb7407117 Mon Sep 17 00:00:00 2001 From: Martin Fasani Date: Tue, 1 Jun 2021 16:15:31 +0200 Subject: [PATCH 08/31] Add old calepd version --- lvgl_tft/calepd_epaper.cpp | 66 ++++++++++++++++++++++++++++++++++++++ lvgl_tft/calepd_epaper.h | 36 +++++++++++++++++++++ 2 files changed, 102 insertions(+) create mode 100644 lvgl_tft/calepd_epaper.cpp create mode 100644 lvgl_tft/calepd_epaper.h diff --git a/lvgl_tft/calepd_epaper.cpp b/lvgl_tft/calepd_epaper.cpp new file mode 100644 index 00000000..4ea6c897 --- /dev/null +++ b/lvgl_tft/calepd_epaper.cpp @@ -0,0 +1,66 @@ +#include "esp_log.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +#include "epdiy_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; + +/********************* + * DEFINES + *********************/ +#define TAG "EPDIY" + +uint16_t flushcalls = 0; + +/* Display initialization routine */ +void epdiy_init(void) +{ + printf("epdiy_init\n"); + display.init(); + display.setRotation(0); + display.clearScreen(); +} + +/* Required by LVGL */ +void epdiy_flush(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_map) +{ + ++flushcalls; + printf("epdiy_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: Looks nice but should find a way to clear that area first. Mode: MODE_EPDIY_WHITE_TO_GL16 + display.updateWindow(area->x1,area->y1,lv_area_get_width(area),lv_area_get_height(area),MODE_GC16); + } + + /* IMPORTANT!!! + * Inform the graphics library that you are ready with the flushing */ + lv_disp_flush_ready(drv); +} + +/* Called for each pixel */ +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) +{ + // Is printing Y axis only till 40 px: And flushing too many times + //printf("%d ", (int16_t)y); // Works and prints "Hello world" + //printf("%d ",(int16_t)color.full); // Debug colors + // Test using RGB232 + int16_t epd_color = EPD_WHITE; + + // Color setting use: RGB232 + if ((int16_t)color.full<250) { + epd_color = (int16_t)color.full/3; + } + display.drawPixel((int16_t)x, (int16_t)y, epd_color); +} diff --git a/lvgl_tft/calepd_epaper.h b/lvgl_tft/calepd_epaper.h new file mode 100644 index 00000000..b9cfba7a --- /dev/null +++ b/lvgl_tft/calepd_epaper.h @@ -0,0 +1,36 @@ +/** + * 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 epdiy_init(void); + +/* LVGL callbacks */ +void epdiy_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 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); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* EPDIY_H */ \ No newline at end of file From 42ae32f373db737b5b86ac7fbde6b1994891b12f Mon Sep 17 00:00:00 2001 From: martinberlin Date: Tue, 1 Jun 2021 17:34:03 +0200 Subject: [PATCH 09/31] Update epdiy_epaper to make void epdiy_set_px_cb callback write directly to the framebuffer --- lvgl_tft/epdiy_epaper.cpp | 29 +++++++++++------------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/lvgl_tft/epdiy_epaper.cpp b/lvgl_tft/epdiy_epaper.cpp index d85fe45c..7b99d63d 100644 --- a/lvgl_tft/epdiy_epaper.cpp +++ b/lvgl_tft/epdiy_epaper.cpp @@ -22,8 +22,9 @@ void epdiy_init(void) epd_init(EPD_OPTIONS_DEFAULT); hl = epd_hl_init(EPD_BUILTIN_WAVEFORM); framebuffer = epd_hl_get_framebuffer(&hl); - epd_fullclear(&hl, temperature); epd_poweron(); + //Clear all always in init? + //epd_fullclear(&hl, temperature); } uint16_t xo = 0; @@ -45,14 +46,6 @@ void epdiy_flush(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_ma .height = h, }; - // Debug test: Draw box x:232 y:78 w:496 h:198. Flush coords are correct: - /* EpdRect rect_area = { - .x = 232, - .y = 78, - .width = 496, - .height = 198, - }; - epd_draw_rect(rect_area, 0, framebuffer); */ 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); @@ -78,19 +71,19 @@ void epdiy_set_px_cb(lv_disp_drv_t * disp_drv, uint8_t* buf, // Test using RGB232 int16_t epd_color = 255; - - // Color setting use: RGB232 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; - // Add offsets from last flush test. Why is drawing in wrong place? - // Bad idea: But is just writing in different area. And I don't understand why: - /* if (flushcalls>0) { - x1 = x1 + xo; - y1 = y1 + yo; - } */ - epd_draw_pixel(x1, y1, epd_color, framebuffer); + + //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); + } } From 160035caca34e6430c283211926f29f5e19b6ade Mon Sep 17 00:00:00 2001 From: Martin Fasani Date: Thu, 3 Jun 2021 13:38:23 +0200 Subject: [PATCH 10/31] Add generic CalEPD SPI epaper driver --- CMakeLists.txt | 2 ++ lvgl_helpers.h | 3 +++ lvgl_tft/Kconfig | 13 +++++++--- lvgl_tft/calepd_epaper.cpp | 50 ++++++++++++++++++++++++++------------ lvgl_tft/calepd_epaper.h | 6 ++--- lvgl_tft/disp_driver.c | 9 +++++-- lvgl_tft/disp_driver.h | 4 +++ 7 files changed, 63 insertions(+), 24 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index bd01af92..1500ed40 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,6 +12,8 @@ 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") elseif(CONFIG_LV_TFT_DISPLAY_CONTROLLER_ILI9481) list(APPEND SOURCES "lvgl_tft/ili9481.c") elseif(CONFIG_LV_TFT_DISPLAY_CONTROLLER_ILI9486) diff --git a/lvgl_helpers.h b/lvgl_helpers.h index 8699ec7d..cda1e6ae 100644 --- a/lvgl_helpers.h +++ b/lvgl_helpers.h @@ -45,6 +45,9 @@ extern "C" { // Here is the issue that it does not draw full epaper. Insufficient buffer: #elif defined (CONFIG_LV_EPAPER_EPDIY_DISPLAY_CONTROLLER) #define DISP_BUF_SIZE (LV_HOR_RES_MAX * 90) +#elif defined (CONFIG_LV_EPAPER_CALEPD_DISPLAY_CONTROLLER) +#define DISP_BUF_SIZE (LV_HOR_RES_MAX * 90) + #elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_HX8357 #define DISP_BUF_SIZE (LV_HOR_RES_MAX * 40) #elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_SH1107 diff --git a/lvgl_tft/Kconfig b/lvgl_tft/Kconfig index 4d651141..21be63ff 100644 --- a/lvgl_tft/Kconfig +++ b/lvgl_tft/Kconfig @@ -89,7 +89,10 @@ 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 @@ -271,8 +274,12 @@ menu "LVGL TFT/Epaper Display controller" bool "EPDIY_GENERIC" select LV_EPAPER_EPDIY_DISPLAY_CONTROLLER select LV_EPAPER_DISPLAY_PROTOCOL_PARALLEL - #select LV_TFT_DISPLAY_PROTOCOL_SPI - + + 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 index 4ea6c897..2de1830a 100644 --- a/lvgl_tft/calepd_epaper.cpp +++ b/lvgl_tft/calepd_epaper.cpp @@ -2,15 +2,29 @@ #include "freertos/FreeRTOS.h" #include "freertos/task.h" -#include "epdiy_epaper.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; +//#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 @@ -20,26 +34,29 @@ Ed047TC1 display; uint16_t flushcalls = 0; /* Display initialization routine */ -void epdiy_init(void) +void calepd_init(void) { - printf("epdiy_init\n"); + printf("calepd_init\n"); display.init(); display.setRotation(0); - display.clearScreen(); + // Clear screen + //display.update(); } /* Required by LVGL */ -void epdiy_flush(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_map) +void calepd_flush(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_map) { ++flushcalls; - printf("epdiy_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)); + 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: Looks nice but should find a way to clear that area first. Mode: MODE_EPDIY_WHITE_TO_GL16 - display.updateWindow(area->x1,area->y1,lv_area_get_width(area),lv_area_get_height(area),MODE_GC16); + // 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!!! @@ -48,19 +65,20 @@ void epdiy_flush(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_ma } /* Called for each pixel */ -void epdiy_set_px_cb(lv_disp_drv_t * disp_drv, uint8_t* buf, +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) { - // Is printing Y axis only till 40 px: And flushing too many times - //printf("%d ", (int16_t)y); // Works and prints "Hello world" - //printf("%d ",(int16_t)color.full); // Debug colors + //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 - if ((int16_t)color.full<250) { - epd_color = (int16_t)color.full/3; + // 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 index b9cfba7a..ea5be619 100644 --- a/lvgl_tft/calepd_epaper.h +++ b/lvgl_tft/calepd_epaper.h @@ -19,14 +19,14 @@ extern "C" { #include "sdkconfig.h" /* Configure your display */ -void epdiy_init(void); +void calepd_init(void); /* LVGL callbacks */ -void epdiy_flush(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_map); +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 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); +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" */ diff --git a/lvgl_tft/disp_driver.c b/lvgl_tft/disp_driver.c index 07a6b2ba..b5c4ab27 100644 --- a/lvgl_tft/disp_driver.c +++ b/lvgl_tft/disp_driver.c @@ -4,8 +4,7 @@ #include "disp_driver.h" #include "disp_spi.h" -// This should be included with CMakeLists but is not -#include "lvgl_tft/epdiy_epaper.h" + void disp_driver_init(void) { @@ -13,6 +12,8 @@ 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 @@ -52,6 +53,8 @@ void disp_driver_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * 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); #elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_ILI9481 ili9481_flush(drv, area, color_map); #elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_ILI9488 @@ -108,6 +111,8 @@ 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 e48d05ec..5df0f794 100644 --- a/lvgl_tft/disp_driver.h +++ b/lvgl_tft/disp_driver.h @@ -20,6 +20,10 @@ extern "C" { #if defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_ILI9341 #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 From c539322a3661095b2b7da653520f4b64e8ffbccb Mon Sep 17 00:00:00 2001 From: martinberlin Date: Fri, 11 Jun 2021 12:39:00 +0200 Subject: [PATCH 11/31] Using epdiy_set_px_cb *buf and returning *color_map in flush method to update only the part that is updated. Still buggy but working version --- lvgl_tft/epdiy_epaper_v2.cpp | 154 +++++++++++++++++++++++++++++++++++ 1 file changed, 154 insertions(+) create mode 100644 lvgl_tft/epdiy_epaper_v2.cpp diff --git a/lvgl_tft/epdiy_epaper_v2.cpp b/lvgl_tft/epdiy_epaper_v2.cpp new file mode 100644 index 00000000..2314b1eb --- /dev/null +++ b/lvgl_tft/epdiy_epaper_v2.cpp @@ -0,0 +1,154 @@ +#include "esp_log.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +#include "epdiy_epaper.h" + +#include "epd_driver.h" +#include "epd_highlevel.h" +// Usable size +#include +/********************* + * DEFINES + *********************/ +#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; +uint16_t rx = 0; +uint16_t ry = 0; +uint16_t rw = 0; +uint16_t rh = 0; + +void buf_copy_to_framebuffer(EpdRect image_area, const uint8_t *image_data) { + + assert(framebuffer != NULL); + + for (uint32_t i = 0; i < image_area.width * image_area.height; i++) { + + uint32_t value_index = i; + // for images of uneven width consume an additional nibble per row. + if (image_area.width % 2) { + value_index += i / image_area.width; + } + // Get out if we get the end of the buffer (image_data[value_index / 2]== '\0') 111684 + if (value_index / 2 > 111600) { + printf("FOUND END incr:%d img[idx]:%d Aw:%d Ah:%d\n", i, + value_index / 2,image_area.width,image_area.height); + break; + } + + uint8_t val = (value_index % 2) ? (image_data[value_index / 2] & 0xF0) >> 4 + : image_data[value_index / 2] & 0x0F; + + int xx = image_area.x + i % image_area.width; + if (xx < 0 || xx >= EPD_WIDTH) { + continue; + } + int yy = image_area.y + i / image_area.width; + if (yy < 0 || yy >= EPD_HEIGHT) { + continue; + } + uint8_t *buf_ptr = &framebuffer[yy * EPD_WIDTH / 2 + xx / 2]; + if (xx % 2) { + *buf_ptr = (*buf_ptr & 0x0F) | (val << 4); + } else { + *buf_ptr = (*buf_ptr & 0xF0) | val; + } + } +} + +/* 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, + }; + + uint8_t* buf = (uint8_t *) color_map; + // Buffer debug + /* + for (int index=0; index<400; index++) { + printf("%x ", buf[index]); + } */ + + // Does not work for full screen update yet (Should check large of bug) + if (flushcalls>0){ + buf_copy_to_framebuffer(update_area, buf); + } + + 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); + //printf("epdiy_flush Rounder() x:%d y:%d w:%d h:%d\n",rx,ry,rw,rh); + /* 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) +{ + // Test using RGB232 + int16_t epd_color = 255; + if ((int16_t)color.full<250) { + epd_color = (int16_t)color.full/3; + } + + //Instead of using epd_draw_pixel: Set pixel directly in buffer + uint16_t idx = (int16_t)y * buf_w / 2 + (int16_t)x / 2; + if (x % 2) { + buf[idx] = (buf[idx] & 0x0F) | (epd_color & 0xF0); + } else { + buf[idx] = (buf[idx] & 0xF0) | (epd_color >> 4); + } + + // Directly in framebuffer for epaper + /* uint8_t *buf_ptr = &framebuffer[(int16_t)y * buf_w / 2 + (int16_t)x / 2]; + if (x % 2) { + *buf_ptr = (*buf_ptr & 0x0F) | (epd_color & 0xF0); + } else { + *buf_ptr = (*buf_ptr & 0xF0) | (epd_color >> 4); + } */ +} + +void epdiy_rounder_cb(lv_disp_drv_t *disp_drv, lv_area_t *area) { + // Print coordinates to understand what rounder is + /* rx = (int16_t)area->x1; + ry = (int16_t)area->y1; + rw = (int16_t)lv_area_get_width(area); + rh = (int16_t)lv_area_get_height(area); + printf("R x:%d y:%d y1:%d w:%d h:%d\n",rx,ry,area->y1,rw,rh); */ + + // Force y to be 0: Make some things better, screws other things + //area->y1 = 0; +} \ No newline at end of file From cd2831897355b8c9259a0e411fc922cba94275fa Mon Sep 17 00:00:00 2001 From: martinberlin Date: Fri, 11 Jun 2021 15:14:47 +0200 Subject: [PATCH 12/31] Clean up example with buffer copy --- lvgl_tft/epdiy_epaper_v2.cpp | 59 ++++++++++++------------------------ 1 file changed, 20 insertions(+), 39 deletions(-) diff --git a/lvgl_tft/epdiy_epaper_v2.cpp b/lvgl_tft/epdiy_epaper_v2.cpp index 2314b1eb..7d22a129 100644 --- a/lvgl_tft/epdiy_epaper_v2.cpp +++ b/lvgl_tft/epdiy_epaper_v2.cpp @@ -1,21 +1,13 @@ #include "esp_log.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" - #include "epdiy_epaper.h" - #include "epd_driver.h" #include "epd_highlevel.h" -// Usable size -#include -/********************* - * DEFINES - *********************/ -#define TAG "EPDIY" + EpdiyHighlevelState hl; uint16_t flushcalls = 0; uint8_t * framebuffer; - uint8_t temperature = 25; /* Display initialization routine */ @@ -25,35 +17,29 @@ void epdiy_init(void) hl = epd_hl_init(EPD_BUILTIN_WAVEFORM); framebuffer = epd_hl_get_framebuffer(&hl); epd_poweron(); - //Clear all always in init? + //Clear all always in init: epd_fullclear(&hl, temperature); } -uint16_t xo = 0; -uint16_t yo = 0; -uint16_t rx = 0; -uint16_t ry = 0; -uint16_t rw = 0; -uint16_t rh = 0; - +/* A copy from epd_copy_to_framebuffer with temporary lenght prediction */ void buf_copy_to_framebuffer(EpdRect image_area, const uint8_t *image_data) { - assert(framebuffer != NULL); for (uint32_t i = 0; i < image_area.width * image_area.height; i++) { - uint32_t value_index = i; - // for images of uneven width consume an additional nibble per row. + // For images of uneven width consume an additional nibble per row. if (image_area.width % 2) { value_index += i / image_area.width; } - // Get out if we get the end of the buffer (image_data[value_index / 2]== '\0') 111684 + + // Get out if we get the end of the buffer. Question: How to detect the end without a lenght? + // Zero terminator check gets out before: (image_data[value_index / 2]== '\0') + // 111684 seems to be the last element in image_data if (value_index / 2 > 111600) { printf("FOUND END incr:%d img[idx]:%d Aw:%d Ah:%d\n", i, value_index / 2,image_area.width,image_area.height); break; } - uint8_t val = (value_index % 2) ? (image_data[value_index / 2] & 0xF0) >> 4 : image_data[value_index / 2] & 0x0F; @@ -74,20 +60,18 @@ void buf_copy_to_framebuffer(EpdRect image_area, const uint8_t *image_data) { } } -/* Required by LVGL */ +/* Required by LVGL. Sends the color_map to the screen with a partial update */ 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, + .x = (uint16_t)area->x1, + .y = (uint16_t)area->y1, .width = w, - .height = h, + .height = h }; uint8_t* buf = (uint8_t *) color_map; @@ -97,15 +81,12 @@ void epdiy_flush(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_ma printf("%x ", buf[index]); } */ - // Does not work for full screen update yet (Should check large of bug) - if (flushcalls>0){ - buf_copy_to_framebuffer(update_area, buf); - } + // Does not work for full screen update yet (Should check large of buf) + buf_copy_to_framebuffer(update_area, buf); 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); - //printf("epdiy_flush Rounder() x:%d y:%d w:%d h:%d\n",rx,ry,rw,rh); + printf("epdiy_flush %d x:%d y:%d w:%d h:%d\n", flushcalls,(uint16_t)area->x1,(uint16_t)area->y1,w,h); /* Inform the graphics library that you are ready with the flushing */ lv_disp_flush_ready(drv); } @@ -141,13 +122,13 @@ void epdiy_set_px_cb(lv_disp_drv_t * disp_drv, uint8_t* buf, } */ } +/* Not used at the moment */ void epdiy_rounder_cb(lv_disp_drv_t *disp_drv, lv_area_t *area) { // Print coordinates to understand what rounder is - /* rx = (int16_t)area->x1; - ry = (int16_t)area->y1; - rw = (int16_t)lv_area_get_width(area); - rh = (int16_t)lv_area_get_height(area); - printf("R x:%d y:%d y1:%d w:%d h:%d\n",rx,ry,area->y1,rw,rh); */ + /* + uint16_t rw = (int16_t)lv_area_get_width(area); + uint16_t rh = (int16_t)lv_area_get_height(area); + printf("R x:%d y:%d w:%d h:%d\n",area->x1,area->y1,rw,rh); */ // Force y to be 0: Make some things better, screws other things //area->y1 = 0; From 6dfa2a122a6523e59815b34b44220088f4b8c46a Mon Sep 17 00:00:00 2001 From: martinberlin Date: Sat, 12 Jun 2021 16:10:57 +0200 Subject: [PATCH 13/31] Fill *buf initially with white in first set_px call. Remove additional nibble per row check since this is done already by LVGL# --- lvgl_tft/epdiy_epaper_v2.cpp | 49 ++++++++++++------------------------ 1 file changed, 16 insertions(+), 33 deletions(-) diff --git a/lvgl_tft/epdiy_epaper_v2.cpp b/lvgl_tft/epdiy_epaper_v2.cpp index 7d22a129..0546caf8 100644 --- a/lvgl_tft/epdiy_epaper_v2.cpp +++ b/lvgl_tft/epdiy_epaper_v2.cpp @@ -9,6 +9,8 @@ EpdiyHighlevelState hl; uint16_t flushcalls = 0; uint8_t * framebuffer; uint8_t temperature = 25; +bool init = true; +#define BUF_MAX 111600 /* Display initialization routine */ void epdiy_init(void) @@ -26,23 +28,15 @@ void buf_copy_to_framebuffer(EpdRect image_area, const uint8_t *image_data) { assert(framebuffer != NULL); for (uint32_t i = 0; i < image_area.width * image_area.height; i++) { - uint32_t value_index = i; - // For images of uneven width consume an additional nibble per row. - if (image_area.width % 2) { - value_index += i / image_area.width; - } - // Get out if we get the end of the buffer. Question: How to detect the end without a lenght? // Zero terminator check gets out before: (image_data[value_index / 2]== '\0') // 111684 seems to be the last element in image_data - if (value_index / 2 > 111600) { - printf("FOUND END incr:%d img[idx]:%d Aw:%d Ah:%d\n", i, - value_index / 2,image_area.width,image_area.height); + if (i / 2 > BUF_MAX) { + printf("FOUND END incr:%d Aw:%d Ah:%d\n", i, image_area.width, image_area.height); break; } - uint8_t val = (value_index % 2) ? (image_data[value_index / 2] & 0xF0) >> 4 - : image_data[value_index / 2] & 0x0F; - + uint8_t val = (i % 2) ? (image_data[i / 2] & 0xF0) >> 4 + : image_data[i / 2] & 0x0F; int xx = image_area.x + i % image_area.width; if (xx < 0 || xx >= EPD_WIDTH) { continue; @@ -99,37 +93,26 @@ 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 + if (init) { + printf("Initialize *buf with white\n\n"); + for (int i=0; i> 4); } - - // Directly in framebuffer for epaper - /* uint8_t *buf_ptr = &framebuffer[(int16_t)y * buf_w / 2 + (int16_t)x / 2]; - if (x % 2) { - *buf_ptr = (*buf_ptr & 0x0F) | (epd_color & 0xF0); - } else { - *buf_ptr = (*buf_ptr & 0xF0) | (epd_color >> 4); - } */ } - -/* Not used at the moment */ -void epdiy_rounder_cb(lv_disp_drv_t *disp_drv, lv_area_t *area) { - // Print coordinates to understand what rounder is - /* - uint16_t rw = (int16_t)lv_area_get_width(area); - uint16_t rh = (int16_t)lv_area_get_height(area); - printf("R x:%d y:%d w:%d h:%d\n",area->x1,area->y1,rw,rh); */ - - // Force y to be 0: Make some things better, screws other things - //area->y1 = 0; -} \ No newline at end of file From d71793ffc9e34e62324e0ae30306565ce4f61858 Mon Sep 17 00:00:00 2001 From: martinberlin Date: Sat, 12 Jun 2021 19:53:28 +0200 Subject: [PATCH 14/31] Now first version is renamed to epdiy_epaper_v1.cpp --- lvgl_helpers.h | 2 +- lvgl_tft/{epdiy_epaper.cpp => epdiy_epaper_v1.cpp} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename lvgl_tft/{epdiy_epaper.cpp => epdiy_epaper_v1.cpp} (100%) diff --git a/lvgl_helpers.h b/lvgl_helpers.h index cda1e6ae..cae3a259 100644 --- a/lvgl_helpers.h +++ b/lvgl_helpers.h @@ -44,7 +44,7 @@ extern "C" { #define DISP_BUF_SIZE (LV_HOR_RES_MAX * 40) // Here is the issue that it does not draw full epaper. Insufficient buffer: #elif defined (CONFIG_LV_EPAPER_EPDIY_DISPLAY_CONTROLLER) -#define DISP_BUF_SIZE (LV_HOR_RES_MAX * 90) +#define DISP_BUF_SIZE (LV_HOR_RES_MAX * 110) #elif defined (CONFIG_LV_EPAPER_CALEPD_DISPLAY_CONTROLLER) #define DISP_BUF_SIZE (LV_HOR_RES_MAX * 90) diff --git a/lvgl_tft/epdiy_epaper.cpp b/lvgl_tft/epdiy_epaper_v1.cpp similarity index 100% rename from lvgl_tft/epdiy_epaper.cpp rename to lvgl_tft/epdiy_epaper_v1.cpp From 97a330ca42ece033b0dbb8a0abe360ebeed33a0c Mon Sep 17 00:00:00 2001 From: martinberlin Date: Sat, 12 Jun 2021 19:58:11 +0200 Subject: [PATCH 15/31] Now v2 is the official EPDiy driver of this fork --- lvgl_tft/{epdiy_epaper_v2.cpp => epdiy_epaper.cpp} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename lvgl_tft/{epdiy_epaper_v2.cpp => epdiy_epaper.cpp} (100%) diff --git a/lvgl_tft/epdiy_epaper_v2.cpp b/lvgl_tft/epdiy_epaper.cpp similarity index 100% rename from lvgl_tft/epdiy_epaper_v2.cpp rename to lvgl_tft/epdiy_epaper.cpp From 255a1a768017ee25c16d241a5b970c6462145ca8 Mon Sep 17 00:00:00 2001 From: martinberlin Date: Sun, 13 Jun 2021 09:42:19 +0200 Subject: [PATCH 16/31] Update callbacks to support also fast update MODE_DU configurable with updateMode enum --- lvgl_tft/epdiy_epaper.cpp | 7 +++++-- lvgl_tft/epdiy_epaper_v1.cpp | 9 ++++++--- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/lvgl_tft/epdiy_epaper.cpp b/lvgl_tft/epdiy_epaper.cpp index 0546caf8..569781c9 100644 --- a/lvgl_tft/epdiy_epaper.cpp +++ b/lvgl_tft/epdiy_epaper.cpp @@ -10,6 +10,9 @@ uint16_t flushcalls = 0; uint8_t * framebuffer; uint8_t temperature = 25; bool init = true; +// MODE_DU: Fast monochrome | MODE_GC16 slow with 16 grayscales +enum EpdDrawMode updateMode = MODE_DU; + #define BUF_MAX 111600 /* Display initialization routine */ @@ -78,7 +81,7 @@ void epdiy_flush(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_ma // Does not work for full screen update yet (Should check large of buf) buf_copy_to_framebuffer(update_area, buf); - epd_hl_update_area(&hl, MODE_GC16, temperature, update_area); //update_area + epd_hl_update_area(&hl, updateMode, temperature, update_area); //update_area printf("epdiy_flush %d x:%d y:%d w:%d h:%d\n", flushcalls,(uint16_t)area->x1,(uint16_t)area->y1,w,h); /* Inform the graphics library that you are ready with the flushing */ @@ -105,7 +108,7 @@ void epdiy_set_px_cb(lv_disp_drv_t * disp_drv, uint8_t* buf, // Test using RGB232 int16_t epd_color = 255; if ((int16_t)color.full<250) { - epd_color = (int16_t)color.full/3; + epd_color = (updateMode==MODE_DU) ? 0 : (int16_t)color.full/3; } //Instead of using epd_draw_pixel: Set pixel directly in *buf that comes afterwards in flush as *color_map diff --git a/lvgl_tft/epdiy_epaper_v1.cpp b/lvgl_tft/epdiy_epaper_v1.cpp index 7b99d63d..38cd948f 100644 --- a/lvgl_tft/epdiy_epaper_v1.cpp +++ b/lvgl_tft/epdiy_epaper_v1.cpp @@ -7,9 +7,12 @@ #include "epd_driver.h" #include "epd_highlevel.h" -/********************* - * DEFINES - *********************/ +/************************************************************************************************** + * 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; From 9a16924501b89f3b3e27965cbddc0c30e11c0de1 Mon Sep 17 00:00:00 2001 From: martinberlin Date: Sun, 13 Jun 2021 14:57:25 +0200 Subject: [PATCH 17/31] Related to commit in https://github.com/martinberlin/lv_port_esp32-epaper/commit/196e4888a0a1af1ea7a7be31f1a2e8dc19d2cbbd --- lvgl_helpers.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lvgl_helpers.h b/lvgl_helpers.h index cae3a259..dae0c350 100644 --- a/lvgl_helpers.h +++ b/lvgl_helpers.h @@ -41,10 +41,10 @@ extern "C" { #elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_ST7735S #define DISP_BUF_SIZE (LV_HOR_RES_MAX * 40) #elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_ST7796S -#define DISP_BUF_SIZE (LV_HOR_RES_MAX * 40) +#define DISP_BUF_SIZE (LV_HOR_RES_MAX * LV_VER_RES_MAX/3) // Here is the issue that it does not draw full epaper. Insufficient buffer: #elif defined (CONFIG_LV_EPAPER_EPDIY_DISPLAY_CONTROLLER) -#define DISP_BUF_SIZE (LV_HOR_RES_MAX * 110) +#define DISP_BUF_SIZE (LV_HOR_RES_MAX * 38) #elif defined (CONFIG_LV_EPAPER_CALEPD_DISPLAY_CONTROLLER) #define DISP_BUF_SIZE (LV_HOR_RES_MAX * 90) From 588b14f02925ea432a0425dfce0064a9db628c28 Mon Sep 17 00:00:00 2001 From: martinberlin Date: Sun, 13 Jun 2021 15:18:48 +0200 Subject: [PATCH 18/31] Leave buf_copy_to_framebuffer as the default method and Gabor method as secondary --- lvgl_tft/epdiy_epaper.cpp | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/lvgl_tft/epdiy_epaper.cpp b/lvgl_tft/epdiy_epaper.cpp index 569781c9..898889b6 100644 --- a/lvgl_tft/epdiy_epaper.cpp +++ b/lvgl_tft/epdiy_epaper.cpp @@ -12,8 +12,8 @@ uint8_t temperature = 25; bool init = true; // MODE_DU: Fast monochrome | MODE_GC16 slow with 16 grayscales enum EpdDrawMode updateMode = MODE_DU; - -#define BUF_MAX 111600 +// Ideally this BUF should be width/2*height = 259200. Now set to 111600 +#define BUF_MAX 110400 /* Display initialization routine */ void epdiy_init(void) @@ -26,6 +26,18 @@ void epdiy_init(void) epd_fullclear(&hl, temperature); } +/* Suggested by @kisvegabor https://forum.lvgl.io/t/lvgl-port-to-be-used-with-epaper-displays/5630/26 */ +void buf_area_to_framebuffer(const lv_area_t *area, const uint8_t *image_data) { + assert(framebuffer != NULL); + uint8_t *fb_ptr = &framebuffer[area->y1 * EPD_WIDTH / 2 + area->x1 / 2]; + lv_coord_t img_w = lv_area_get_width(area); + for(uint32_t y = area->y1; y < area->y2; y++) { + memcpy(fb_ptr, image_data, img_w / 2); + fb_ptr += EPD_WIDTH / 2; + image_data += img_w / 2; + } +} + /* A copy from epd_copy_to_framebuffer with temporary lenght prediction */ void buf_copy_to_framebuffer(EpdRect image_area, const uint8_t *image_data) { assert(framebuffer != NULL); @@ -34,10 +46,10 @@ void buf_copy_to_framebuffer(EpdRect image_area, const uint8_t *image_data) { // Get out if we get the end of the buffer. Question: How to detect the end without a lenght? // Zero terminator check gets out before: (image_data[value_index / 2]== '\0') // 111684 seems to be the last element in image_data - if (i / 2 > BUF_MAX) { + /* if (i / 2 > BUF_MAX) { printf("FOUND END incr:%d Aw:%d Ah:%d\n", i, image_area.width, image_area.height); break; - } + } */ uint8_t val = (i % 2) ? (image_data[i / 2] & 0xF0) >> 4 : image_data[i / 2] & 0x0F; int xx = image_area.x + i % image_area.width; @@ -81,6 +93,9 @@ void epdiy_flush(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_ma // Does not work for full screen update yet (Should check large of buf) buf_copy_to_framebuffer(update_area, buf); + //Faster mode suggested in LVGL forum (Leaves ghosting) + //buf_area_to_framebuffer(area, buf); + epd_hl_update_area(&hl, updateMode, temperature, update_area); //update_area printf("epdiy_flush %d x:%d y:%d w:%d h:%d\n", flushcalls,(uint16_t)area->x1,(uint16_t)area->y1,w,h); @@ -89,8 +104,7 @@ void epdiy_flush(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_ma } /* - * 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 + * Called for each pixel. Designed with the idea to fill the buffer directly, not to set each pixel, see LVGL Forum (buf_area_to_framebuffer) */ 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, From 4650001bdedc898b0cc18eaef332aafe8d4da7e2 Mon Sep 17 00:00:00 2001 From: Martin Fasani Date: Tue, 15 Jun 2021 10:59:32 +0200 Subject: [PATCH 19/31] Rendering correctly in full screen and small updates --- lvgl_helpers.h | 4 ++-- lvgl_tft/epdiy_epaper.cpp | 23 +++-------------------- lvgl_tft/epdiy_epaper.h | 3 +-- 3 files changed, 6 insertions(+), 24 deletions(-) diff --git a/lvgl_helpers.h b/lvgl_helpers.h index dae0c350..7fea4bf7 100644 --- a/lvgl_helpers.h +++ b/lvgl_helpers.h @@ -42,9 +42,9 @@ extern "C" { #define DISP_BUF_SIZE (LV_HOR_RES_MAX * 40) #elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_ST7796S #define DISP_BUF_SIZE (LV_HOR_RES_MAX * LV_VER_RES_MAX/3) -// Here is the issue that it does not draw full epaper. Insufficient buffer: +// 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 * 38) + #define DISP_BUF_SIZE LV_HOR_RES_MAX*(LV_VER_RES_MAX/10) #elif defined (CONFIG_LV_EPAPER_CALEPD_DISPLAY_CONTROLLER) #define DISP_BUF_SIZE (LV_HOR_RES_MAX * 90) diff --git a/lvgl_tft/epdiy_epaper.cpp b/lvgl_tft/epdiy_epaper.cpp index 898889b6..784096a9 100644 --- a/lvgl_tft/epdiy_epaper.cpp +++ b/lvgl_tft/epdiy_epaper.cpp @@ -12,8 +12,6 @@ uint8_t temperature = 25; bool init = true; // MODE_DU: Fast monochrome | MODE_GC16 slow with 16 grayscales enum EpdDrawMode updateMode = MODE_DU; -// Ideally this BUF should be width/2*height = 259200. Now set to 111600 -#define BUF_MAX 110400 /* Display initialization routine */ void epdiy_init(void) @@ -43,13 +41,6 @@ void buf_copy_to_framebuffer(EpdRect image_area, const uint8_t *image_data) { assert(framebuffer != NULL); for (uint32_t i = 0; i < image_area.width * image_area.height; i++) { - // Get out if we get the end of the buffer. Question: How to detect the end without a lenght? - // Zero terminator check gets out before: (image_data[value_index / 2]== '\0') - // 111684 seems to be the last element in image_data - /* if (i / 2 > BUF_MAX) { - printf("FOUND END incr:%d Aw:%d Ah:%d\n", i, image_area.width, image_area.height); - break; - } */ uint8_t val = (i % 2) ? (image_data[i / 2] & 0xF0) >> 4 : image_data[i / 2] & 0x0F; int xx = image_area.x + i % image_area.width; @@ -90,10 +81,11 @@ void epdiy_flush(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_ma printf("%x ", buf[index]); } */ - // Does not work for full screen update yet (Should check large of buf) + // UNCOMMENT only one of this options + // SAFE Option with EPDiy copy of epd_copy_to_framebuffer buf_copy_to_framebuffer(update_area, buf); - //Faster mode suggested in LVGL forum (Leaves ghosting) + //Faster mode suggested in LVGL forum (Leaves ghosting&prints bad sections / experimental) NOTE: Do NOT use in production //buf_area_to_framebuffer(area, buf); epd_hl_update_area(&hl, updateMode, temperature, update_area); //update_area @@ -110,15 +102,6 @@ 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 - if (init) { - printf("Initialize *buf with white\n\n"); - for (int i=0; i Date: Mon, 21 Jun 2021 20:31:31 +0200 Subject: [PATCH 20/31] Update Readme --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 89659a67..60fad2fa 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,10 @@ swap of RGB565 color on the LVGL configuration menuconfig (it's not handled auto | IL3820 | e-Paper | SPI | 1: 1byte per pixel | No | | UC8151D/ GoodDisplay GDEW0154M10 DES | e-Paper | SPI | 1: 1byte per pixel | No | | 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). ## Supported indev controllers From a66706d139a15cd860afb097132f4ac2fcc6b936 Mon Sep 17 00:00:00 2001 From: Martin Fasani Date: Tue, 22 Jun 2021 10:07:38 +0200 Subject: [PATCH 21/31] #1 Cleanup and add L58 as driver in this component --- CMakeLists.txt | 5 +- README.md | 7 +- lvgl_helpers.h | 2 +- lvgl_tft/Kconfig | 11 +- lvgl_tft/calepd_epaper.cpp | 84 ----- lvgl_tft/calepd_epaper.h | 36 -- lvgl_tft/disp_driver.c | 8 +- lvgl_tft/disp_driver.h | 2 - lvgl_tft/{epdiy_epaper.cpp => epdiy_epaper.c} | 0 lvgl_tft/epdiy_epaper_v1.cpp | 92 ----- lvgl_touch/L58/L58Touch.cpp | 316 ++++++++++++++++++ lvgl_touch/L58/include/L58Touch.h | 125 +++++++ 12 files changed, 451 insertions(+), 237 deletions(-) delete mode 100644 lvgl_tft/calepd_epaper.cpp delete mode 100644 lvgl_tft/calepd_epaper.h rename lvgl_tft/{epdiy_epaper.cpp => epdiy_epaper.c} (100%) delete mode 100644 lvgl_tft/epdiy_epaper_v1.cpp create mode 100644 lvgl_touch/L58/L58Touch.cpp create mode 100644 lvgl_touch/L58/include/L58Touch.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 18b78fb0..1cf3c2bc 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 60fad2fa..7f4abadc 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 a7a999e2..b5a3ec0e 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 a8ff5a62..10cda568 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 2de1830a..00000000 --- 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 ea5be619..00000000 --- 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 0acacd64..e70504f3 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 74255f50..28e0f220 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 38cd948f..00000000 --- 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 00000000..cbd733f3 --- /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 00000000..1063a85b --- /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 From 22893f0ae1081ea0ac52b72d3729710751a44eb1 Mon Sep 17 00:00:00 2001 From: martinberlin Date: Wed, 23 Jun 2021 19:05:48 +0200 Subject: [PATCH 22/31] Add a reference to L58 include directory --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3c10f8ea..028726ba 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ if(ESP_PLATFORM) file(GLOB SOURCES *.c) -set(LVGL_INCLUDE_DIRS . lvgl_tft) +set(LVGL_INCLUDE_DIRS . lvgl_tft lvgl_touch/L58/include) list(APPEND SOURCES "lvgl_tft/disp_driver.c") #@todo add SimleInclude macro here From 2868e219fc994b4d3e6e3c112c2626d017f9ea23 Mon Sep 17 00:00:00 2001 From: martinberlin Date: Sun, 2 Jan 2022 12:19:02 +0100 Subject: [PATCH 23/31] #75 Start resolving conflicts (updating component) --- lvgl_helpers.c | 136 ++++----------- lvgl_i2c/Kconfig | 98 +++++++++++ lvgl_i2c/README.md | 90 ++++++++++ lvgl_i2c/i2c_manager.c | 368 +++++++++++++++++++++++++++++++++++++++++ lvgl_i2c/i2c_manager.h | 76 +++++++++ 5 files changed, 661 insertions(+), 107 deletions(-) create mode 100644 lvgl_i2c/Kconfig create mode 100644 lvgl_i2c/README.md create mode 100644 lvgl_i2c/i2c_manager.c create mode 100644 lvgl_i2c/i2c_manager.h diff --git a/lvgl_helpers.c b/lvgl_helpers.c index 3c836fc2..440bb1d3 100644 --- a/lvgl_helpers.c +++ b/lvgl_helpers.c @@ -14,9 +14,8 @@ #include "lvgl_touch/tp_spi.h" #include "lvgl_spi_conf.h" -#include "lvgl_i2c_conf.h" -#include "driver/i2c.h" +#include "lvgl_i2c/i2c_manager.h" #ifdef LV_LVGL_H_INCLUDE_SIMPLE #include "lvgl.h" @@ -68,7 +67,7 @@ void lvgl_driver_init(void) DISP_SPI_MISO, DISP_SPI_MOSI, DISP_SPI_CLK, SPI_BUS_MAX_TRANSFER_SZ, 1, DISP_SPI_IO2, DISP_SPI_IO3); - + disp_spi_add_device(TFT_SPI_HOST); disp_driver_init(); @@ -86,48 +85,29 @@ void lvgl_driver_init(void) TP_SPI_MISO, DISP_SPI_MOSI, DISP_SPI_CLK, SPI_BUS_MAX_TRANSFER_SZ, 1, -1, -1); - + disp_spi_add_device(TFT_SPI_HOST); tp_spi_add_device(TOUCH_SPI_HOST); - - disp_driver_init(); - touch_driver_init(); - return; -#endif - -#if defined (SHARED_I2C_BUS) - ESP_LOGI(TAG, "Initializing shared I2C master"); - - lvgl_i2c_driver_init(DISP_I2C_PORT, - DISP_I2C_SDA, DISP_I2C_SCL, - DISP_I2C_SPEED_HZ); - disp_driver_init(); touch_driver_init(); - + return; #endif /* Display controller initialization */ #if defined CONFIG_LV_TFT_DISPLAY_PROTOCOL_SPI ESP_LOGI(TAG, "Initializing SPI master for display"); - + lvgl_spi_driver_init(TFT_SPI_HOST, DISP_SPI_MISO, DISP_SPI_MOSI, DISP_SPI_CLK, SPI_BUS_MAX_TRANSFER_SZ, 1, DISP_SPI_IO2, DISP_SPI_IO3); - + disp_spi_add_device(TFT_SPI_HOST); - + disp_driver_init(); -#elif defined (CONFIG_LV_TFT_DISPLAY_PROTOCOL_I2C) - ESP_LOGI(TAG, "Initializing I2C master for display"); - /* Init the i2c master on the display driver code */ - lvgl_i2c_driver_init(DISP_I2C_PORT, - DISP_I2C_SDA, DISP_I2C_SCL, - DISP_I2C_SPEED_HZ); - +#elif defined (CONFIG_LV_I2C_DISPLAY) disp_driver_init(); #elif defined (CONFIG_LV_EPAPER_DISPLAY_PROTOCOL_PARALLEL) // Do not initialize SPI. Uses EPDiy @@ -135,77 +115,35 @@ void lvgl_driver_init(void) // Check how not to initialize SPI. disp_driver_init() call is needed: disp_driver_init(); #else - #error "No protocol defined for display controller" +#error "No protocol defined for display controller" #endif /* Touch controller initialization */ #if CONFIG_LV_TOUCH_CONTROLLER != TOUCH_CONTROLLER_NONE #if defined (CONFIG_LV_TOUCH_DRIVER_PROTOCOL_SPI) ESP_LOGI(TAG, "Initializing SPI master for touch"); - + lvgl_spi_driver_init(TOUCH_SPI_HOST, TP_SPI_MISO, TP_SPI_MOSI, TP_SPI_CLK, 0 /* Defaults to 4094 */, 2, -1, -1); - + tp_spi_add_device(TOUCH_SPI_HOST); - + touch_driver_init(); - #elif defined (CONFIG_LV_TOUCH_DRIVER_PROTOCOL_I2C) - ESP_LOGI(TAG, "Initializing I2C master for touch"); - lvgl_i2c_driver_init(TOUCH_I2C_PORT, - TOUCH_I2C_SDA, TOUCH_I2C_SCL, - TOUCH_I2C_SPEED_HZ); - + #elif defined (CONFIG_LV_I2C_TOUCH) touch_driver_init(); #elif defined (CONFIG_LV_TOUCH_DRIVER_ADC) touch_driver_init(); #elif defined (CONFIG_LV_TOUCH_DRIVER_DISPLAY) || defined (CONFIG_LV_TOUCH_CONTROLLER_L58) touch_driver_init(); #else - #error "No protocol defined for touch controller" - + #error "No protocol defined for touch controller" #endif #else #endif } -/* Config the i2c master - * - * This should init the i2c master to be used on display and touch controllers. - * So we should be able to know if the display and touch controllers shares the - * same i2c master. - */ -bool lvgl_i2c_driver_init(int port, int sda_pin, int scl_pin, int speed_hz) -{ - esp_err_t err; - - ESP_LOGI(TAG, "Initializing I2C master port %d...", port); - ESP_LOGI(TAG, "SDA pin: %d, SCL pin: %d, Speed: %d (Hz)", - sda_pin, scl_pin, speed_hz); - - i2c_config_t conf = { - .mode = I2C_MODE_MASTER, - .sda_io_num = sda_pin, - .sda_pullup_en = GPIO_PULLUP_ENABLE, - .scl_io_num = scl_pin, - .scl_pullup_en = GPIO_PULLUP_ENABLE, - .master.clk_speed = speed_hz, - }; - - ESP_LOGI(TAG, "Setting I2C master configuration..."); - err = i2c_param_config(port, &conf); - assert(ESP_OK == err); - - ESP_LOGI(TAG, "Installing I2C master driver..."); - err = i2c_driver_install(port, - I2C_MODE_MASTER, - 0, 0 /*I2C_MASTER_RX_BUF_DISABLE, I2C_MASTER_TX_BUF_DISABLE */, - 0 /* intr_alloc_flags */); - assert(ESP_OK == err); - - return ESP_OK != err; -} /* Initialize spi bus master * @@ -221,34 +159,16 @@ bool lvgl_spi_driver_init(int host, int dma_channel, int quadwp_pin, int quadhd_pin) { - int dma_chan = 0 /* SPI_DMA_DISABLED */; - -#if defined (CONFIG_IDF_TARGET_ESP32) - assert((SPI_HOST <= host) && (VSPI_HOST >= host)); - const char *spi_names[] = { - "SPI_HOST", "HSPI_HOST", "VSPI_HOST" - }; - - dma_chan = dma_channel; -#elif defined (CONFIG_IDF_TARGET_ESP32S2) - assert((SPI_HOST <= host) && (HSPI_HOST >= host)); - const char *spi_names[] = { - "SPI_HOST", "", "" - }; - - dma_chan = dma_channel; -#elif defined (CONFIG_IDF_TARGET_ESP32C3) - assert((SPI1_HOST <= host) && (SPI3_HOST >= host)); + /** + * @brief in idf 4.3 is giving me an error: + * error: 'SPI_HOST_MAX' undeclared + */ + assert((0 <= host) && (SPI_HOST_MAX > host)); const char *spi_names[] = { "SPI1_HOST", "SPI2_HOST", "SPI3_HOST" }; - dma_chan = 3 /* SPI_DMA_CH_AUTO */; -#else -#error "Target chip not selected" -#endif - - ESP_LOGI(TAG, "Configuring SPI host %s (%d)", spi_names[host], host); + ESP_LOGI(TAG, "Configuring SPI host %s", spi_names[host]); ESP_LOGI(TAG, "MISO pin: %d, MOSI pin: %d, SCLK pin: %d, IO2/WP pin: %d, IO3/HD pin: %d", miso_pin, mosi_pin, sclk_pin, quadwp_pin, quadhd_pin); @@ -256,17 +176,19 @@ bool lvgl_spi_driver_init(int host, spi_bus_config_t buscfg = { .miso_io_num = miso_pin, - .mosi_io_num = mosi_pin, - .sclk_io_num = sclk_pin, - .quadwp_io_num = quadwp_pin, - .quadhd_io_num = quadhd_pin, + .mosi_io_num = mosi_pin, + .sclk_io_num = sclk_pin, + .quadwp_io_num = quadwp_pin, + .quadhd_io_num = quadhd_pin, .max_transfer_sz = max_transfer_sz }; ESP_LOGI(TAG, "Initializing SPI bus..."); - esp_err_t ret = spi_bus_initialize(host, &buscfg, dma_chan); + #if defined (CONFIG_IDF_TARGET_ESP32C3) + dma_channel = SPI_DMA_CH_AUTO; + #endif + esp_err_t ret = spi_bus_initialize(host, &buscfg, (spi_dma_chan_t)dma_channel); assert(ret == ESP_OK); return ESP_OK != ret; -} - +} \ No newline at end of file diff --git a/lvgl_i2c/Kconfig b/lvgl_i2c/Kconfig new file mode 100644 index 00000000..48df924e --- /dev/null +++ b/lvgl_i2c/Kconfig @@ -0,0 +1,98 @@ +menu "I2C Port 0" + + config I2C_MANAGER_0_ENABLED + bool "Enable I2C port 0" + + if I2C_MANAGER_0_ENABLED + config I2C_MANAGER_0_SDA + int "SDA (GPIO pin)" + default 0 + config I2C_MANAGER_0_SCL + int "SCL (GPIO pin)" + default 0 + config I2C_MANAGER_0_FREQ_HZ + int "Frequency (Hz)" + default 400000 + range 100000 5000000 + help + The clock speed in Hz. Ranges from 100000 (100 kHz) to + 5000000 (5 Mhz). I2C busses that involve external wires may + have to be slower, and the real maximum speed the bus will + support depends on the value of the pullup resistors and the + design of the overall circuit. + config I2C_MANAGER_0_TIMEOUT + int "R/W timeout (ms)" + default 20 + range 10 1000 + help + Timeout for I2C read and write operations. This does not + include the time waiting for a lock. + config I2C_MANAGER_0_LOCK_TIMEOUT + int "Stale lock override (ms)" + default 50 + range 10 1000 + help + Timeout at which point an operation waiting for its turn on + the port will assume that whatever set the lock has died and + overrides it. Set this somewhat larger than the previous + timeout. + config I2C_MANAGER_0_PULLUPS + bool "Use ESP32 built-in bus pull-up resistors" + help + The I2C bus needs resistors to make sure it's in a defined + state when nobody is talking. Many circuits have external + pullup resistors already and turning these on will increase + power consumption slightly and may limit the speed your bus + can attain. Try with these off first if you don't know. + endif + +endmenu + + +menu "I2C Port 1" + + config I2C_MANAGER_1_ENABLED + bool "Enable I2C port 1" + + if I2C_MANAGER_1_ENABLED + config I2C_MANAGER_1_SDA + int "SDA (GPIO pin)" + config I2C_MANAGER_1_SCL + int "SCL (GPIO pin)" + config I2C_MANAGER_1_FREQ_HZ + int "Frequency (Hz)" + default 1000000 + range 100000 5000000 + help + The clock speed in Hz. Ranges from 100000 (100 kHz) to + 5000000 (5 Mhz). I2C busses that involve external wires may + have to be slower, and the real maximum speed the bus will + support depends on the value of the pullup resistors and the + design of the overall circuit. + config I2C_MANAGER_1_TIMEOUT + int "R/W timeout (ms)" + default 20 + range 10 1000 + help + Timeout for I2C read and write operations. This does not + include the time waiting for a lock. Default should be fine. + config I2C_MANAGER_1_LOCK_TIMEOUT + int "Stale lock override (ms)" + default 50 + help + Timeout at which point an operation waiting for its turn on + the port will assume that whatever set the lock has died and + overrides it. Set this somewhat larger than the previous + timeout. Default should be fine. + range 30 1000 + config I2C_MANAGER_1_PULLUPS + bool "Use ESP32 built-in bus pull-up resistors" + help + The I2C bus needs resistors to make sure it's in a defined + state when nobody is talking. Many circuits have external + pullup resistors already and turning these on will increase + power consumption slightly and may limit the speed your bus + can attain. Try with these off first if you don't know. + endif + +endmenu diff --git a/lvgl_i2c/README.md b/lvgl_i2c/README.md new file mode 100644 index 00000000..90f37289 --- /dev/null +++ b/lvgl_i2c/README.md @@ -0,0 +1,90 @@ +# I2C in `lvgl_esp32_drivers` + + +  + + +## Information for users + +### I2C Manager support + +`lvgl_esp32_drivers` integrates [I2C Manager](https://github.com/ropg/i2c_manager), which is used in case you select a touch sensor or screen that uses the I2C bus. + +I2C Manager is also available as a separate ESP-IDF component and can help if you are in a situation where you want to avoid "bus conflicts" on the I2C bus. **If in your application nothing outside of LVGL needs to talk to the I2C bus, you can stop reading here.** + +Suppose you use LVGL with a touch sensor that uses I2C, and your device also has another I2C device that needs to be read frequently, such as a 3D-accelerometer. ESP-IDF is not inherently "thread-safe". So if you read that from another task than the one LVGL uses to read the touch data, you need some kind of mechanism to keep these communications from interfering. + +If you have (or write) a driver for that 3D-accelerometer that can use I2C Manager (or the I2C HAL and i2cdev abstraction layers that I2C Manager is compatible with) then put I2C Manager in your components directory by cloning the repository from below and in your main program do: + +```c +#include "i2c_manager.h" +#include "lvgl_helpers.h" + +[...] + +lvgl_i2c_locking(i2c_manager_locking()); +lv_init(); +lvgl_driver_init(); +``` + +The `lvgl_i2c_locking` part will cause the LVGL I2C driver to play nice with anything else that uses the I2C port(s) through I2C Manager. + + +  + + +## Information for LVGL driver developers + +I2C support in the LVGL ESP drivers is provided exclusively by the files in this directory. Driver code that uses I2C communicates through the functions provided in `i2c_manager.h`. + + +  + + +### Using I2C in an LVGL driver, a multi-step guide + +
+ +
Step 1
+ +
+The Kconfig entries for your driver only need to specify that you will be using I2C. This is done by adding `select LV_I2C_DISPLAY` or `select LV_I2C_TOUCH`. +
+ + +
Step 2
+ +
+To use the I2C port in your code you would do something like: + + +```c +#include "lvgl_i2c/i2c_manager.h" + +uint8_t data[2]; +lvgl_i2c_read(CONFIG_LV_I2C_TOUCH_PORT, 0x23, 0x42, &data, 2); +``` + +This causes a touch driver to read two bytes at register `0x42` from the IC at address `0x23`. Replace `CONFIG_LV_I2C_TOUCH_PORT` by `CONFIG_LV_I2C_DISPLAY_PORT` when this is a display instead of a touch driver. `lvgl_i2c_write` works much the same way, except it writes the bytes from the buffer instead of reading them. _(It's ignored above but these functions return `esp_err_t` so you can check if the I2C communication worked.)_ +
+ +
Step 3
+ +
+There is no step 3, you are already done. +
+ +
+ + +### Meanwhile, behind the scenes ... + +If any of the drivers selected by the user uses I2C, the menuconfig system will show an extra menu to select I2C port(s) for screen and/or touch sensor. An additional menu allows for setting of GPIO pins and bus speed of any port selected for use with LVGL. It's perfectly fine for a display and a touch sensor to be on the same I2C port or different ones. + + +  + + +## More information + +If you need more documentation, please refer to the [I2C Manager GitHub repository](https://github.com/ropg/i2c_manager) for more detailed information on how I2C manager works. There are features not in the simple example above, such as reads and writes without specifying a register, 16-bit registers, 10-bit I2C addressing and more. diff --git a/lvgl_i2c/i2c_manager.c b/lvgl_i2c/i2c_manager.c new file mode 100644 index 00000000..080d81a7 --- /dev/null +++ b/lvgl_i2c/i2c_manager.c @@ -0,0 +1,368 @@ +/* + +SPDX-License-Identifier: MIT + +MIT License + +Copyright (c) 2021 Rop Gonggrijp. Based on esp_i2c_helper by Mika Tuupola. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#include +#include + +#include + +#include "freertos/FreeRTOS.h" +#include "freertos/semphr.h" +#include "freertos/task.h" +#include + +#include "sdkconfig.h" + +#include "i2c_manager.h" + + +#if defined __has_include + #if __has_include ("esp_idf_version.h") + #include "esp_idf_version.h" + #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 3, 0) + #define HAS_CLK_FLAGS + #endif + #endif +#endif + + +static const char* TAG = I2C_TAG; + +static SemaphoreHandle_t I2C_FN(_local_mutex)[2] = { NULL, NULL }; +static SemaphoreHandle_t* I2C_FN(_mutex) = &I2C_FN(_local_mutex)[0]; + +static const uint8_t ACK_CHECK_EN = 1; + +#if defined (I2C_NUM_0) && defined (CONFIG_I2C_MANAGER_0_ENABLED) + #define I2C_ZERO I2C_NUM_0 + #if defined (CONFIG_I2C_MANAGER_0_PULLUPS) + #define I2C_MANAGER_0_PULLUPS true + #else + #define I2C_MANAGER_0_PULLUPS false + #endif + + #define I2C_MANAGER_0_TIMEOUT ( CONFIG_I2C_MANAGER_0_TIMEOUT / portTICK_RATE_MS ) + #define I2C_MANAGER_0_LOCK_TIMEOUT ( CONFIG_I2C_MANAGER_0_LOCK_TIMEOUT / portTICK_RATE_MS ) +#endif + + +#if defined (I2C_NUM_1) && defined (CONFIG_I2C_MANAGER_1_ENABLED) + #define I2C_ONE I2C_NUM_1 + #if defined (CONFIG_I2C_MANAGER_1_PULLUPS) + #define I2C_MANAGER_1_PULLUPS true + #else + #define I2C_MANAGER_1_PULLUPS false + #endif + + #define I2C_MANAGER_1_TIMEOUT ( CONFIG_I2C_MANAGER_1_TIMEOUT / portTICK_RATE_MS ) + #define I2C_MANAGER_1_LOCK_TIMEOUT ( CONFIG_I2C_MANAGER_1_LOCK_TIMEOUT / portTICK_RATE_MS ) +#endif + +#define ERROR_PORT(port, fail) { \ + ESP_LOGE(TAG, "Invalid port or not configured for I2C Manager: %d", (int)port); \ + return fail; \ +} + +#if defined(I2C_ZERO) && defined (I2C_ONE) + #define I2C_PORT_CHECK(port, fail) \ + if (port != I2C_NUM_0 && port != I2C_NUM_1) ERROR_PORT(port, fail); +#else + #if defined(I2C_ZERO) + #define I2C_PORT_CHECK(port, fail) \ + if (port != I2C_NUM_0) ERROR_PORT(port, fail); + #elif defined(I2C_ONE) + #define I2C_PORT_CHECK(port, fail) \ + if (port != I2C_NUM_1) ERROR_PORT(port, fail); + #else + #define I2C_PORT_CHECK(port, fail) \ + ERROR_PORT(port, fail); + #endif +#endif + +static void i2c_send_address(i2c_cmd_handle_t cmd, uint16_t addr, i2c_rw_t rw) { + if (addr & I2C_ADDR_10) { + i2c_master_write_byte(cmd, 0xF0 | ((addr & 0x3FF) >> 7) | rw, ACK_CHECK_EN); + i2c_master_write_byte(cmd, addr & 0xFF, ACK_CHECK_EN); + } else { + i2c_master_write_byte(cmd, (addr << 1) | rw, ACK_CHECK_EN); + } +} + +static void i2c_send_register(i2c_cmd_handle_t cmd, uint32_t reg) { + if (reg & I2C_REG_16) { + i2c_master_write_byte(cmd, (reg & 0xFF00) >> 8, ACK_CHECK_EN); + } + i2c_master_write_byte(cmd, reg & 0xFF, ACK_CHECK_EN); +} + +esp_err_t I2C_FN(_init)(i2c_port_t port) { + + I2C_PORT_CHECK(port, ESP_FAIL); + + esp_err_t ret = ESP_OK; + + if (I2C_FN(_mutex)[port] == 0) { + + ESP_LOGI(TAG, "Starting I2C master at port %d.", (int)port); + + I2C_FN(_mutex)[port] = xSemaphoreCreateMutex(); + + i2c_config_t conf = {0}; + + #ifdef HAS_CLK_FLAGS + conf.clk_flags = 0; + #endif + + #if defined (I2C_ZERO) + if (port == I2C_NUM_0) { + conf.sda_io_num = CONFIG_I2C_MANAGER_0_SDA; + conf.scl_io_num = CONFIG_I2C_MANAGER_0_SCL; + conf.sda_pullup_en = I2C_MANAGER_0_PULLUPS ? GPIO_PULLUP_ENABLE : GPIO_PULLUP_DISABLE; + conf.scl_pullup_en = conf.sda_pullup_en; + conf.master.clk_speed = CONFIG_I2C_MANAGER_0_FREQ_HZ; + } + #endif + + #if defined (I2C_ONE) + if (port == I2C_NUM_1) { + conf.sda_io_num = CONFIG_I2C_MANAGER_1_SDA; + conf.scl_io_num = CONFIG_I2C_MANAGER_1_SCL; + conf.sda_pullup_en = I2C_MANAGER_1_PULLUPS ? GPIO_PULLUP_ENABLE : GPIO_PULLUP_DISABLE; + conf.scl_pullup_en = conf.sda_pullup_en; + conf.master.clk_speed = CONFIG_I2C_MANAGER_1_FREQ_HZ; + } + #endif + + conf.mode = I2C_MODE_MASTER; + + ret = i2c_param_config(port, &conf); + ret |= i2c_driver_install(port, conf.mode, 0, 0, 0); + + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Failed to initialise I2C port %d.", (int)port); + ESP_LOGW(TAG, "If it was already open, we'll use it with whatever settings were used " + "to open it. See I2C Manager README for details."); + } else { + ESP_LOGI(TAG, "Initialised port %d (SDA: %d, SCL: %d, speed: %d Hz.)", + port, conf.sda_io_num, conf.scl_io_num, conf.master.clk_speed); + } + + } + + return ret; +} + +esp_err_t I2C_FN(_read)(i2c_port_t port, uint16_t addr, uint32_t reg, uint8_t *buffer, uint16_t size) { + + I2C_PORT_CHECK(port, ESP_FAIL); + + esp_err_t result; + + // May seem weird, but init starts with a check if it's needed, no need for that check twice. + I2C_FN(_init)(port); + + ESP_LOGV(TAG, "Reading port %d, addr 0x%03x, reg 0x%04x", port, addr, reg); + + TickType_t timeout = 0; + #if defined (I2C_ZERO) + if (port == I2C_NUM_0) { + timeout = I2C_MANAGER_0_TIMEOUT; + } + #endif + #if defined (I2C_ONE) + if (port == I2C_NUM_1) { + timeout = I2C_MANAGER_1_TIMEOUT; + } + #endif + + if (I2C_FN(_lock)((int)port) == ESP_OK) { + i2c_cmd_handle_t cmd = i2c_cmd_link_create(); + if (!(reg & I2C_NO_REG)) { + /* When reading specific register set the addr pointer first. */ + i2c_master_start(cmd); + i2c_send_address(cmd, addr, I2C_MASTER_WRITE); + i2c_send_register(cmd, reg); + } + /* Read size bytes from the current pointer. */ + i2c_master_start(cmd); + i2c_send_address(cmd, addr, I2C_MASTER_READ); + i2c_master_read(cmd, buffer, size, I2C_MASTER_LAST_NACK); + i2c_master_stop(cmd); + result = i2c_master_cmd_begin(port, cmd, timeout); + i2c_cmd_link_delete(cmd); + I2C_FN(_unlock)((int)port); + } else { + ESP_LOGE(TAG, "Lock could not be obtained for port %d.", (int)port); + return ESP_ERR_TIMEOUT; + } + + if (result != ESP_OK) { + ESP_LOGW(TAG, "Error: %d", result); + } + + ESP_LOG_BUFFER_HEX_LEVEL(TAG, buffer, size, ESP_LOG_VERBOSE); + + return result; +} + +esp_err_t I2C_FN(_write)(i2c_port_t port, uint16_t addr, uint32_t reg, const uint8_t *buffer, uint16_t size) { + + I2C_PORT_CHECK(port, ESP_FAIL); + + esp_err_t result; + + // May seem weird, but init starts with a check if it's needed, no need for that check twice. + I2C_FN(_init)(port); + + ESP_LOGV(TAG, "Writing port %d, addr 0x%03x, reg 0x%04x", port, addr, reg); + + TickType_t timeout = 0; + #if defined (I2C_ZERO) + if (port == I2C_NUM_0) { + timeout = (CONFIG_I2C_MANAGER_0_TIMEOUT) / portTICK_RATE_MS; + } + #endif + #if defined (I2C_ONE) + if (port == I2C_NUM_1) { + timeout = (CONFIG_I2C_MANAGER_1_TIMEOUT) / portTICK_RATE_MS; + } + #endif + + if (I2C_FN(_lock)((int)port) == ESP_OK) { + i2c_cmd_handle_t cmd = i2c_cmd_link_create(); + i2c_master_start(cmd); + i2c_send_address(cmd, addr, I2C_MASTER_WRITE); + if (!(reg & I2C_NO_REG)) { + i2c_send_register(cmd, reg); + } + i2c_master_write(cmd, (uint8_t *)buffer, size, ACK_CHECK_EN); + i2c_master_stop(cmd); + result = i2c_master_cmd_begin( port, cmd, timeout); + i2c_cmd_link_delete(cmd); + I2C_FN(_unlock)((int)port); + } else { + ESP_LOGE(TAG, "Lock could not be obtained for port %d.", (int)port); + return ESP_ERR_TIMEOUT; + } + + if (result != ESP_OK) { + ESP_LOGW(TAG, "Error: %d", result); + } + + ESP_LOG_BUFFER_HEX_LEVEL(TAG, buffer, size, ESP_LOG_VERBOSE); + + return result; +} + +esp_err_t I2C_FN(_close)(i2c_port_t port) { + I2C_PORT_CHECK(port, ESP_FAIL); + vSemaphoreDelete(I2C_FN(_mutex)[port]); + I2C_FN(_mutex)[port] = NULL; + ESP_LOGI(TAG, "Closing I2C master at port %d", port); + return i2c_driver_delete(port); +} + +esp_err_t I2C_FN(_lock)(i2c_port_t port) { + I2C_PORT_CHECK(port, ESP_FAIL); + ESP_LOGV(TAG, "Mutex lock set for %d.", (int)port); + + TickType_t timeout; + #if defined (I2C_ZERO) + if (port == I2C_NUM_0) { + timeout = (CONFIG_I2C_MANAGER_0_LOCK_TIMEOUT) / portTICK_RATE_MS; + } + #endif + #if defined (I2C_ONE) + if (port == I2C_NUM_1) { + timeout = (CONFIG_I2C_MANAGER_1_LOCK_TIMEOUT) / portTICK_RATE_MS; + } + #endif + + if (xSemaphoreTake(I2C_FN(_mutex)[port], timeout) == pdTRUE) { + return ESP_OK; + } else { + ESP_LOGE(TAG, "Removing stale mutex lock from port %d.", (int)port); + I2C_FN(_force_unlock)(port); + return (xSemaphoreTake(I2C_FN(_mutex)[port], timeout) == pdTRUE ? ESP_OK : ESP_FAIL); + } +} + +esp_err_t I2C_FN(_unlock)(i2c_port_t port) { + I2C_PORT_CHECK(port, ESP_FAIL); + ESP_LOGV(TAG, "Mutex lock removed for %d.", (int)port); + return (xSemaphoreGive(I2C_FN(_mutex)[port]) == pdTRUE) ? ESP_OK : ESP_FAIL; +} + +esp_err_t I2C_FN(_force_unlock)(i2c_port_t port) { + I2C_PORT_CHECK(port, ESP_FAIL); + if (I2C_FN(_mutex)[port]) { + vSemaphoreDelete(I2C_FN(_mutex)[port]); + } + I2C_FN(_mutex)[port] = xSemaphoreCreateMutex(); + return ESP_OK; +} + + + +#ifdef I2C_OEM + + void I2C_FN(_locking)(void* leader) { + if (leader) { + ESP_LOGI(TAG, "Now following I2C Manager for locking"); + I2C_FN(_mutex) = (SemaphoreHandle_t*)leader; + } + } + +#else + + void* i2c_manager_locking() { + return (void*)i2c_manager_mutex; + } + + int32_t i2c_hal_read(void *handle, uint8_t address, uint8_t reg, uint8_t *buffer, uint16_t size) { + return i2c_manager_read(*(i2c_port_t*)handle, address, reg, buffer, size); + } + + int32_t i2c_hal_write(void *handle, uint8_t address, uint8_t reg, const uint8_t *buffer, uint16_t size) { + return i2c_manager_write(*(i2c_port_t*)handle, address, reg, buffer, size); + } + + static i2c_port_t port_zero = (i2c_port_t)0; + static i2c_port_t port_one = (i2c_port_t)1; + + static i2c_hal_t _i2c_hal[2] = { + {&i2c_hal_read, &i2c_hal_write, &port_zero}, + {&i2c_hal_read, &i2c_hal_write, &port_one} + }; + + void* i2c_hal(i2c_port_t port) { + I2C_PORT_CHECK(port, NULL); + return (void*)&_i2c_hal[port]; + } + +#endif diff --git a/lvgl_i2c/i2c_manager.h b/lvgl_i2c/i2c_manager.h new file mode 100644 index 00000000..f9ce5850 --- /dev/null +++ b/lvgl_i2c/i2c_manager.h @@ -0,0 +1,76 @@ +#ifndef _I2C_MANAGER_H +#define _I2C_MANAGER_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/* + + If you copy the i2c_manager files to your own component instead of + depending on i2c_manager, you MUST uncomment the define below + and put in some short string that identifies your component (such + as 'xyz'). This will cause i2c_manager to create functions named + xyz_i2c_* instead of i2c_manager_*. See README.md for details. + +*/ + +#define I2C_OEM lvgl + + +// Only here to get the I2C_NUM_0 and I2C_NUM_1 defines. +#include + +#define CONCATX(A, B) A ## B +#define CONCAT(A, B) CONCATX(A, B) +#define STR_LITERAL(s) # s +#define STR_EXPAND(s) STR_LITERAL(s) +#define STR_QUOTE(s) STR_EXPAND(STR_EXPAND(s)) + +#ifdef I2C_OEM + #define I2C_NAME_PREFIX CONCAT(I2C_OEM, _i2c) +#else + #define I2C_NAME_PREFIX i2c_manager +#endif +#define I2C_TAG STR_EXPAND(I2C_NAME_PREFIX) + +#define I2C_FN(s) CONCAT(I2C_NAME_PREFIX, s) + + +#define I2C_ADDR_10 ( 1 << 15 ) +#define I2C_REG_16 ( 1 << 31 ) +#define I2C_NO_REG ( 1 << 30 ) + +esp_err_t I2C_FN(_init)(i2c_port_t port); +esp_err_t I2C_FN(_read)(i2c_port_t port, uint16_t addr, uint32_t reg, uint8_t *buffer, uint16_t size); +esp_err_t I2C_FN(_write)(i2c_port_t port, uint16_t addr, uint32_t reg, const uint8_t *buffer, uint16_t size); +esp_err_t I2C_FN(_close)(i2c_port_t port); +esp_err_t I2C_FN(_lock)(i2c_port_t port); +esp_err_t I2C_FN(_unlock)(i2c_port_t port); +esp_err_t I2C_FN(_force_unlock)(i2c_port_t port); + + +#ifdef I2C_OEM + + void I2C_FN(_locking)(void* leader); + +#else + + void* i2c_manager_locking(); + + typedef struct { + int32_t (* read)(void *handle, uint8_t address, uint8_t reg, uint8_t *buffer, uint16_t size); + int32_t (* write)(void *handle, uint8_t address, uint8_t reg, const uint8_t *buffer, uint16_t size); + void *handle; + } i2c_hal_t; + + void* i2c_hal(i2c_port_t port); + +#endif + + +#ifdef __cplusplus +} +#endif +#endif From 63bc5f4cf7cf773a2a29dfa256daf008a313fdcc Mon Sep 17 00:00:00 2001 From: martinberlin Date: Sun, 2 Jan 2022 12:28:43 +0100 Subject: [PATCH 24/31] #75 Update lvgl_tft --- lvgl_tft/disp_driver.c | 35 ++++++++++++++++++++++++++++++++++- lvgl_tft/disp_driver.h | 4 +++- 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/lvgl_tft/disp_driver.c b/lvgl_tft/disp_driver.c index e70504f3..b2e85830 100644 --- a/lvgl_tft/disp_driver.c +++ b/lvgl_tft/disp_driver.c @@ -6,7 +6,7 @@ #include "disp_spi.h" -void disp_driver_init(void) +void *disp_driver_init(void) { #if defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_ILI9341 ili9341_init(); @@ -44,6 +44,33 @@ void disp_driver_init(void) uc8151d_init(); #elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_ILI9163C ili9163c_init(); +#elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_PCD8544 + pcd8544_init(); +#endif + + // We still use menuconfig for these settings + // It will be set up during runtime in the future +#if (defined(CONFIG_LV_DISP_BACKLIGHT_SWITCH) || defined(CONFIG_LV_DISP_BACKLIGHT_PWM)) + const disp_backlight_config_t bckl_config = { + .gpio_num = CONFIG_LV_DISP_PIN_BCKL, +#if defined CONFIG_LV_DISP_BACKLIGHT_PWM + .pwm_control = true, +#else + .pwm_control = false, +#endif +#if defined CONFIG_LV_BACKLIGHT_ACTIVE_LVL + .output_invert = false, // Backlight on high +#else + .output_invert = true, // Backlight on low +#endif + .timer_idx = 0, + .channel_idx = 0 // @todo this prevents us from having two PWM controlled displays + }; + disp_backlight_h bckl_handle = disp_backlight_new(&bckl_config); + disp_backlight_set(bckl_handle, 100); + return bckl_handle; +#else + return NULL; #endif } @@ -85,6 +112,8 @@ void disp_driver_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * uc8151d_lv_fb_flush(drv, area, color_map); #elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_ILI9163C ili9163c_flush(drv, area, color_map); +#elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_PCD8544 + pcd8544_flush(drv, area, color_map); #endif } @@ -101,6 +130,8 @@ void disp_driver_rounder(lv_disp_drv_t * disp_drv, lv_area_t * area) jd79653a_lv_rounder_cb(disp_drv, area); #elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_UC8151D uc8151d_lv_rounder_cb(disp_drv, area); +#elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_PCD8544 + pcd8544_rounder(disp_drv, area); #endif } @@ -119,5 +150,7 @@ void disp_driver_set_px(lv_disp_drv_t * disp_drv, uint8_t * buf, lv_coord_t buf_ jd79653a_lv_set_fb_cb(disp_drv, buf, buf_w, x, y, color, opa); #elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_UC8151D uc8151d_lv_set_fb_cb(disp_drv, buf, buf_w, x, y, color, opa); +#elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_PCD8544 + pcd8544_set_px_cb(disp_drv, buf, buf_w, x, y, color, opa); #endif } diff --git a/lvgl_tft/disp_driver.h b/lvgl_tft/disp_driver.h index 28e0f220..1970e423 100644 --- a/lvgl_tft/disp_driver.h +++ b/lvgl_tft/disp_driver.h @@ -54,6 +54,8 @@ extern "C" { #include "uc8151d.h" #elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_ILI9163C #include "ili9163c.h" +#elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_PCD8544 +#include "pcd8544.h" #endif /********************* @@ -69,7 +71,7 @@ extern "C" { **********************/ /* Initialize display */ -void disp_driver_init(void); +void *disp_driver_init(void); /* Display flush callback */ void disp_driver_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * color_map); From d738aaa84f12b4229d136652dd559409b3cb1046 Mon Sep 17 00:00:00 2001 From: martinberlin Date: Sun, 2 Jan 2022 13:04:46 +0100 Subject: [PATCH 25/31] #75 update I2C references since lvgl_i2c_conf.h is not used --- lvgl_touch/l58.cpp | 1 - lvgl_touch/touch_driver.c | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/lvgl_touch/l58.cpp b/lvgl_touch/l58.cpp index de4329d8..62ac1d67 100644 --- a/lvgl_touch/l58.cpp +++ b/lvgl_touch/l58.cpp @@ -25,7 +25,6 @@ #include #endif #include "l58.h" -#include "../lvgl_i2c_conf.h" // Cale touch implementation #include "L58Touch.h" L58Touch Touch(CONFIG_LV_TOUCH_INT); diff --git a/lvgl_touch/touch_driver.c b/lvgl_touch/touch_driver.c index 74966474..a59ac6bc 100644 --- a/lvgl_touch/touch_driver.c +++ b/lvgl_touch/touch_driver.c @@ -4,7 +4,7 @@ #include "touch_driver.h" #include "tp_spi.h" -#include "tp_i2c.h" + // Is not being included in CMakeLists.txt (Research why) #include "l58.h" From 87bf29d6762f526221b98c3cf9bbfd95a8674a31 Mon Sep 17 00:00:00 2001 From: martinberlin Date: Thu, 24 Aug 2023 12:45:30 +0200 Subject: [PATCH 26/31] Update with epdiy last version support --- CMakeLists.txt | 31 ++-- Kconfig | 16 +- README.md | 40 +---- component.mk | 6 +- lvgl_helpers.c | 146 ++++++++++----- lvgl_helpers.h | 20 +-- lvgl_i2c_conf.h | 116 ++++++++++++ lvgl_spi_conf.h | 31 ++-- lvgl_tft/EVE_commands.c | 6 +- lvgl_tft/EVE_commands.h | 6 +- lvgl_tft/EVE_config.h | 11 +- lvgl_tft/FT81x.c | 14 +- lvgl_tft/GC9A01.c | 47 ++++- lvgl_tft/GC9A01.h | 16 +- lvgl_tft/Kconfig | 333 ++++++++++++++++++----------------- lvgl_tft/calepd_epaper.cpp | 95 ++++++++++ lvgl_tft/calepd_epaper.h | 38 ++++ lvgl_tft/disp_driver.c | 62 ++----- lvgl_tft/disp_driver.h | 11 +- lvgl_tft/disp_spi.c | 5 - lvgl_tft/epdiy_epaper.cpp | 125 +++++++++++++ lvgl_tft/epdiy_epaper_v1.cpp | 92 ++++++++++ lvgl_tft/hx8357.c | 31 +++- lvgl_tft/hx8357.h | 17 +- lvgl_tft/il3820.c | 58 +++--- lvgl_tft/il3820.h | 1 - lvgl_tft/ili9341.c | 46 ++++- lvgl_tft/ili9341.h | 19 +- lvgl_tft/ili9481.c | 26 ++- lvgl_tft/ili9481.h | 16 +- lvgl_tft/ili9486.c | 48 ++++- lvgl_tft/ili9486.h | 14 +- lvgl_tft/ili9488.c | 38 +++- lvgl_tft/ili9488.h | 15 +- lvgl_tft/ra8875.c | 39 +++- lvgl_tft/ra8875.h | 4 +- lvgl_tft/sh1107.c | 3 - lvgl_tft/sh1107.h | 5 +- lvgl_tft/sharp_mip.cpp | 110 ++++++++++++ lvgl_tft/sharp_mip.h | 35 ++++ lvgl_tft/ssd1306.c | 43 ++++- lvgl_tft/ssd1306.h | 2 + lvgl_tft/st7735s.c | 98 ++++++----- lvgl_tft/st7735s.h | 9 +- lvgl_tft/st7789.c | 75 ++++---- lvgl_tft/st7789.h | 18 +- lvgl_tft/st7796s.c | 35 +++- lvgl_tft/st7796s.h | 16 +- lvgl_touch/Kconfig | 236 ++++++++++++------------- lvgl_touch/ft6x36.c | 217 ++++++++++++++--------- lvgl_touch/ft6x36.h | 36 ++-- lvgl_touch/l58.cpp | 1 + lvgl_touch/touch_driver.c | 15 +- lvgl_touch/touch_driver.h | 7 - lvgl_touch/tp_i2c.c | 43 +++++ lvgl_touch/tp_i2c.h | 36 ++++ 56 files changed, 1832 insertions(+), 847 deletions(-) create mode 100644 lvgl_i2c_conf.h create mode 100644 lvgl_tft/calepd_epaper.cpp create mode 100644 lvgl_tft/calepd_epaper.h create mode 100644 lvgl_tft/epdiy_epaper.cpp create mode 100644 lvgl_tft/epdiy_epaper_v1.cpp create mode 100644 lvgl_tft/sharp_mip.cpp create mode 100644 lvgl_tft/sharp_mip.h create mode 100644 lvgl_touch/tp_i2c.c create mode 100644 lvgl_touch/tp_i2c.h diff --git a/CMakeLists.txt b/CMakeLists.txt index a842e936..6b3942dd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,16 +1,22 @@ if(ESP_PLATFORM) file(GLOB SOURCES *.c) -set(LVGL_INCLUDE_DIRS . lvgl_tft lvgl_touch/L58/include) +set(LVGL_INCLUDE_DIRS . lvgl_tft) list(APPEND SOURCES "lvgl_tft/disp_driver.c") -list(APPEND SOURCES "lvgl_tft/esp_lcd_backlight.c") + +#@todo add SimleInclude macro here # Include only the source file of the selected # display controller. 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.c") + list(APPEND SOURCES "lvgl_tft/epdiy_epaper.cpp") +elseif(CONFIG_LV_EPAPER_CALEPD_DISPLAY_CONTROLLER) + list(APPEND SOURCES "lvgl_tft/calepd_epaper.cpp") +elseif(CONFIG_LV_SHARP_DISPLAY_CONTROLLER) + list(APPEND SOURCES "lvgl_tft/sharp_mip.cpp") + elseif(CONFIG_LV_TFT_DISPLAY_CONTROLLER_ILI9481) list(APPEND SOURCES "lvgl_tft/ili9481.c") elseif(CONFIG_LV_TFT_DISPLAY_CONTROLLER_ILI9486) @@ -42,10 +48,6 @@ elseif(CONFIG_LV_TFT_DISPLAY_CONTROLLER_RA8875) list(APPEND SOURCES "lvgl_tft/ra8875.c") elseif(CONFIG_LV_TFT_DISPLAY_CONTROLLER_GC9A01) list(APPEND SOURCES "lvgl_tft/GC9A01.c") -elseif(CONFIG_LV_TFT_DISPLAY_CONTROLLER_ILI9163C) - list(APPEND SOURCES "lvgl_tft/ili9163c.c") -elseif(CONFIG_LV_TFT_DISPLAY_CONTROLLER_PCD8544) - list(APPEND SOURCES "lvgl_tft/pcd8544.c") else() message(WARNING "LVGL ESP32 drivers: Display controller not defined.") endif() @@ -66,7 +68,6 @@ 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") @@ -76,23 +77,21 @@ if(CONFIG_LV_TOUCH_CONTROLLER) list(APPEND SOURCES "lvgl_touch/FT81x.c") elseif(CONFIG_LV_TOUCH_CONTROLLER_RA8875) list(APPEND SOURCES "lvgl_touch/ra8875_touch.c") - elseif(CONFIG_LV_TOUCH_CONTROLLER_GT911) - list(APPEND SOURCES "lvgl_touch/gt911.c") endif() if(CONFIG_LV_TOUCH_DRIVER_PROTOCOL_SPI) list(APPEND SOURCES "lvgl_touch/tp_spi.c") + elseif(CONFIG_LV_TOUCH_DRIVER_PROTOCOL_I2C) + list(APPEND SOURCES "lvgl_touch/tp_i2c.c") endif() endif() -if(CONFIG_LV_I2C) - list(APPEND SOURCES "lvgl_i2c/i2c_manager.c") -endif() - idf_component_register(SRCS ${SOURCES} INCLUDE_DIRS ${LVGL_INCLUDE_DIRS} - REQUIRES lvgl) - + REQUIRES epdiy + lvgl CalEPD sharp-lcd + ) + target_compile_definitions(${COMPONENT_LIB} PUBLIC "-DLV_LVGL_H_INCLUDE_SIMPLE") else() diff --git a/Kconfig b/Kconfig index 36b45268..ae11925e 100644 --- a/Kconfig +++ b/Kconfig @@ -1,14 +1,2 @@ -menu "LVGL ESP Drivers" - - rsource "lvgl_tft/Kconfig" - - rsource "lvgl_touch/Kconfig" - -endmenu - -menu "I2C Port Settings" - depends on LV_I2C && !HAVE_I2C_MANAGER - - rsource "lvgl_i2c/Kconfig" - -endmenu +rsource "lvgl_tft/Kconfig" +rsource "lvgl_touch/Kconfig" diff --git a/README.md b/README.md index 11a8ce02..6aeec919 100644 --- a/README.md +++ b/README.md @@ -6,8 +6,6 @@ For a ready to use ESP32 project take look at the [lv_port_esp32](https://github - [Supported display controllers](#supported-display-controllers) - [Supported indev controllers](#supported-indev-controllers) - [Support for predefined development kits](#support-for-predefined-development-kits) -- [Thread-safe I2C with I2C Manager](#thread-safe-i2c-with-i2c-manager) -- [Backlight control](#backlight-control) **NOTE:** You need to set the display horizontal and vertical size, color depth and swap of RGB565 color on the LVGL configuration menuconfig (it's not handled automatically). @@ -19,7 +17,6 @@ swap of RGB565 color on the LVGL configuration menuconfig (it's not handled auto | Display Controller | Type | Interface | Color depth (LV_COLOR_DEPTH) | Swap RGB565 color (LV_COLOR_16_SWAP) | |---------------------------------------------|------------|------------------------|------------------------------|----------------------------------------| | ILI9341 | TFT | SPI | 16: RGB565 | Yes | -| ILI9163C | TFT | SPI | 16: RGB565 | Yes | | ILI9486 | TFT | SPI | 16: RGB565 | Yes | | ILI9488 | TFT | SPI | 16: RGB565 | No | | HX8357B/HX8357D | TFT | SPI | 16: RGB565 | Yes | @@ -30,25 +27,17 @@ swap of RGB565 color on the LVGL configuration menuconfig (it's not handled auto | RA8875 | TFT | SPI | 16: RGB565 | Yes | | SH1107 | Monochrome | SPI | 1: 1byte per pixel | No | | SSD1306 | Monochrome | I2C | 1: 1byte per pixel | No | -| PCD8544 | Monochrome | SPI | 1: 1byte per pixel | No | | IL3820 | e-Paper | SPI | 1: 1byte per pixel | No | | UC8151D/ GoodDisplay GDEW0154M10 DES | e-Paper | SPI | 1: 1byte per pixel | No | | 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 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 - XPT2046 -- FT3236, FT6X36 -- FT6206 controllers should work as well (not tested) +- FT3236 +- 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) @@ -62,7 +51,6 @@ and sets the gpio numbers for the interface. |---------------------------|-----------------------|-----------|-----------|-----------| | ESP Wrover Kit v4.1 | ILI9341 | SPI | 240 | 320 | | M5Stack | ILI9341 | SPI | 240 | 320 | -| M5Stack Core2 | ILI9341 | SPI | 240 | 320 | | M5Stick | SH1107 | SPI | - | - | | M5StickC | ST7735S | SPI | 80 | 160 | | Adafruit 3.5 Featherwing | HX8357 | SPI | 480 | 320 | @@ -75,27 +63,3 @@ and sets the gpio numbers for the interface. **NOTE:** See [Supported display controllers](#supported-display-controllers) for more information on display configuration. **NOTE:** See [Supported indev controllers](#supported-indev-controllers) for more information about indev configuration. - - -## Thread-safe I2C with I2C Manager - -LVGL can use I2C to read from a touch sensor or write to a display, possibly -many times a second. Meanwhile, other tasks may also want to read from i2c -devices on the same bus. I2C using the ESP-IDF is not thread-safe. - -I2C Manager (`i2c_manager`) is a component that will let code in multiple threads -talk to devices on the I2C ports without getting in each other's way. These drivers -use a built-in copy of I2C Manager to talk to the I2C port, but you can also use -the I2C Manager component itself and have others play nice with LVGL and vice-versa. -[Click here](i2c_manager/README.md) for details. - - -## Backlight control - -Control of LCD's backlight is provided by separate module that is independent from the display driver. -Configuration of the backlight controller can be found in menuconfig `LVGL ESP Drivers -> LVGL TFT Display controller`. - -There are three modes of operation: -1. Off - No backlight control -2. Switch - Allows ON/OFF control -3. PWM - Allows brightness control (by Pulse-Width-Modulated signal) diff --git a/component.mk b/component.mk index 0017d0ba..dbd1105a 100644 --- a/component.mk +++ b/component.mk @@ -1,7 +1,7 @@ # LVGL ESP32 drivers # Define sources and include dirs -COMPONENT_SRCDIRS := . lvgl_tft lvgl_touch lvgl_i2c +COMPONENT_SRCDIRS := . lvgl_tft lvgl_touch COMPONENT_ADD_INCLUDEDIRS := . # LVGL is supposed to be used as a ESP-IDF component @@ -44,6 +44,4 @@ $(call compile_only_if,$(and $(CONFIG_LV_TOUCH_CONTROLLER),$(CONFIG_LV_TOUCH_CON $(call compile_only_if,$(and $(CONFIG_LV_TOUCH_CONTROLLER),$(CONFIG_LV_TOUCH_CONTROLLER_RA8875)), lvgl_touch/ra8875_touch.o) $(call compile_only_if,$(and $(CONFIG_LV_TOUCH_CONTROLLER),$(CONFIG_LV_TOUCH_DRIVER_PROTOCOL_SPI)), lvgl_touch/tp_spi.o) - -# I2C Manager -$(call compile_only_if,$(CONFIG_LV_I2C), lvgl_i2c/i2c_manager.o) +$(call compile_only_if,$(and $(CONFIG_LV_TOUCH_CONTROLLER),$(CONFIG_LV_TOUCH_DRIVER_PROTOCOL_I2C)), lvgl_touch/tp_i2c.o) diff --git a/lvgl_helpers.c b/lvgl_helpers.c index 14780596..334f1f3c 100644 --- a/lvgl_helpers.c +++ b/lvgl_helpers.c @@ -14,13 +14,14 @@ #include "lvgl_touch/tp_spi.h" #include "lvgl_spi_conf.h" +#include "lvgl_i2c_conf.h" -#include "lvgl_i2c/i2c_manager.h" +#include "driver/i2c.h" #ifdef LV_LVGL_H_INCLUDE_SIMPLE -#include "lvgl.h" +#include "src/lv_core/lv_refr.h" #else -#include "lvgl/lvgl.h" +#include "lvgl/src/lv_core/lv_refr.h" #endif /********************* @@ -52,12 +53,7 @@ /* Interface and driver initialization */ void lvgl_driver_init(void) { - /* Since LVGL v8 LV_HOR_RES_MAX and LV_VER_RES_MAX are not defined, so - * print it only if they are defined. */ -#if (LVGL_VERSION_MAJOR < 8) ESP_LOGI(TAG, "Display hor size: %d, ver size: %d", LV_HOR_RES_MAX, LV_VER_RES_MAX); -#endif - ESP_LOGI(TAG, "Display buffer size: %d", DISP_BUF_SIZE); #if defined (CONFIG_LV_TFT_DISPLAY_CONTROLLER_FT81X) @@ -67,7 +63,7 @@ void lvgl_driver_init(void) DISP_SPI_MISO, DISP_SPI_MOSI, DISP_SPI_CLK, SPI_BUS_MAX_TRANSFER_SZ, 1, DISP_SPI_IO2, DISP_SPI_IO3); - + disp_spi_add_device(TFT_SPI_HOST); disp_driver_init(); @@ -85,92 +81,152 @@ void lvgl_driver_init(void) TP_SPI_MISO, DISP_SPI_MOSI, DISP_SPI_CLK, SPI_BUS_MAX_TRANSFER_SZ, 1, -1, -1); - + disp_spi_add_device(TFT_SPI_HOST); tp_spi_add_device(TOUCH_SPI_HOST); - + disp_driver_init(); touch_driver_init(); return; #endif +#if defined (SHARED_I2C_BUS) + ESP_LOGI(TAG, "Initializing shared I2C master"); + + lvgl_i2c_driver_init(DISP_I2C_PORT, + DISP_I2C_SDA, DISP_I2C_SCL, + DISP_I2C_SPEED_HZ); + + disp_driver_init(); + touch_driver_init(); + + return; +#endif + /* Display controller initialization */ #if defined CONFIG_LV_TFT_DISPLAY_PROTOCOL_SPI ESP_LOGI(TAG, "Initializing SPI master for display"); - + lvgl_spi_driver_init(TFT_SPI_HOST, DISP_SPI_MISO, DISP_SPI_MOSI, DISP_SPI_CLK, SPI_BUS_MAX_TRANSFER_SZ, 1, DISP_SPI_IO2, DISP_SPI_IO3); - + disp_spi_add_device(TFT_SPI_HOST); - + disp_driver_init(); -#elif defined (CONFIG_LV_I2C_DISPLAY) +#elif defined (CONFIG_LV_TFT_DISPLAY_PROTOCOL_I2C) + ESP_LOGI(TAG, "Initializing I2C master for display"); + /* Init the i2c master on the display driver code */ + lvgl_i2c_driver_init(DISP_I2C_PORT, + DISP_I2C_SDA, DISP_I2C_SCL, + DISP_I2C_SPEED_HZ); + disp_driver_init(); #elif defined (CONFIG_LV_EPAPER_DISPLAY_PROTOCOL_PARALLEL) // Do not initialize SPI. Uses EPDiy - ESP_LOGI(TAG, "Initializing Parallel driver for display"); + ESP_LOGI(TAG, "Initializing driver for display"); // Check how not to initialize SPI. disp_driver_init() call is needed: disp_driver_init(); -#elif defined (CONFIG_LV_I2C_DISPLAY) - disp_driver_init(); #else -#error "No protocol defined for display controller" + #error "No protocol defined for display controller" #endif /* Touch controller initialization */ #if CONFIG_LV_TOUCH_CONTROLLER != TOUCH_CONTROLLER_NONE #if defined (CONFIG_LV_TOUCH_DRIVER_PROTOCOL_SPI) ESP_LOGI(TAG, "Initializing SPI master for touch"); - + lvgl_spi_driver_init(TOUCH_SPI_HOST, TP_SPI_MISO, TP_SPI_MOSI, TP_SPI_CLK, 0 /* Defaults to 4094 */, 2, -1, -1); - + tp_spi_add_device(TOUCH_SPI_HOST); - + touch_driver_init(); - #elif defined (CONFIG_LV_I2C_TOUCH) + #elif defined (CONFIG_LV_TOUCH_DRIVER_PROTOCOL_I2C) + ESP_LOGI(TAG, "Initializing I2C master for touch"); + lvgl_i2c_driver_init(TOUCH_I2C_PORT, + TOUCH_I2C_SDA, TOUCH_I2C_SCL, + TOUCH_I2C_SPEED_HZ); + touch_driver_init(); #elif defined (CONFIG_LV_TOUCH_DRIVER_ADC) touch_driver_init(); #elif defined (CONFIG_LV_TOUCH_DRIVER_DISPLAY) || defined (CONFIG_LV_TOUCH_CONTROLLER_L58) touch_driver_init(); #else - #error "No protocol defined for touch controller" + #error "No protocol defined for touch controller" + #endif #else #endif } - -/* Initialize spi bus master - * - * NOTE: dma_chan type and value changed to int instead of spi_dma_chan_t - * for backwards compatibility with ESP-IDF versions prior v4.3. +/* Config the i2c master * - * We could use the ESP_IDF_VERSION_VAL macro available in the "esp_idf_version.h" - * header available since ESP-IDF v4. + * This should init the i2c master to be used on display and touch controllers. + * So we should be able to know if the display and touch controllers shares the + * same i2c master. */ +bool lvgl_i2c_driver_init(int port, int sda_pin, int scl_pin, int speed_hz) +{ + esp_err_t err; + + ESP_LOGI(TAG, "Initializing I2C master port %d...", port); + ESP_LOGI(TAG, "SDA pin: %d, SCL pin: %d, Speed: %d (Hz)", + sda_pin, scl_pin, speed_hz); + + i2c_config_t conf = { + .mode = I2C_MODE_MASTER, + .sda_io_num = sda_pin, + .sda_pullup_en = GPIO_PULLUP_ENABLE, + .scl_io_num = scl_pin, + .scl_pullup_en = GPIO_PULLUP_ENABLE, + .master.clk_speed = speed_hz, + }; + + ESP_LOGI(TAG, "Setting I2C master configuration..."); + err = i2c_param_config(port, &conf); + assert(ESP_OK == err); + + ESP_LOGI(TAG, "Installing I2C master driver..."); + err = i2c_driver_install(port, + I2C_MODE_MASTER, + 0, 0 /*I2C_MASTER_RX_BUF_DISABLE, I2C_MASTER_TX_BUF_DISABLE */, + 0 /* intr_alloc_flags */); + assert(ESP_OK == err); + + return ESP_OK != err; +} + +/* Initialize spi bus master */ bool lvgl_spi_driver_init(int host, int miso_pin, int mosi_pin, int sclk_pin, int max_transfer_sz, int dma_channel, int quadwp_pin, int quadhd_pin) { - /** - * @brief in idf 4.3 is giving me an error: - * error: 'SPI_HOST_MAX' undeclared - */ - assert((0 <= host) && (SPI_HOST_MAX > host)); +#if defined (CONFIG_IDF_TARGET_ESP32) + assert((SPI_HOST <= host) && (VSPI_HOST >= host)); + const char *spi_names[] = { + "SPI_HOST", "HSPI_HOST", "VSPI_HOST" + }; +#elif defined (CONFIG_IDF_TARGET_ESP32C3) + //assert((SPI2_HOST <= host) && (SPI2_HOST >= host)); + const char *spi_names[] = { + "SPI2_HOST", "", "" + }; +#elif defined (CONFIG_IDF_TARGET_ESP32S2) || defined (CONFIG_IDF_TARGET_ESP32S3) + //assert((SPI_HOST <= host) && (HSPI_HOST >= host)); const char *spi_names[] = { - "SPI1_HOST", "SPI2_HOST", "SPI3_HOST" + "SPI_HOST", "", "" }; +#endif - ESP_LOGI(TAG, "Configuring SPI host %s", spi_names[host]); + ESP_LOGI(TAG, "Configuring SPI host %s (%d)", spi_names[host], host); ESP_LOGI(TAG, "MISO pin: %d, MOSI pin: %d, SCLK pin: %d, IO2/WP pin: %d, IO3/HD pin: %d", miso_pin, mosi_pin, sclk_pin, quadwp_pin, quadhd_pin); @@ -178,19 +234,17 @@ bool lvgl_spi_driver_init(int host, spi_bus_config_t buscfg = { .miso_io_num = miso_pin, - .mosi_io_num = mosi_pin, - .sclk_io_num = sclk_pin, - .quadwp_io_num = quadwp_pin, - .quadhd_io_num = quadhd_pin, + .mosi_io_num = mosi_pin, + .sclk_io_num = sclk_pin, + .quadwp_io_num = quadwp_pin, + .quadhd_io_num = quadhd_pin, .max_transfer_sz = max_transfer_sz }; ESP_LOGI(TAG, "Initializing SPI bus..."); - #if defined (CONFIG_IDF_TARGET_ESP32C3) - dma_channel = SPI_DMA_CH_AUTO; - #endif - esp_err_t ret = spi_bus_initialize(host, &buscfg, (spi_dma_chan_t)dma_channel); + esp_err_t ret = spi_bus_initialize(host, &buscfg, dma_channel); assert(ret == ESP_OK); return ESP_OK != ret; } + diff --git a/lvgl_helpers.h b/lvgl_helpers.h index f9b3ba8a..db76c700 100644 --- a/lvgl_helpers.h +++ b/lvgl_helpers.h @@ -16,7 +16,6 @@ extern "C" { #include "lvgl_spi_conf.h" #include "lvgl_tft/disp_driver.h" -#include "lvgl_tft/esp_lcd_backlight.h" #include "lvgl_touch/touch_driver.h" /********************* @@ -43,11 +42,14 @@ extern "C" { #define DISP_BUF_SIZE (LV_HOR_RES_MAX * 40) #elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_ST7796S #define DISP_BUF_SIZE (LV_HOR_RES_MAX * LV_VER_RES_MAX/3) -// IMPORTANT: This will render the screen in 10 times: +// IMPORTANT: This will render the screen in 8 times (Max more and it skips lines) #elif defined (CONFIG_LV_EPAPER_EPDIY_DISPLAY_CONTROLLER) - #define DISP_BUF_SIZE LV_HOR_RES_MAX*(LV_VER_RES_MAX/10) -#elif defined () -#define DISP_BUF_SIZE (LV_HOR_RES_MAX * 90) + #define DISP_BUF_SIZE LV_HOR_RES_MAX*(LV_VER_RES_MAX/ 8) + +#elif defined (CONFIG_LV_EPAPER_CALEPD_DISPLAY_CONTROLLER) +#define DISP_BUF_SIZE LV_HOR_RES_MAX*(LV_VER_RES_MAX/10) +#elif defined (CONFIG_LV_SHARP_DISPLAY_CONTROLLER) +#define DISP_BUF_SIZE LV_HOR_RES_MAX*(LV_VER_RES_MAX) #elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_HX8357 #define DISP_BUF_SIZE (LV_HOR_RES_MAX * 40) @@ -80,10 +82,6 @@ extern "C" { #define DISP_BUF_SIZE ((LV_VER_RES_MAX * LV_VER_RES_MAX) / 8) // 5KB #elif defined (CONFIG_LV_TFT_DISPLAY_CONTROLLER_UC8151D) #define DISP_BUF_SIZE ((LV_VER_RES_MAX * LV_VER_RES_MAX) / 8) // 2888 bytes -#elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_ILI9163C -#define DISP_BUF_SIZE (LV_HOR_RES_MAX * 40) -#elif defined (CONFIG_LV_TFT_DISPLAY_CONTROLLER_PCD8544) -#define DISP_BUF_SIZE (LV_HOR_RES_MAX * (LV_VER_RES_MAX / 8)) #else #error "No display controller selected" #endif @@ -97,14 +95,14 @@ extern "C" { * GLOBAL PROTOTYPES **********************/ -void lvgl_i2c_locking(void* leader); - /* Initialize detected SPI and I2C bus and devices */ void lvgl_driver_init(void); /* Initialize SPI master */ bool lvgl_spi_driver_init(int host, int miso_pin, int mosi_pin, int sclk_pin, int max_transfer_sz, int dma_channel, int quadwp_pin, int quadhd_pin); +/* Initialize I2C master */ +bool lvgl_i2c_driver_init(int port, int sda_pin, int scl_pin, int speed); /********************** * MACROS diff --git a/lvgl_i2c_conf.h b/lvgl_i2c_conf.h new file mode 100644 index 00000000..cf8ac45e --- /dev/null +++ b/lvgl_i2c_conf.h @@ -0,0 +1,116 @@ +/** + * @file lvgl_i2c_config.h + */ + +#ifndef LVGL_I2C_CONF_H +#define LVGL_I2C_CONF_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_LVGL_H_INCLUDE_SIMPLE +#include "lvgl.h" +#else +#include "lvgl/lvgl.h" +#endif + +/********************* + * DEFINES + *********************/ + +/* TODO: Define the I2C bus clock based on the selected display or touch + * controllers. */ + +/* Do both display and touch controllers uses I2C? */ +#if defined (CONFIG_LV_TOUCH_DRIVER_PROTOCOL_I2C) && \ + defined (CONFIG_LV_TFT_DISPLAY_PROTOCOL_I2C) + +#if defined (CONFIG_LV_DISPLAY_I2C_PORT_0) && \ + defined (CONFIG_LV_TOUCH_I2C_PORT_0) +#define SHARED_I2C_PORT +#define DISP_I2C_PORT I2C_NUM_0 +#endif + +#if defined (CONFIG_LV_DISPLAY_I2C_PORT_1) && \ + defined (CONFIG_LV_TOUCH_I2C_PORT_1) +#define SHARED_I2C_PORT +#define DISP_I2C_PORT I2C_NUM_1 +#endif + +#if !defined (SHARED_I2C_PORT) +#endif +#endif + +#if defined (SHARED_I2C_PORT) +/* If the port is shared the display and touch controllers must use the same + * SCL and SDA pins, otherwise let the user know with an error. */ +#if (CONFIG_LV_DISP_PIN_SDA != CONFIG_LV_TOUCH_I2C_SDA) || \ + (CONFIG_LV_DISP_PIN_SCL != CONFIG_LV_TOUCH_I2C_SCL) +#error "To share I2C port you need to choose the same SDA and SCL pins on both display and touch configurations" +#endif + +#define DISP_I2C_SDA CONFIG_LV_DISP_PIN_SDA +#define DISP_I2C_SCL CONFIG_LV_DISP_PIN_SCL +#define DISP_I2C_ORIENTATION TFT_ORIENTATION_LANDSCAPE + +/* Setting the I2C speed to the slowest one */ +#if DISP_I2C_SPEED_HZ < TOUCH_I2C_SPEED_HZ +#define DISP_I2C_SPEED_HZ 400000 /* DISP_I2C_SPEED_HZ */ +#else +#define DISP_I2C_SPEED_HZ 400000 /* DISP_I2C_SPEED_HZ */ +#endif + +#else + +/* lets check if the touch controller uses I2C... */ +#if defined (CONFIG_LV_TOUCH_DRIVER_PROTOCOL_I2C) +#if defined (CONFIG_LV_TOUCH_I2C_PORT_0) +#define TOUCH_I2C_PORT I2C_NUM_0 +#else +#define TOUCH_I2C_PORT I2C_NUM_1 +#endif +#define TOUCH_I2C_SDA CONFIG_LV_TOUCH_I2C_SDA +#define TOUCH_I2C_SCL CONFIG_LV_TOUCH_I2C_SCL +#define TOUCH_I2C_SPEED_HZ 400000 +#endif + +/* lets check if the display controller uses I2C... */ +#if defined (CONFIG_LV_TFT_DISPLAY_PROTOCOL_I2C) +#if defined (CONFIG_LV_DISPLAY_I2C_PORT_0) +#define DISP_I2C_PORT I2C_NUM_0 +#else +#define DISP_I2C_PORT I2C_NUM_1 +#endif + +#define DISP_I2C_SDA CONFIG_LV_DISP_PIN_SDA +#define DISP_I2C_SCL CONFIG_LV_DISP_PIN_SCL +#define DISP_I2C_ORIENTATION TFT_ORIENTATION_LANDSCAPE +#define DISP_I2C_SPEED_HZ 400000 +#endif + +#endif + +/********************** + * TYPEDEFS + **********************/ + + +/********************** + * GLOBAL PROTOTYPES + **********************/ + + +/********************** + * MACROS + **********************/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LVGL_I2C_CONF_H*/ diff --git a/lvgl_spi_conf.h b/lvgl_spi_conf.h index 662be989..16e63b4f 100644 --- a/lvgl_spi_conf.h +++ b/lvgl_spi_conf.h @@ -64,10 +64,12 @@ extern "C" { #define ENABLE_TOUCH_INPUT CONFIG_LV_ENABLE_TOUCH -#if defined (CONFIG_LV_TFT_DISPLAY_SPI2_HOST) -#define TFT_SPI_HOST SPI2_HOST -#elif defined (CONFIG_LV_TFT_DISPLAY_SPI3_HOST) -#define TFT_SPI_HOST SPI3_HOST +#if defined (CONFIG_LV_TFT_DISPLAY_SPI_HSPI) +#define TFT_SPI_HOST HSPI_HOST +#elif defined (CONFIG_LV_TFT_DISPLAY_SPI_VSPI) +#define TFT_SPI_HOST VSPI_HOST +#elif defined (CONFIG_LV_TFT_DISPLAY_SPI_FSPI) +#define TFT_SPI_HOST FSPI_HOST #endif #if defined (CONFIG_LV_TFT_DISPLAY_SPI_HALF_DUPLEX) @@ -84,10 +86,12 @@ extern "C" { #define DISP_SPI_TRANS_MODE_SIO #endif -#if defined (CONFIG_LV_TOUCH_CONTROLLER_SPI2_HOST) -#define TOUCH_SPI_HOST SPI2_HOST -#elif defined (CONFIG_LV_TOUCH_CONTROLLER_SPI3_HOST) -#define TOUCH_SPI_HOST SPI3_HOST +#if defined (CONFIG_LV_TOUCH_CONTROLLER_SPI_HSPI) +#define TOUCH_SPI_HOST HSPI_HOST +#elif defined (CONFIG_LV_TOUCH_CONTROLLER_SPI_VSPI) +#define TOUCH_SPI_HOST VSPI_HOST +#elif defined (CONFIG_LV_TOUCH_CONTROLLER_SPI_FSPI) +#define TOUCH_SPI_HOST FSPI_HOST #endif /* Handle the FT81X Special case */ @@ -103,7 +107,7 @@ extern "C" { // Detect the use of a shared SPI Bus and verify the user specified the same SPI bus for both touch and tft #if defined (CONFIG_LV_TOUCH_DRIVER_PROTOCOL_SPI) && TP_SPI_MOSI == DISP_SPI_MOSI && TP_SPI_CLK == DISP_SPI_CLK #if TFT_SPI_HOST != TOUCH_SPI_HOST -#error You must specify the same SPI host (SPIx_HOST) for both display and touch driver +#error You must specify the same SPI host (HSPI, VSPI or FSPI) for both display and touch driver #endif #define SHARED_SPI_BUS @@ -126,8 +130,7 @@ extern "C" { defined (CONFIG_LV_TFT_DISPLAY_CONTROLLER_SH1107) || \ defined (CONFIG_LV_TFT_DISPLAY_CONTROLLER_FT81X) || \ defined (CONFIG_LV_TFT_DISPLAY_CONTROLLER_IL3820) || \ - defined (CONFIG_LV_TFT_DISPLAY_CONTROLLER_JD79653A) || \ - defined (CONFIG_LV_TFT_DISPLAY_CONTROLLER_ILI9163C) + defined (CONFIG_LV_TFT_DISPLAY_CONTROLLER_JD79653A) #define SPI_BUS_MAX_TRANSFER_SZ (DISP_BUF_SIZE * 2) @@ -154,12 +157,8 @@ extern "C" { #define SPI_TFT_CLOCK_SPEED_HZ (40*1000*1000) #elif defined (CONFIG_LV_TFT_DISPLAY_CONTROLLER_ILI9341) #define SPI_TFT_CLOCK_SPEED_HZ (40*1000*1000) -#elif defined(CONFIG_LV_TFT_DISPLAY_CONTROLLER_ILI9163C) -#define SPI_TFT_CLOCK_SPEED_HZ (40 * 1000 * 1000) -#elif defined(CONFIG_LV_TFT_DISPLAY_CONTROLLER_FT81X) +#elif defined (CONFIG_LV_TFT_DISPLAY_CONTROLLER_FT81X) #define SPI_TFT_CLOCK_SPEED_HZ (32*1000*1000) -#elif defined (CONFIG_LV_TFT_DISPLAY_CONTROLLER_PCD8544) -#define SPI_TFT_CLOCK_SPEED_HZ (4*1000*1000) #else #define SPI_TFT_CLOCK_SPEED_HZ (40*1000*1000) #endif diff --git a/lvgl_tft/EVE_commands.c b/lvgl_tft/EVE_commands.c index 2a93efab..9e458f48 100644 --- a/lvgl_tft/EVE_commands.c +++ b/lvgl_tft/EVE_commands.c @@ -144,7 +144,7 @@ void DELAY_MS(uint16_t ms) vTaskDelay(ms / portTICK_PERIOD_MS); } -#if EVE_USE_PDN + void EVE_pdn_set(void) { gpio_set_level(EVE_PDN, 0); /* Power-Down low */ @@ -155,7 +155,7 @@ void EVE_pdn_clear(void) { gpio_set_level(EVE_PDN, 1); /* Power-Down high */ } -#endif + void spi_acquire() { @@ -841,13 +841,11 @@ uint8_t EVE_init(void) uint8_t chipid = 0; uint16_t timeout = 0; -#if EVE_USE_PDN EVE_pdn_set(); DELAY_MS(6); /* minimum time for power-down is 5ms */ EVE_pdn_clear(); DELAY_MS(21); /* minimum time to allow from rising PD_N to first access is 20ms */ -#endif /* EVE_cmdWrite(EVE_CORERST,0); */ /* reset, only required for warm-start if PowerDown line is not used */ diff --git a/lvgl_tft/EVE_commands.h b/lvgl_tft/EVE_commands.h index aa9d0612..3c5c1047 100644 --- a/lvgl_tft/EVE_commands.h +++ b/lvgl_tft/EVE_commands.h @@ -39,12 +39,8 @@ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR TH #define BLOCK_TRANSFER_SIZE 3840 // block transfer size when write data to CMD buffer void DELAY_MS(uint16_t ms); - -#if EVE_USE_PDN void EVE_pdn_set(void); void EVE_pdn_clear(void); -#endif - void spi_acquire(); void spi_release(); @@ -68,7 +64,7 @@ void EVE_get_cmdoffset(void); /* commands to operate on memory: */ void EVE_cmd_memzero(uint32_t ptr, uint32_t num); void EVE_cmd_memset(uint32_t ptr, uint8_t value, uint32_t num); -void EVE_cmd_memwrite(uint32_t dest, uint32_t num, const uint8_t *data); +void EVE_cmd_memwrite(uint32_t dest, uint32_t num, const uint8_t *data); void EVE_cmd_memcpy(uint32_t dest, uint32_t src, uint32_t num); #if FT81X_FULL diff --git a/lvgl_tft/EVE_config.h b/lvgl_tft/EVE_config.h index 386edb9b..53225a23 100644 --- a/lvgl_tft/EVE_config.h +++ b/lvgl_tft/EVE_config.h @@ -44,12 +44,11 @@ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR TH #include "FT81x.h" -#define EVE_CLK DISP_SPI_CLK // orange -#define EVE_MISO DISP_SPI_MISO // yellow -#define EVE_MOSI DISP_SPI_MOSI // green -#define EVE_CS DISP_SPI_CS // blue -#define EVE_PDN CONFIG_LV_DISP_PIN_RST // grey -#define EVE_USE_PDN CONFIG_LV_DISP_USE_RST +#define EVE_CLK DISP_SPI_CLK // orange +#define EVE_MISO DISP_SPI_MISO // yellow +#define EVE_MOSI DISP_SPI_MOSI // green +#define EVE_CS DISP_SPI_CS // blue +#define EVE_PDN CONFIG_LV_DISP_PIN_RST // grey #define SPI_TRANSER_SIZE (DISP_BUF_SIZE * (LV_COLOR_DEPTH / 8)) diff --git a/lvgl_tft/FT81x.c b/lvgl_tft/FT81x.c index 63e0dee7..b004eba2 100644 --- a/lvgl_tft/FT81x.c +++ b/lvgl_tft/FT81x.c @@ -250,7 +250,7 @@ void TFT_bitmap_display(void) EVE_cmd_dl(TAG(0)); EVE_cmd_dl(DL_DISPLAY); /* instruct the graphics processor to show the list */ - + EVE_cmd_dl(CMD_SWAP); /* make this list active */ EVE_end_cmd_burst(); /* stop writing to the cmd-fifo */ @@ -262,18 +262,12 @@ void TFT_bitmap_display(void) void FT81x_init(void) { -#if EVE_USE_PDN gpio_pad_select_gpio(EVE_PDN); -#endif - gpio_set_level(EVE_CS, 1); - -#if EVE_USE_PDN gpio_set_direction(EVE_PDN, GPIO_MODE_OUTPUT); -#endif spi_acquire(); - + if(EVE_init()) { tft_active = 1; @@ -284,7 +278,7 @@ void FT81x_init(void) EVE_cmd_memset(SCREEN_BITMAP_ADDR, BLACK, SCREEN_BUFFER_SIZE); // clear screen buffer EVE_cmd_execute(); - + TFT_bitmap_display(); // set DL for fullscreen bitmap display } @@ -326,4 +320,4 @@ void TFT_WriteBitmap(uint8_t* Bitmap, uint16_t X, uint16_t Y, uint16_t Width, ui void FT81x_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * color_map) { TFT_WriteBitmap((uint8_t*)color_map, area->x1, area->y1, lv_area_get_width(area), lv_area_get_height(area)); -} +} \ No newline at end of file diff --git a/lvgl_tft/GC9A01.c b/lvgl_tft/GC9A01.c index c807233d..63687e3c 100644 --- a/lvgl_tft/GC9A01.c +++ b/lvgl_tft/GC9A01.c @@ -111,20 +111,31 @@ void GC9A01_init(void) }; +#if GC9A01_BCKL == 15 + gpio_config_t io_conf; + io_conf.intr_type = GPIO_PIN_INTR_DISABLE; + io_conf.mode = GPIO_MODE_OUTPUT; + io_conf.pin_bit_mask = GPIO_SEL_15; + io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE; + io_conf.pull_up_en = GPIO_PULLUP_DISABLE; + gpio_config(&io_conf); +#endif + //Initialize non-SPI GPIOs - gpio_pad_select_gpio(GC9A01_DC); + gpio_pad_select_gpio(GC9A01_DC); gpio_set_direction(GC9A01_DC, GPIO_MODE_OUTPUT); - -#if GC9A01_USE_RST - gpio_pad_select_gpio(GC9A01_RST); + gpio_pad_select_gpio(GC9A01_RST); gpio_set_direction(GC9A01_RST, GPIO_MODE_OUTPUT); +#if GC9A01_ENABLE_BACKLIGHT_CONTROL + gpio_pad_select_gpio(GC9A01_BCKL); + gpio_set_direction(GC9A01_BCKL, GPIO_MODE_OUTPUT); +#endif //Reset the display gpio_set_level(GC9A01_RST, 0); vTaskDelay(100 / portTICK_RATE_MS); gpio_set_level(GC9A01_RST, 1); vTaskDelay(100 / portTICK_RATE_MS); -#endif ESP_LOGI(TAG, "Initialization."); @@ -139,6 +150,8 @@ void GC9A01_init(void) cmd++; } + GC9A01_enable_backlight(true); + GC9A01_set_orientation(CONFIG_LV_DISPLAY_ORIENTATION); #if GC9A01_INVERT_COLORS == 1 @@ -154,7 +167,7 @@ void GC9A01_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * colo uint8_t data[4]; /*Column addresses*/ - GC9A01_send_cmd(0x2A); //0x2A + GC9A01_send_cmd(0x2A); //0x2A data[0] = (area->x1 >> 8) & 0xFF; data[1] = area->x1 & 0xFF; data[2] = (area->x2 >> 8) & 0xFF; @@ -162,7 +175,7 @@ void GC9A01_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * colo GC9A01_send_data(data, 4); /*Page addresses*/ - GC9A01_send_cmd(0x2B); //0x2B + GC9A01_send_cmd(0x2B); //0x2B data[0] = (area->y1 >> 8) & 0xFF; data[1] = area->y1 & 0xFF; data[2] = (area->y2 >> 8) & 0xFF; @@ -170,7 +183,7 @@ void GC9A01_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * colo GC9A01_send_data(data, 4); /*Memory write*/ - GC9A01_send_cmd(0x2C); //0x2C + GC9A01_send_cmd(0x2C); //0x2C uint32_t size = lv_area_get_width(area) * lv_area_get_height(area); @@ -178,11 +191,27 @@ void GC9A01_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * colo GC9A01_send_color((void*)color_map, size * 2); } +void GC9A01_enable_backlight(bool backlight) +{ +#if GC9A01_ENABLE_BACKLIGHT_CONTROL + ESP_LOGI(TAG, "%s backlight.", backlight ? "Enabling" : "Disabling"); + uint32_t tmp = 0; + +#if (GC9A01_BCKL_ACTIVE_LVL==1) + tmp = backlight ? 1 : 0; +#else + tmp = backlight ? 0 : 1; +#endif + + gpio_set_level(GC9A01_BCKL, tmp); +#endif +} + void GC9A01_sleep_in() { uint8_t data[] = {0x08}; GC9A01_send_cmd(0x10); //0x10 Enter Sleep Mode - GC9A01_send_data(&data, 1); + GC9A01_send_data(&data, 1); } void GC9A01_sleep_out() diff --git a/lvgl_tft/GC9A01.h b/lvgl_tft/GC9A01.h index e39c14d6..d462c8d4 100644 --- a/lvgl_tft/GC9A01.h +++ b/lvgl_tft/GC9A01.h @@ -25,9 +25,18 @@ extern "C" { /********************* * DEFINES *********************/ -#define GC9A01_DC CONFIG_LV_DISP_PIN_DC -#define GC9A01_RST CONFIG_LV_DISP_PIN_RST -#define GC9A01_USE_RST CONFIG_LV_DISP_USE_RST +#define GC9A01_DC CONFIG_LV_DISP_PIN_DC +#define GC9A01_RST CONFIG_LV_DISP_PIN_RST +#define GC9A01_BCKL CONFIG_LV_DISP_PIN_BCKL + +#define GC9A01_ENABLE_BACKLIGHT_CONTROL CONFIG_LV_ENABLE_BACKLIGHT_CONTROL + +#if CONFIG_LV_BACKLIGHT_ACTIVE_LVL + #define GC9A01_BCKL_ACTIVE_LVL 1 +#else + #define GC9A01_BCKL_ACTIVE_LVL 0 +#endif + #define GC9A01_INVERT_COLORS CONFIG_LV_INVERT_COLORS /********************** @@ -40,6 +49,7 @@ extern "C" { void GC9A01_init(void); void GC9A01_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * color_map); +void GC9A01_enable_backlight(bool backlight); void GC9A01_sleep_in(void); void GC9A01_sleep_out(void); diff --git a/lvgl_tft/Kconfig b/lvgl_tft/Kconfig index 7f1c8a6b..294f51f2 100644 --- a/lvgl_tft/Kconfig +++ b/lvgl_tft/Kconfig @@ -21,10 +21,6 @@ menu "LVGL TFT/Epaper Display controller" bool "M5Stack" select LV_TFT_DISPLAY_CONTROLLER_ILI9341 select LV_TFT_DISPLAY_PROTOCOL_SPI - config LV_PREDEFINED_DISPLAY_M5CORE2 - bool "M5Core2" - select LV_TFT_DISPLAY_CONTROLLER_ILI9341 - select LV_TFT_DISPLAY_PROTOCOL_SPI config LV_PREDEFINED_DISPLAY_M5STICK bool "M5Stick" select LV_TFT_DISPLAY_CONTROLLER_SH1107 @@ -50,7 +46,7 @@ menu "LVGL TFT/Epaper Display controller" config LV_PREDEFINED_DISPLAY_WEMOS_LOLIN bool "Wemos Lolin OLED" select LV_TFT_DISPLAY_CONTROLLER_SSD1306 - select LV_I2C_DISPLAY + select LV_TFT_DISPLAY_PROTOCOL_I2C select LV_TFT_DISPLAY_MONOCHROME select LV_THEME_MONO config LV_PREDEFINED_DISPLAY_ATAG @@ -93,7 +89,14 @@ 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_SHARP_DISPLAY_CONTROLLER + bool + help + SHARP memory LCD controller. config LV_TFT_DISPLAY_CONTROLLER_ILI9341 bool help @@ -174,15 +177,6 @@ menu "LVGL TFT/Epaper Display controller" help ST7796S display controller. - config LV_TFT_DISPLAY_CONTROLLER_ILI9163C - bool - help - ILI9163C display controller. - - config LV_TFT_DISPLAY_CONTROLLER_PCD8544 - bool - help - PCD8544 display controller (Nokia 3110/5110) # Display controller communication protocol # # This symbols define the communication protocol used by the @@ -201,7 +195,7 @@ menu "LVGL TFT/Epaper Display controller" help Display controller protocol SPI - config LV_I2C_DISPLAY + config LV_TFT_DISPLAY_PROTOCOL_I2C bool help Display controller protocol I2C @@ -209,24 +203,24 @@ menu "LVGL TFT/Epaper Display controller" # Used in display init function to send display orientation commands choice DISPLAY_ORIENTATION prompt "Display orientation" - default LV_DISPLAY_ORIENTATION_PORTRAIT if !LV_TFT_DISPLAY_CONTROLLER_SSD1306 - default LV_DISPLAY_ORIENTATION_LANDSCAPE if LV_TFT_DISPLAY_CONTROLLER_SSD1306 - config LV_DISPLAY_ORIENTATION_PORTRAIT + default DISPLAY_ORIENTATION_PORTRAIT if !LV_TFT_DISPLAY_CONTROLLER_SSD1306 + default DISPLAY_ORIENTATION_LANDSCAPE if LV_TFT_DISPLAY_CONTROLLER_SSD1306 + config DISPLAY_ORIENTATION_PORTRAIT bool "Portrait" if !LV_TFT_DISPLAY_CONTROLLER_SSD1306 - config LV_DISPLAY_ORIENTATION_PORTRAIT_INVERTED + config DISPLAY_ORIENTATION_PORTRAIT_INVERTED bool "Portrait inverted" if !LV_TFT_DISPLAY_CONTROLLER_SSD1306 - config LV_DISPLAY_ORIENTATION_LANDSCAPE + config DISPLAY_ORIENTATION_LANDSCAPE bool "Landscape" - config LV_DISPLAY_ORIENTATION_LANDSCAPE_INVERTED + config DISPLAY_ORIENTATION_LANDSCAPE_INVERTED bool "Landscape inverted" endchoice config LV_DISPLAY_ORIENTATION int - default 0 if LV_DISPLAY_ORIENTATION_PORTRAIT - default 1 if LV_DISPLAY_ORIENTATION_PORTRAIT_INVERTED - default 2 if LV_DISPLAY_ORIENTATION_LANDSCAPE - default 3 if LV_DISPLAY_ORIENTATION_LANDSCAPE_INVERTED + default 0 if DISPLAY_ORIENTATION_PORTRAIT + default 1 if DISPLAY_ORIENTATION_PORTRAIT_INVERTED + default 2 if DISPLAY_ORIENTATION_LANDSCAPE + default 3 if DISPLAY_ORIENTATION_LANDSCAPE_INVERTED config LV_TFT_DISPLAY_OFFSETS bool @@ -235,14 +229,14 @@ menu "LVGL TFT/Epaper Display controller" config LV_TFT_DISPLAY_X_OFFSET depends on LV_TFT_DISPLAY_OFFSETS - int "X offset" + int default 40 if LV_PREDEFINED_DISPLAY_TTGO && (LV_DISPLAY_ORIENTATION_LANDSCAPE || LV_DISPLAY_ORIENTATION_LANDSCAPE_INVERTED) default 53 if LV_PREDEFINED_DISPLAY_TTGO && (LV_DISPLAY_ORIENTATION_PORTRAIT || LV_DISPLAY_ORIENTATION_PORTRAIT_INVERTED) default 0 config LV_TFT_DISPLAY_Y_OFFSET depends on LV_TFT_DISPLAY_OFFSETS - int "Y offset" + int default 53 if LV_PREDEFINED_DISPLAY_TTGO && (LV_DISPLAY_ORIENTATION_LANDSCAPE || LV_DISPLAY_ORIENTATION_LANDSCAPE_INVERTED) default 40 if LV_PREDEFINED_DISPLAY_TTGO && (LV_DISPLAY_ORIENTATION_PORTRAIT || LV_DISPLAY_ORIENTATION_PORTRAIT_INVERTED) default 0 @@ -284,6 +278,18 @@ 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_SHARP_USER_CONTROLLER + bool "SHARP_LCD" + # Use also Parallel to avoid LGVL SPI instantiation + select LV_SHARP_DISPLAY_CONTROLLER + select LV_EPAPER_DISPLAY_PROTOCOL_PARALLEL + config LV_TFT_DISPLAY_USER_CONTROLLER_ILI9341 bool "ILI9341" select LV_TFT_DISPLAY_CONTROLLER_ILI9341 @@ -328,7 +334,7 @@ menu "LVGL TFT/Epaper Display controller" config LV_TFT_DISPLAY_USER_CONTROLLER_SSD1306 bool "SSD1306" select LV_TFT_DISPLAY_CONTROLLER_SSD1306 - select LV_I2C_DISPLAY + select LV_TFT_DISPLAY_PROTOCOL_I2C select LV_TFT_DISPLAY_MONOCHROME config LV_TFT_DISPLAY_USER_CONTROLLER_FT81X bool "FT81X" @@ -353,15 +359,6 @@ menu "LVGL TFT/Epaper Display controller" bool "RA8875" select LV_TFT_DISPLAY_CONTROLLER_RA8875 select LV_TFT_DISPLAY_PROTOCOL_SPI - config LV_TFT_DISPLAY_USER_CONTROLLER_ILI9163C - bool "ILI9163C" - select LV_TFT_DISPLAY_CONTROLLER_ILI9163C - select LV_TFT_DISPLAY_PROTOCOL_SPI - config LV_TFT_DISPLAY_USER_CONTROLLER_PCD8544 - bool "PCD8544" - select LV_TFT_DISPLAY_CONTROLLER_PCD8544 - select LV_TFT_DISPLAY_PROTOCOL_SPI - select LV_TFT_DISPLAY_MONOCHROME endchoice config CUSTOM_DISPLAY_BUFFER_SIZE @@ -481,15 +478,20 @@ menu "LVGL TFT/Epaper Display controller" endchoice choice - prompt "TFT SPI Bus." if LV_TFT_DISPLAY_PROTOCOL_SPI - default LV_TFT_DISPLAY_SPI2_HOST + prompt "TFT SPI Bus." if LV_TFT_DISPLAY_PROTOCOL_SPI && \ + !LV_PREDEFINED_DISPLAY_TTGO + default LV_TFT_DISPLAY_SPI_VSPI if LV_PREDEFINED_DISPLAY_TTGO && \ + !IDF_TARGET_ESP32S2 + default LV_TFT_DISPLAY_SPI_FSPI if IDF_TARGET_ESP32S2 help Select the SPI Bus the TFT Display is attached to. - config LV_TFT_DISPLAY_SPI2_HOST - bool "SPI2_HOST" - config LV_TFT_DISPLAY_SPI3_HOST - bool "SPI3_HOST" + config LV_TFT_DISPLAY_SPI_HSPI + bool "HSPI" + config LV_TFT_DISPLAY_SPI_VSPI + bool "VSPI" if !IDF_TARGET_ESP32S2 + config LV_TFT_DISPLAY_SPI_FSPI + bool "FSPI" if IDF_TARGET_ESP32S2 endchoice choice @@ -520,6 +522,18 @@ menu "LVGL TFT/Epaper Display controller" depends on LV_TFT_DISPLAY_SPI_TRANS_MODE_SIO endchoice + choice + prompt "Display I2C port" if LV_TFT_DISPLAY_PROTOCOL_I2C + default LV_DISPLAY_I2C_PORT_0 + help + Select the I2C port used by the display controller. + + config LV_DISPLAY_I2C_PORT_0 + bool "I2C PORT 0" + config LV_DISPLAY_I2C_PORT_1 + bool "I2C PORT 1" + endchoice + config LV_TFT_USE_CUSTOM_SPI_CLK_DIVIDER bool "Use custom SPI clock frequency." if LV_TFT_DISPLAY_PROTOCOL_SPI default n @@ -597,16 +611,6 @@ menu "LVGL TFT/Epaper Display controller" default 80 if LV_TFT_SPI_CLK_DIVIDER_80 default 2 - config LV_M5STICKC_HANDLE_AXP192 - bool "Handle Backlight and TFT power for M5StickC using AXP192." if LV_PREDEFINED_DISPLAY_M5STICKC || LV_TFT_DISPLAY_CONTROLLER_ST7735S - default y if LV_PREDEFINED_DISPLAY_M5STICKC - select LV_I2C_DISPLAY - help - Display and TFT power supply on M5StickC is controlled using an - AXP192 Power Mangerment IC. Select yes if you want to enable TFT IC - (LDO3) and backlight power using AXP192 by LVGL, or select no if you - want to take care of power management in your own code. - config LV_INVERT_DISPLAY bool "IN DEPRECATION - Invert display." if LV_TFT_DISPLAY_CONTROLLER_RA8875 default n @@ -614,12 +618,37 @@ menu "LVGL TFT/Epaper Display controller" If text is backwards on your display, try enabling this. config LV_INVERT_COLORS - bool "Invert colors in display" if LV_TFT_DISPLAY_CONTROLLER_ILI9341 || LV_TFT_DISPLAY_CONTROLLER_ST7735S || LV_TFT_DISPLAY_CONTROLLER_ILI9481 || LV_TFT_DISPLAY_CONTROLLER_ST7789 || LV_TFT_DISPLAY_CONTROLLER_SSD1306 || LV_TFT_DISPLAY_CONTROLLER_SH1107 || LV_TFT_DISPLAY_CONTROLLER_HX8357 || LV_TFT_DISPLAY_CONTROLLER_GC9A01 || LV_TFT_DISPLAY_CONTROLLER_ILI9163C + bool "Invert colors in display" if LV_TFT_DISPLAY_CONTROLLER_ILI9341 || LV_TFT_DISPLAY_CONTROLLER_ST7735S || LV_TFT_DISPLAY_CONTROLLER_ILI9481 || LV_TFT_DISPLAY_CONTROLLER_ST7789 || LV_TFT_DISPLAY_CONTROLLER_SSD1306 || LV_TFT_DISPLAY_CONTROLLER_SH1107 || LV_TFT_DISPLAY_CONTROLLER_HX8357 default y if LV_PREDEFINED_DISPLAY_M5STACK || LV_PREDEFINED_DISPLAY_M5STICKC help If the colors look inverted on your display, try enabling this. If it didn't help try LVGL configuration -> Swap the 2 bytes of RGB565 color. + config LV_M5STICKC_HANDLE_AXP192 + bool "Handle Backlight and TFT power for M5StickC using AXP192." if LV_PREDEFINED_DISPLAY_M5STICKC || LV_TFT_DISPLAY_CONTROLLER_ST7735S + default y if LV_PREDEFINED_DISPLAY_M5STICKC + help + Display and TFT power supply on M5StickC is controlled using an AXP192 Power Mangerment IC. + Select yes if you want to enable TFT IC (LDO3) and backlight power using AXP192 by LVGL, or select no if you want to take care of + power management in your own code. + + config LV_AXP192_PIN_SDA + int "GPIO for AXP192 I2C SDA" + depends on LV_M5STICKC_HANDLE_AXP192 + range 0 39 + default 21 if LV_PREDEFINED_DISPLAY_M5STICKC + default 21 + help + Configure the AXP192 I2C SDA pin here. + + config LV_AXP192_PIN_SCL + int "GPIO for AXP192 I2C SCL" + depends on LV_M5STICKC_HANDLE_AXP192 + range 0 39 + default 22 if LV_PREDEFINED_DISPLAY_M5STICKC + default 22 + help + Configure the AXP192 I2C SDA pin here. # menu will be visible only when LV_PREDEFINED_DISPLAY_NONE is y menu "Display RA8875 Configuration" @@ -747,11 +776,11 @@ menu "LVGL TFT/Epaper Display controller" config LV_DISP_ST7789_SOFT_RESET bool "Soft reset - use software reset instead of reset pin" - depends on LV_TFT_DISPLAY_CONTROLLER_ST7789 + depends on LV_TFT_DISPLAY_CONTROLLER_ST7789 default n help Use software reset and ignores configured reset pin (some hardware does not use a reset pin). - + endmenu # menu will be visible only when LV_PREDEFINED_DISPLAY_NONE is y @@ -760,10 +789,12 @@ menu "LVGL TFT/Epaper Display controller" config LV_DISP_SPI_MOSI int "GPIO for MOSI (Master Out Slave In)" if LV_TFT_DISPLAY_PROTOCOL_SPI + range 0 39 if IDF_TARGET_ESP32 + range 0 43 if IDF_TARGET_ESP32S2 + default 23 if LV_PREDEFINED_DISPLAY_WROVER4 default 23 if LV_PREDEFINED_DISPLAY_ATAG default 23 if LV_PREDEFINED_DISPLAY_M5STACK || LV_PREDEFINED_DISPLAY_M5STICK - default 23 if LV_PREDEFINED_DISPLAY_M5CORE2 default 15 if LV_PREDEFINED_DISPLAY_M5STICKC default 18 if LV_PREDEFINED_DISPLAY_ADA_FEATHERWING default 23 if LV_PREDEFINED_PINS_TKOALA @@ -771,13 +802,13 @@ menu "LVGL TFT/Epaper Display controller" default 19 if LV_PREDEFINED_DISPLAY_TTGO_CAMERA_PLUS default 13 if LV_PREDEFINED_DISPLAY_WT32_SC01 default 13 + help Configure the display MOSI pin here. config LV_DISPLAY_USE_SPI_MISO bool "GPIO for MISO (Master In Slave Out)" if LV_TFT_DISPLAY_PROTOCOL_SPI default y if LV_PREDEFINED_PINS_TKOALA - default y if LV_PREDEFINED_DISPLAY_M5CORE2 help Enable the MISO signal to control the display. You can disable it when the display does not need MISO signal to be controlled. @@ -785,8 +816,10 @@ menu "LVGL TFT/Epaper Display controller" config LV_DISP_SPI_MISO int "GPIO for MISO (Master In Slave Out)" if LV_TFT_DISPLAY_PROTOCOL_SPI depends on LV_DISPLAY_USE_SPI_MISO + range 0 39 if IDF_TARGET_ESP32 + range 0 43 if IDF_TARGET_ESP32S2 + default 19 if LV_PREDEFINED_PINS_TKOALA - default 38 if LV_PREDEFINED_DISPLAY_M5CORE2 default 0 help @@ -804,6 +837,9 @@ menu "LVGL TFT/Epaper Display controller" config LV_DISP_SPI_IO2 int "GPIO for Quad SPI IO2/WP" if LV_TFT_DISPLAY_PROTOCOL_SPI depends on LV_TFT_DISPLAY_SPI_TRANS_MODE_QIO + range -1 39 if IDF_TARGET_ESP32 + range -1 43 if IDF_TARGET_ESP32S2 + default 22 if LV_PREDEFINED_PINS_TKOALA && LV_TFT_DISPLAY_SPI_TRANS_MODE_QIO default -1 help @@ -812,6 +848,9 @@ menu "LVGL TFT/Epaper Display controller" config LV_DISP_SPI_IO3 int "GPIO for Quad SPI IO3/HD" if LV_TFT_DISPLAY_PROTOCOL_SPI depends on LV_TFT_DISPLAY_SPI_TRANS_MODE_QIO + range -1 39 if IDF_TARGET_ESP32 + range -1 43 if IDF_TARGET_ESP32S2 + default 21 if LV_PREDEFINED_PINS_TKOALA && LV_TFT_DISPLAY_SPI_TRANS_MODE_QIO default -1 help @@ -819,8 +858,10 @@ menu "LVGL TFT/Epaper Display controller" config LV_DISP_SPI_CLK int "GPIO for CLK (SCK / Serial Clock)" if LV_TFT_DISPLAY_PROTOCOL_SPI + range 0 39 if IDF_TARGET_ESP32 + range 0 43 if IDF_TARGET_ESP32S2 + default 18 if LV_PREDEFINED_DISPLAY_M5STACK || LV_PREDEFINED_DISPLAY_M5STICK - default 18 if LV_PREDEFINED_DISPLAY_M5CORE2 default 13 if LV_PREDEFINED_DISPLAY_M5STICKC default 18 if LV_PREDEFINED_DISPLAY_ATAG default 19 if LV_PREDEFINED_DISPLAY_WROVER4 @@ -844,9 +885,11 @@ menu "LVGL TFT/Epaper Display controller" config LV_DISP_SPI_CS int "GPIO for CS (Slave Select)" if LV_TFT_DISPLAY_PROTOCOL_SPI depends on LV_DISPLAY_USE_SPI_CS + range 0 39 if IDF_TARGET_ESP32 + range 0 43 if IDF_TARGET_ESP32S2 + default 5 if LV_PREDEFINED_PINS_38V1 default 14 if LV_PREDEFINED_DISPLAY_M5STACK || LV_PREDEFINED_DISPLAY_M5STICK - default 5 if LV_PREDEFINED_DISPLAY_M5CORE2 default 5 if LV_PREDEFINED_DISPLAY_M5STICKC default 22 if LV_PREDEFINED_DISPLAY_WROVER4 default 15 if LV_PREDEFINED_DISPLAY_ADA_FEATHERWING @@ -869,11 +912,13 @@ menu "LVGL TFT/Epaper Display controller" config LV_DISP_PIN_DC int "GPIO for DC (Data / Command)" if LV_TFT_DISPLAY_PROTOCOL_SPI + range 0 39 if IDF_TARGET_ESP32 + range 0 43 if IDF_TARGET_ESP32S2 + depends on LV_DISPLAY_USE_DC default 19 if LV_PREDEFINED_PINS_38V1 default 17 if LV_PREDEFINED_PINS_38V4 default 27 if LV_PREDEFINED_DISPLAY_M5STACK || LV_PREDEFINED_DISPLAY_M5STICK - default 15 if LV_PREDEFINED_DISPLAY_M5CORE2 default 23 if LV_PREDEFINED_DISPLAY_M5STICKC default 21 if LV_PREDEFINED_DISPLAY_WROVER4 default 21 if LV_PREDEFINED_DISPLAY_WT32_SC01 @@ -887,22 +932,11 @@ menu "LVGL TFT/Epaper Display controller" help Configure the display DC pin here. - config LV_DISP_USE_RST - bool "Use a GPIO for resetting the display" if LV_TFT_DISPLAY_PROTOCOL_SPI - default n if LV_PREDEFINED_DISPLAY_M5CORE2 - default y - help - Enable display reset control. Set this if the reset pin of the - display is connected to the host. If this is not set, then it is - the user's responsibility to ensure that the display is reset - before initialisation. - You may want to disable this option because the reset pin is not - connected, or is connected to an external component such as the - power management IC. - config LV_DISP_PIN_RST int "GPIO for Reset" if LV_TFT_DISPLAY_PROTOCOL_SPI && !LV_DISP_ST7789_SOFT_RESET - depends on LV_DISP_USE_RST + range 0 39 if IDF_TARGET_ESP32 + range 0 43 if IDF_TARGET_ESP32S2 + default 18 if LV_PREDEFINED_PINS_38V1 default 25 if LV_PREDEFINED_PINS_38V4 default 33 if LV_PREDEFINED_DISPLAY_M5STACK || LV_PREDEFINED_DISPLAY_M5STICK @@ -921,103 +955,84 @@ menu "LVGL TFT/Epaper Display controller" config LV_DISP_PIN_BUSY int "GPIO for Busy" if LV_TFT_DISPLAY_CONTROLLER_IL3820 || LV_TFT_DISPLAY_CONTROLLER_JD79653A || LV_TFT_DISPLAY_CONTROLLER_UC8151D + range 0 39 if IDF_TARGET_ESP32 + range 0 43 if IDF_TARGET_ESP32S2 + default 35 if LV_TFT_DISPLAY_CONTROLLER_IL3820 || LV_TFT_DISPLAY_CONTROLLER_JD79653A || LV_TFT_DISPLAY_CONTROLLER_UC8151D - default 35 if IDF_TARGET_ESP32 || IDF_TARGET_ESP32S2 - default 21 if IDF_TARGET_ESP32C3 + default 35 help Configure the display Busy pin here. - endmenu - - choice - prompt "Select an I2C port for the display" - default LV_I2C_DISPLAY_PORT_0 - depends on LV_I2C_DISPLAY - - config LV_I2C_DISPLAY_PORT_0 - bool - prompt "I2C port 0" + config LV_ENABLE_BACKLIGHT_CONTROL + bool "Enable control of the display backlight by using an GPIO." if \ + ( LV_PREDEFINED_DISPLAY_NONE && ! ( LV_TFT_DISPLAY_CONTROLLER_SH1107 || LV_TFT_DISPLAY_CONTROLLER_SSD1306 ) ) \ + || LV_PREDEFINED_DISPLAY_RPI_MPI3501 + default y if LV_PREDEFINED_DISPLAY_M5STACK + default y if LV_PREDEFINED_DISPLAY_WROVER4 + default y if LV_PREDEFINED_DISPLAY_ERTFT0356 + default y if LV_PREDEFINED_DISPLAY_TTGO + default y if LV_PREDEFINED_DISPLAY_TTGO_CAMERA_PLUS + default y if LV_PREDEFINED_DISPLAY_WT32_SC01 help - I2C is shared peripheral managed by I2C Manager. In order to configure I2C Manager (pinout, etc.) see menu - Component config->I2C Port Settings. - - config LV_I2C_DISPLAY_PORT_1 - bool - prompt "I2C port 1" + Enable controlling the display backlight using an GPIO + + config LV_BACKLIGHT_ACTIVE_LVL + bool "Is backlight turn on with a HIGH (1) logic level?" + depends on LV_ENABLE_BACKLIGHT_CONTROL + default y if LV_PREDEFINED_DISPLAY_M5STACK + default y if LV_PREDEFINED_DISPLAY_ERTFT0356 + default y if LV_PREDEFINED_DISPLAY_TTGO + default y if LV_PREDEFINED_DISPLAY_TTGO_CAMERA_PLUS + default y if LV_PREDEFINED_DISPLAY_WT32_SC01 help - I2C is shared peripheral managed by I2C Manager. In order to configure I2C Manager (pinout, etc.) see menu - Component config->I2C Port Settings. + Some backlights are turned on with a high signal, others held low. + If enabled, a value of 1 will be sent to the display to enable the backlight, + otherwise a 0 will be expected to enable it. + + config LV_DISP_PIN_BCKL + int "GPIO for Backlight Control" + depends on LV_ENABLE_BACKLIGHT_CONTROL + range 0 39 if IDF_TARGET_ESP32 + range 0 43 if IDF_TARGET_ESP32S2 + + default 23 if LV_PREDEFINED_PINS_38V1 + default 26 if LV_PREDEFINED_PINS_38V4 + default 32 if LV_PREDEFINED_DISPLAY_M5STACK + default 5 if LV_PREDEFINED_DISPLAY_WROVER4 + default 2 if LV_PREDEFINED_DISPLAY_ADA_FEATHERWING + default 27 if LV_PREDEFINED_DISPLAY_ERTFT0356 + default 0 if LV_PREDEFINED_PINS_TKOALA + default 4 if LV_PREDEFINED_DISPLAY_TTGO + default 2 if LV_PREDEFINED_DISPLAY_TTGO_CAMERA_PLUS + default 23 if LV_PREDEFINED_DISPLAY_WT32_SC01 + default 27 - endchoice + help + Configure the display BCLK (LED) pin here. - choice - default LV_DISP_BACKLIGHT_SWITCH - prompt "Backlight Control" if \ - (! ( LV_TFT_DISPLAY_CONTROLLER_SH1107 || LV_TFT_DISPLAY_CONTROLLER_SSD1306 ) ) + config LV_DISP_PIN_SDA + int "GPIO for I2C SDA" if LV_TFT_DISPLAY_PROTOCOL_I2C + range 0 39 if IDF_TARGET_ESP32 + range 0 43 if IDF_TARGET_ESP32S2 - config LV_DISP_BACKLIGHT_OFF - bool - prompt "Not Used" - help - Display backlight is not controlled by this driver, must be hardwired in hardware. + default 5 if LV_PREDEFINED_DISPLAY_WEMOS_LOLIN + default 5 - config LV_DISP_BACKLIGHT_SWITCH - bool - prompt "Switch control" help - Display backlight can be switched on or off. + Configure the I2C SDA pin here. - config LV_DISP_BACKLIGHT_PWM - bool - prompt "PWM control" - help - Display backlight is controlled by pulse-width modulation, allowing brightness settings. + config LV_DISP_PIN_SCL + int "GPIO for I2C SCL" if LV_TFT_DISPLAY_PROTOCOL_I2C + range 0 39 if IDF_TARGET_ESP32 + range 0 43 if IDF_TARGET_ESP32S2 - endchoice + default 4 if LV_PREDEFINED_DISPLAY_WEMOS_LOLIN + default 4 - config LV_BACKLIGHT_ACTIVE_LVL - bool "Is backlight turn on with a HIGH (1) logic level?" if \ - ( LV_PREDEFINED_DISPLAY_NONE && ! ( LV_TFT_DISPLAY_CONTROLLER_SH1107 || LV_TFT_DISPLAY_CONTROLLER_SSD1306 ) ) \ - || LV_PREDEFINED_DISPLAY_RPI_MPI3501 - depends on !LV_DISP_BACKLIGHT_OFF - default y if LV_PREDEFINED_DISPLAY_M5STACK - default y if LV_PREDEFINED_DISPLAY_ERTFT0356 - default y if LV_PREDEFINED_DISPLAY_TTGO - default y if LV_PREDEFINED_DISPLAY_TTGO_CAMERA_PLUS - default y if LV_PREDEFINED_DISPLAY_WT32_SC01 - help - Some backlights are turned on with a high signal, others held low. - If enabled, a value of 1 will be sent to the display to enable the backlight, - otherwise a 0 will be expected to enable it. - - config LV_DISP_PIN_BCKL - int "GPIO for Backlight Control" if \ - ( LV_PREDEFINED_DISPLAY_NONE && ! ( LV_TFT_DISPLAY_CONTROLLER_SH1107 || LV_TFT_DISPLAY_CONTROLLER_SSD1306 ) ) \ - || LV_PREDEFINED_DISPLAY_RPI_MPI3501 - depends on !LV_DISP_BACKLIGHT_OFF - default 23 if LV_PREDEFINED_PINS_38V1 - default 26 if LV_PREDEFINED_PINS_38V4 - default 32 if LV_PREDEFINED_DISPLAY_M5STACK - default 5 if LV_PREDEFINED_DISPLAY_WROVER4 - default 2 if LV_PREDEFINED_DISPLAY_ADA_FEATHERWING - default 27 if LV_PREDEFINED_DISPLAY_ERTFT0356 - default 0 if LV_PREDEFINED_PINS_TKOALA - default 4 if LV_PREDEFINED_DISPLAY_TTGO - default 2 if LV_PREDEFINED_DISPLAY_TTGO_CAMERA_PLUS - default 23 if LV_PREDEFINED_DISPLAY_WT32_SC01 - default -1 - - help - Configure the display BCLK (LED) pin here. - - config LV_I2C - bool - default y if LV_I2C_DISPLAY + help + Configure the I2C SCL pin here. - config LV_I2C_DISPLAY_PORT - int - default 1 if LV_I2C_DISPLAY_PORT_1 - default 0 + endmenu endmenu diff --git a/lvgl_tft/calepd_epaper.cpp b/lvgl_tft/calepd_epaper.cpp new file mode 100644 index 00000000..f5fccd9e --- /dev/null +++ b/lvgl_tft/calepd_epaper.cpp @@ -0,0 +1,95 @@ +#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 +EpdSpi io; +Gdey027T91 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 "CalEPD" + +uint16_t flushcalls = 0; + +void delay(uint32_t period_ms) { + vTaskDelay(pdMS_TO_TICKS(period_ms)); +} + +/* Display initialization routine */ +void calepd_init(void) +{ + printf("calepd_init\n"); + display.init(); + display.setMonoMode(true); + display.setRotation(3); + // Partial update test + /* display.fillRect(1,10, display.width(), 20, EPD_BLACK); + display.updateWindow(1,10, display.width(), 20); */ + printf("calEPD done with SPI init\n"); + // 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)); + //delay(10); + } + + /* 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) +{ + // Test using RGB232 + int16_t epd_color = EPD_WHITE; + + // Color setting use: RGB232 + // Only monochrome:All what is not white, turn black + if (color.full<254) { + //if (color.ch.red < 7 && color.ch.green < 7 && color.ch.blue < 7) { + epd_color = EPD_BLACK; + } + display.drawPixel((int16_t)x, (int16_t)y, epd_color); + + //If not drawing anything: Debug to see if this function is called: + //printf("set_px %d %d R:%d G:%d B:%d\n",(int16_t)x,(int16_t)y, color.ch.red, color.ch.green, color.ch.blue); + +} diff --git a/lvgl_tft/calepd_epaper.h b/lvgl_tft/calepd_epaper.h new file mode 100644 index 00000000..087ceb4b --- /dev/null +++ b/lvgl_tft/calepd_epaper.h @@ -0,0 +1,38 @@ +/** + * Display class for generic e-Paper driven by EPDiy class +*/ +#ifndef CALEPD_H +#define CALEPD_H + +#include "freertos/FreeRTOS.h" +#include "freertos/task.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 a2d5f125..fdb416c2 100644 --- a/lvgl_tft/disp_driver.c +++ b/lvgl_tft/disp_driver.c @@ -4,15 +4,18 @@ #include "disp_driver.h" #include "disp_spi.h" -#include "esp_lcd_backlight.h" -#include "sdkconfig.h" -void *disp_driver_init(void) + +void disp_driver_init(void) { #if defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_ILI9341 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_SHARP_DISPLAY_CONTROLLER + sharp_init(); #elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_ILI9481 ili9481_init(); #elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_ILI9488 @@ -25,7 +28,7 @@ void *disp_driver_init(void) st7735s_init(); #elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_HX8357 hx8357_init(); -#elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_ILI9486 +#elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_ILI9486 ili9486_init(); #elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_SH1107 sh1107_init(); @@ -43,35 +46,6 @@ void *disp_driver_init(void) jd79653a_init(); #elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_UC8151D uc8151d_init(); -#elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_ILI9163C - ili9163c_init(); -#elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_PCD8544 - pcd8544_init(); -#endif - - // We still use menuconfig for these settings - // It will be set up during runtime in the future -#if (defined(CONFIG_LV_DISP_BACKLIGHT_SWITCH) || defined(CONFIG_LV_DISP_BACKLIGHT_PWM)) - const disp_backlight_config_t bckl_config = { - .gpio_num = CONFIG_LV_DISP_PIN_BCKL, -#if defined CONFIG_LV_DISP_BACKLIGHT_PWM - .pwm_control = true, -#else - .pwm_control = false, -#endif -#if defined CONFIG_LV_BACKLIGHT_ACTIVE_LVL - .output_invert = false, // Backlight on high -#else - .output_invert = true, // Backlight on low -#endif - .timer_idx = 0, - .channel_idx = 0 // @todo this prevents us from having two PWM controlled displays - }; - disp_backlight_h bckl_handle = disp_backlight_new(&bckl_config); - disp_backlight_set(bckl_handle, 100); - return bckl_handle; -#else - return NULL; #endif } @@ -80,7 +54,11 @@ 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); + epdiy_flush(drv, area, color_map); +#elif defined CONFIG_LV_EPAPER_CALEPD_DISPLAY_CONTROLLER + calepd_flush(drv, area, color_map); +#elif defined CONFIG_LV_SHARP_DISPLAY_CONTROLLER + sharp_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 @@ -111,10 +89,6 @@ void disp_driver_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * jd79653a_lv_fb_flush(drv, area, color_map); #elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_UC8151D uc8151d_lv_fb_flush(drv, area, color_map); -#elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_ILI9163C - ili9163c_flush(drv, area, color_map); -#elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_PCD8544 - pcd8544_flush(drv, area, color_map); #endif } @@ -131,18 +105,22 @@ void disp_driver_rounder(lv_disp_drv_t * disp_drv, lv_area_t * area) jd79653a_lv_rounder_cb(disp_drv, area); #elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_UC8151D uc8151d_lv_rounder_cb(disp_drv, area); -#elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_PCD8544 - pcd8544_rounder(disp_drv, area); +#elif defined CONFIG_LV_SHARP_DISPLAY_CONTROLLER + sharp_rounder(disp_drv, area); #endif } void disp_driver_set_px(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) + lv_color_t color, lv_opa_t opa) { #if defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_SSD1306 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_SHARP_DISPLAY_CONTROLLER + sharp_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 @@ -151,7 +129,5 @@ void disp_driver_set_px(lv_disp_drv_t * disp_drv, uint8_t * buf, lv_coord_t buf_ jd79653a_lv_set_fb_cb(disp_drv, buf, buf_w, x, y, color, opa); #elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_UC8151D uc8151d_lv_set_fb_cb(disp_drv, buf, buf_w, x, y, color, opa); -#elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_PCD8544 - pcd8544_set_px_cb(disp_drv, buf, buf_w, x, y, color, opa); #endif } diff --git a/lvgl_tft/disp_driver.h b/lvgl_tft/disp_driver.h index 1970e423..c986a4ce 100644 --- a/lvgl_tft/disp_driver.h +++ b/lvgl_tft/disp_driver.h @@ -22,6 +22,11 @@ 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_SHARP_DISPLAY_CONTROLLER +#include "lvgl_tft/sharp_mip.h" + #elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_ILI9481 #include "ili9481.h" #elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_ILI9488 @@ -52,10 +57,6 @@ extern "C" { #include "jd79653a.h" #elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_UC8151D #include "uc8151d.h" -#elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_ILI9163C -#include "ili9163c.h" -#elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_PCD8544 -#include "pcd8544.h" #endif /********************* @@ -71,7 +72,7 @@ extern "C" { **********************/ /* Initialize display */ -void *disp_driver_init(void); +void disp_driver_init(void); /* Display flush callback */ void disp_driver_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * color_map); diff --git a/lvgl_tft/disp_spi.c b/lvgl_tft/disp_spi.c index 9b708066..0e4e5486 100644 --- a/lvgl_tft/disp_spi.c +++ b/lvgl_tft/disp_spi.c @@ -310,12 +310,7 @@ static void IRAM_ATTR spi_ready(spi_transaction_t *trans) disp = lv_refr_get_disp_refreshing(); #endif -#if LVGL_VERSION_MAJOR < 8 lv_disp_flush_ready(&disp->driver); -#else - lv_disp_flush_ready(disp->driver); -#endif - } if (chained_post_cb) { diff --git a/lvgl_tft/epdiy_epaper.cpp b/lvgl_tft/epdiy_epaper.cpp new file mode 100644 index 00000000..9fb3ef73 --- /dev/null +++ b/lvgl_tft/epdiy_epaper.cpp @@ -0,0 +1,125 @@ +#include "esp_log.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "epdiy_epaper.h" +#include "epdiy.h" +//#include "epd_highlevel.h" + +EpdiyHighlevelState hl; +uint16_t flushcalls = 0; +uint8_t * framebuffer; +uint8_t temperature = 25; +bool init = true; +// MODE_DU: Fast monochrome | MODE_GC16 slow with 16 grayscales +enum EpdDrawMode updateMode = MODE_DU; + +/* Display initialization routine */ +void epdiy_init(void) +{ + epd_init(&epd_board_v7, &ED097TC2, EPD_LUT_64K); + // Set VCOM for boards that allow to set this in software (in mV). + // This will print an error if unsupported. In this case, + // set VCOM using the hardware potentiometer and delete this line. + epd_set_vcom(1760); + + // Only for older versions epdiy + //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); +} + +/* Suggested by @kisvegabor https://forum.lvgl.io/t/lvgl-port-to-be-used-with-epaper-displays/5630/26 */ +void buf_area_to_framebuffer(const lv_area_t *area, const uint8_t *image_data) { + assert(framebuffer != NULL); + uint8_t *fb_ptr = &framebuffer[area->y1 * epd_width() / 2 + area->x1 / 2]; + lv_coord_t img_w = lv_area_get_width(area); + for(uint32_t y = area->y1; y < area->y2; y++) { + memcpy(fb_ptr, image_data, img_w / 2); + fb_ptr += epd_width() / 2; + image_data += img_w / 2; + } +} + +/* A copy from epd_copy_to_framebuffer with temporary lenght prediction */ +void buf_copy_to_framebuffer(EpdRect image_area, const uint8_t *image_data) { + assert(framebuffer != NULL); + + for (uint32_t i = 0; i < image_area.width * image_area.height; i++) { + uint8_t val = (i % 2) ? (image_data[i / 2] & 0xF0) >> 4 + : image_data[i / 2] & 0x0F; + int xx = image_area.x + i % image_area.width; + if (xx < 0 || xx >= epd_width()) { + continue; + } + int yy = image_area.y + i / image_area.width; + if (yy < 0 || yy >= epd_height()) { + continue; + } + uint8_t *buf_ptr = &framebuffer[yy * epd_width() / 2 + xx / 2]; + if (xx % 2) { + *buf_ptr = (*buf_ptr & 0x0F) | (val << 4); + } else { + *buf_ptr = (*buf_ptr & 0xF0) | val; + } + } +} + +/* Required by LVGL. Sends the color_map to the screen with a partial update */ +void epdiy_flush(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_map) +{ + ++flushcalls; + uint16_t w = lv_area_get_width(area); + uint16_t h = lv_area_get_height(area); + + EpdRect update_area = { + .x = (uint16_t)area->x1, + .y = (uint16_t)area->y1, + .width = w, + .height = h + }; + + uint8_t* buf = (uint8_t *) color_map; + // Buffer debug + /* + for (int index=0; index<400; index++) { + printf("%x ", buf[index]); + } */ + + // UNCOMMENT only one of this options + // SAFE Option with EPDiy copy of epd_copy_to_framebuffer + buf_copy_to_framebuffer(update_area, buf); + + //Faster mode suggested in LVGL forum (Leaves ghosting&prints bad sections / experimental) NOTE: Do NOT use in production + //buf_area_to_framebuffer(area, buf); + + epd_hl_update_area(&hl, updateMode, temperature, update_area); //update_area + + //printf("epdiy_flush %d x:%d y:%d w:%d h:%d\n", flushcalls,(uint16_t)area->x1,(uint16_t)area->y1,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 LVGL Forum (buf_area_to_framebuffer) +*/ +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) +{ + // Test using RGB232 + int16_t epd_color = 255; + if ((int16_t)color.full < 254) { + epd_color = (updateMode==MODE_DU) ? 0 : (int16_t)color.full / 3; + } + + //Instead of using epd_draw_pixel: Set pixel directly in *buf that comes afterwards in flush as *color_map + uint16_t idx = (int16_t)y * buf_w / 2 + (int16_t)x / 2; + if (x % 2) { + buf[idx] = (buf[idx] & 0x0F) | (epd_color & 0xF0); + } else { + buf[idx] = (buf[idx] & 0xF0) | (epd_color >> 4); + } +} diff --git a/lvgl_tft/epdiy_epaper_v1.cpp b/lvgl_tft/epdiy_epaper_v1.cpp new file mode 100644 index 00000000..38cd948f --- /dev/null +++ b/lvgl_tft/epdiy_epaper_v1.cpp @@ -0,0 +1,92 @@ +#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_tft/hx8357.c b/lvgl_tft/hx8357.c index bb9ea58b..ad180fdf 100644 --- a/lvgl_tft/hx8357.c +++ b/lvgl_tft/hx8357.c @@ -160,19 +160,21 @@ static uint8_t displayType = HX8357D; void hx8357_init(void) { //Initialize non-SPI GPIOs - gpio_pad_select_gpio(HX8357_DC); + gpio_pad_select_gpio(HX8357_DC); gpio_set_direction(HX8357_DC, GPIO_MODE_OUTPUT); - -#if HX8357_USE_RST - gpio_pad_select_gpio(HX8357_RST); + gpio_pad_select_gpio(HX8357_RST); gpio_set_direction(HX8357_RST, GPIO_MODE_OUTPUT); +#if HX8357_ENABLE_BACKLIGHT_CONTROL + gpio_pad_select_gpio(HX8357_BCKL); + gpio_set_direction(HX8357_BCKL, GPIO_MODE_OUTPUT); +#endif + //Reset the display gpio_set_level(HX8357_RST, 0); vTaskDelay(10 / portTICK_RATE_MS); gpio_set_level(HX8357_RST, 1); vTaskDelay(120 / portTICK_RATE_MS); -#endif ESP_LOGI(TAG, "Initialization."); @@ -203,6 +205,8 @@ void hx8357_init(void) #else hx8357_send_cmd(HX8357_INVOFF); #endif + + hx8357_enable_backlight(true); } @@ -239,6 +243,23 @@ void hx8357_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * colo hx8357_send_color((void*)color_map, size * 2); } +void hx8357_enable_backlight(bool backlight) +{ +#if HX8357_ENABLE_BACKLIGHT_CONTROL + ESP_LOGD(TAG, "%s backlight.\n", backlight ? "Enabling" : "Disabling"); + uint32_t tmp = 0; + +#if (HX8357_BCKL_ACTIVE_LVL==1) + tmp = backlight ? 1 : 0; +#else + tmp = backlight ? 0 : 1; +#endif + + gpio_set_level(HX8357_BCKL, tmp); +#endif +} + + void hx8357_set_rotation(uint8_t r) { r = r & 3; // can't be higher than 3 diff --git a/lvgl_tft/hx8357.h b/lvgl_tft/hx8357.h index 34cbaf9e..6bad32d9 100644 --- a/lvgl_tft/hx8357.h +++ b/lvgl_tft/hx8357.h @@ -35,10 +35,18 @@ extern "C" { /********************* * DEFINES *********************/ -#define HX8357_DC CONFIG_LV_DISP_PIN_DC -#define HX8357_RST CONFIG_LV_DISP_PIN_RST -#define HX8357_USE_RST CONFIG_LV_DISP_USE_RST -#define HX8357_INVERT_COLORS CONFIG_LV_INVERT_COLORS +#define HX8357_DC CONFIG_LV_DISP_PIN_DC +#define HX8357_RST CONFIG_LV_DISP_PIN_RST +#define HX8357_BCKL CONFIG_LV_DISP_PIN_BCKL + +#define HX8357_ENABLE_BACKLIGHT_CONTROL CONFIG_LV_ENABLE_BACKLIGHT_CONTROL +#define HX8357_INVERT_COLORS CONFIG_LV_INVERT_COLORS + +#if CONFIG_LV_BACKLIGHT_ACTIVE_LVL + #define HX8357_BCKL_ACTIVE_LVL 1 +#else + #define HX8357_BCKL_ACTIVE_LVL 0 +#endif /******************* @@ -127,6 +135,7 @@ extern "C" { void hx8357_init(void); void hx8357_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * color_map); +void hx8357_enable_backlight(bool backlight); void hx8357_set_rotation(uint8_t r); /********************** diff --git a/lvgl_tft/il3820.c b/lvgl_tft/il3820.c index 76432dcf..4295ae0f 100644 --- a/lvgl_tft/il3820.c +++ b/lvgl_tft/il3820.c @@ -73,9 +73,9 @@ static uint8_t il3820_lut_initial[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; static uint8_t il3820_lut_default[] = { - 0x10, 0x18, 0x18, 0x08, 0x18, 0x18, - 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x18, 0x18, 0x08, 0x18, 0x18, + 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x14, 0x44, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; @@ -113,7 +113,7 @@ void il3820_flush(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_m uint8_t *buffer = (uint8_t*) color_map; uint16_t x_addr_counter = 0; uint16_t y_addr_counter = 0; - + /* Configure entry mode */ il3820_write_cmd(IL3820_CMD_ENTRY_MODE, &il3820_scan_mode, 1); @@ -131,7 +131,7 @@ void il3820_flush(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_m il3820_set_cursor(x_addr_counter, y_addr_counter); il3820_send_cmd(IL3820_CMD_WRITE_RAM); - + /* Write the pixel data to graphic RAM, linelen bytes at the time. */ for(size_t row = 0; row <= (EPD_PANEL_HEIGHT - 1); row++){ il3820_send_data(buffer, linelen); @@ -139,7 +139,7 @@ void il3820_flush(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_m } il3820_set_window(0, EPD_PANEL_WIDTH - 1, 0, EPD_PANEL_HEIGHT - 1); - + il3820_update_display(); /* IMPORTANT!!! @@ -152,7 +152,7 @@ void il3820_flush(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_m * BIT_SET(byte_index, bit_index) clears the bit_index pixel at byte_index of * the display buffer. * BIT_CLEAR(byte_index, bit_index) sets the bit_index pixel at the byte_index - * of the display buffer. */ + * of the display buffer. */ void il3820_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) @@ -198,24 +198,20 @@ void il3820_init(void) /* Initialize non-SPI GPIOs */ gpio_pad_select_gpio(IL3820_DC_PIN); gpio_set_direction(IL3820_DC_PIN, GPIO_MODE_OUTPUT); - - gpio_pad_select_gpio(IL3820_BUSY_PIN); - gpio_set_direction(IL3820_BUSY_PIN, GPIO_MODE_INPUT); - -#if IL3820_USE_RST gpio_pad_select_gpio(IL3820_RST_PIN); gpio_set_direction(IL3820_RST_PIN, GPIO_MODE_OUTPUT); + gpio_pad_select_gpio(IL3820_BUSY_PIN); + gpio_set_direction(IL3820_BUSY_PIN, GPIO_MODE_INPUT); /* Harware reset */ gpio_set_level( IL3820_RST_PIN, 0); vTaskDelay(IL3820_RESET_DELAY / portTICK_RATE_MS); gpio_set_level( IL3820_RST_PIN, 1); vTaskDelay(IL3820_RESET_DELAY / portTICK_RATE_MS); -#endif /* Software reset */ il3820_write_cmd(IL3820_CMD_SW_RESET, NULL, 0); - + /* Busy wait for the BUSY signal to go low */ il3820_waitbusy(IL3820_WAIT); @@ -243,10 +239,10 @@ void il3820_init(void) // allow partial updates now il3820_partial = true; - + /* Update LUT */ il3820_write_cmd(IL3820_CMD_UPDATE_LUT, il3820_lut_default, sizeof(il3820_lut_default)); - + /* Clear control memory and update */ il3820_clear_cntlr_mem(IL3820_CMD_WRITE_RAM, true); } @@ -255,10 +251,10 @@ void il3820_init(void) void il3820_sleep_in(void) { uint8_t data[] = {0x01}; - + /* Wait for the BUSY signal to go low */ il3820_waitbusy(IL3820_WAIT); - + il3820_write_cmd(IL3820_CMD_SLEEP_MODE, data, 1); } @@ -268,15 +264,15 @@ static void il3820_waitbusy(int wait_ms) int i = 0; vTaskDelay(10 / portTICK_RATE_MS); // 10ms delay - + for(i = 0; i < (wait_ms * 10); i++) { if(gpio_get_level(IL3820_BUSY_PIN) != IL3820_BUSY_LEVEL) { return; } - + vTaskDelay(10 / portTICK_RATE_MS); } - + ESP_LOGE( TAG, "busy exceeded %dms", i*10 ); } @@ -292,10 +288,10 @@ static inline void il3820_data_mode(void) gpio_set_level(IL3820_DC_PIN, 1); } -static inline void il3820_write_cmd(uint8_t cmd, uint8_t *data, size_t len) +static inline void il3820_write_cmd(uint8_t cmd, uint8_t *data, size_t len) { disp_wait_for_pending_transactions(); - + il3820_command_mode(); disp_spi_send_data(&cmd, 1); @@ -306,10 +302,10 @@ static inline void il3820_write_cmd(uint8_t cmd, uint8_t *data, size_t len) } /* Send cmd to the display */ -static inline void il3820_send_cmd(uint8_t cmd) +static inline void il3820_send_cmd(uint8_t cmd) { disp_wait_for_pending_transactions(); - + il3820_command_mode(); disp_spi_send_data(&cmd, 1); } @@ -318,14 +314,14 @@ static inline void il3820_send_cmd(uint8_t cmd) static void il3820_send_data(uint8_t *data, uint16_t length) { disp_wait_for_pending_transactions(); - + il3820_data_mode(); disp_spi_send_colors(data, length); } /* Specify the start/end positions of the window address in the X and Y * directions by an address unit. - * + * * @param sx: X Start position. * @param ex: X End position. * @param ys: Y Start position. @@ -334,7 +330,7 @@ static void il3820_send_data(uint8_t *data, uint16_t length) static inline void il3820_set_window( uint16_t sx, uint16_t ex, uint16_t ys, uint16_t ye) { uint8_t tmp[4] = {0}; - + tmp[0] = sx / 8; tmp[1] = ex / 8; @@ -382,7 +378,7 @@ static void il3820_update_display(void) } else { tmp = (IL3820_CTRL2_ENABLE_CLK | IL3820_CTRL2_ENABLE_ANALOG | IL3820_CTRL2_TO_PATTERN); } - + il3820_write_cmd(IL3820_CMD_UPDATE_CTRL2, &tmp, 1); il3820_write_cmd(IL3820_CMD_MASTER_ACTIVATION, NULL, 0); @@ -398,10 +394,10 @@ static void il3820_clear_cntlr_mem(uint8_t ram_cmd, bool update) /* Arrays used by SPI must be word alligned */ WORD_ALIGNED_ATTR uint8_t clear_page[IL3820_COLUMNS]; memset(clear_page, 0xff, sizeof clear_page); - + /* Configure entry mode */ il3820_write_cmd(IL3820_CMD_ENTRY_MODE, &il3820_scan_mode, 1); - + /* Configure the window */ il3820_set_window(0, EPD_PANEL_WIDTH - 1, 0, EPD_PANEL_HEIGHT - 1); diff --git a/lvgl_tft/il3820.h b/lvgl_tft/il3820.h index f77ffb4b..e0b73cd6 100644 --- a/lvgl_tft/il3820.h +++ b/lvgl_tft/il3820.h @@ -28,7 +28,6 @@ extern "C" #define IL3820_DC_PIN CONFIG_LV_DISP_PIN_DC #define IL3820_RST_PIN CONFIG_LV_DISP_PIN_RST -#define IL3820_USE_RST CONFIG_LV_DISP_USE_RST #define IL3820_BUSY_PIN CONFIG_LV_DISP_PIN_BUSY #define IL3820_BUSY_LEVEL 1 diff --git a/lvgl_tft/ili9341.c b/lvgl_tft/ili9341.c index e91680f1..faf5546f 100644 --- a/lvgl_tft/ili9341.c +++ b/lvgl_tft/ili9341.c @@ -80,20 +80,31 @@ void ili9341_init(void) {0, {0}, 0xff}, }; +#if ILI9341_BCKL == 15 + gpio_config_t io_conf; + io_conf.intr_type = GPIO_PIN_INTR_DISABLE; + io_conf.mode = GPIO_MODE_OUTPUT; + io_conf.pin_bit_mask = GPIO_SEL_15; + io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE; + io_conf.pull_up_en = GPIO_PULLUP_DISABLE; + gpio_config(&io_conf); +#endif + //Initialize non-SPI GPIOs - gpio_pad_select_gpio(ILI9341_DC); + gpio_pad_select_gpio(ILI9341_DC); gpio_set_direction(ILI9341_DC, GPIO_MODE_OUTPUT); - -#if ILI9341_USE_RST - gpio_pad_select_gpio(ILI9341_RST); + gpio_pad_select_gpio(ILI9341_RST); gpio_set_direction(ILI9341_RST, GPIO_MODE_OUTPUT); +#if ILI9341_ENABLE_BACKLIGHT_CONTROL + gpio_pad_select_gpio(ILI9341_BCKL); + gpio_set_direction(ILI9341_BCKL, GPIO_MODE_OUTPUT); +#endif //Reset the display gpio_set_level(ILI9341_RST, 0); vTaskDelay(100 / portTICK_RATE_MS); gpio_set_level(ILI9341_RST, 1); vTaskDelay(100 / portTICK_RATE_MS); -#endif ESP_LOGI(TAG, "Initialization."); @@ -108,7 +119,9 @@ void ili9341_init(void) cmd++; } - ili9341_set_orientation(CONFIG_LV_DISPLAY_ORIENTATION); + ili9341_enable_backlight(true); + + ili9341_set_orientation(CONFIG_LV_DISPLAY_ORIENTATION); #if ILI9341_INVERT_COLORS == 1 ili9341_send_cmd(0x21); @@ -140,10 +153,29 @@ void ili9341_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * col /*Memory write*/ ili9341_send_cmd(0x2C); + + uint32_t size = lv_area_get_width(area) * lv_area_get_height(area); + ili9341_send_color((void*)color_map, size * 2); } +void ili9341_enable_backlight(bool backlight) +{ +#if ILI9341_ENABLE_BACKLIGHT_CONTROL + ESP_LOGI(TAG, "%s backlight.", backlight ? "Enabling" : "Disabling"); + uint32_t tmp = 0; + +#if (ILI9341_BCKL_ACTIVE_LVL==1) + tmp = backlight ? 1 : 0; +#else + tmp = backlight ? 0 : 1; +#endif + + gpio_set_level(ILI9341_BCKL, tmp); +#endif +} + void ili9341_sleep_in() { uint8_t data[] = {0x08}; @@ -196,8 +228,6 @@ static void ili9341_set_orientation(uint8_t orientation) #if defined CONFIG_LV_PREDEFINED_DISPLAY_M5STACK uint8_t data[] = {0x68, 0x68, 0x08, 0x08}; -#elif defined (CONFIG_LV_PREDEFINED_DISPLAY_M5CORE2) - uint8_t data[] = {0x08, 0x88, 0x28, 0xE8}; #elif defined (CONFIG_LV_PREDEFINED_DISPLAY_WROVER4) uint8_t data[] = {0x6C, 0xEC, 0xCC, 0x4C}; #elif defined (CONFIG_LV_PREDEFINED_DISPLAY_NONE) diff --git a/lvgl_tft/ili9341.h b/lvgl_tft/ili9341.h index 62317e85..4beb4f32 100644 --- a/lvgl_tft/ili9341.h +++ b/lvgl_tft/ili9341.h @@ -20,15 +20,23 @@ extern "C" { #else #include "lvgl/lvgl.h" #endif - -#include "sdkconfig.h" +#include "../lvgl_helpers.h" /********************* * DEFINES *********************/ -#define ILI9341_DC CONFIG_LV_DISP_PIN_DC -#define ILI9341_USE_RST CONFIG_LV_DISP_USE_RST -#define ILI9341_RST CONFIG_LV_DISP_PIN_RST +#define ILI9341_DC CONFIG_LV_DISP_PIN_DC +#define ILI9341_RST CONFIG_LV_DISP_PIN_RST +#define ILI9341_BCKL CONFIG_LV_DISP_PIN_BCKL + +#define ILI9341_ENABLE_BACKLIGHT_CONTROL CONFIG_LV_ENABLE_BACKLIGHT_CONTROL + +#if CONFIG_LV_BACKLIGHT_ACTIVE_LVL + #define ILI9341_BCKL_ACTIVE_LVL 1 +#else + #define ILI9341_BCKL_ACTIVE_LVL 0 +#endif + #define ILI9341_INVERT_COLORS CONFIG_LV_INVERT_COLORS /********************** @@ -41,6 +49,7 @@ extern "C" { void ili9341_init(void); void ili9341_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * color_map); +void ili9341_enable_backlight(bool backlight); void ili9341_sleep_in(void); void ili9341_sleep_out(void); diff --git a/lvgl_tft/ili9481.c b/lvgl_tft/ili9481.c index 74bda98b..6472a932 100644 --- a/lvgl_tft/ili9481.c +++ b/lvgl_tft/ili9481.c @@ -76,17 +76,19 @@ void ili9481_init(void) //Initialize non-SPI GPIOs gpio_pad_select_gpio(ILI9481_DC); gpio_set_direction(ILI9481_DC, GPIO_MODE_OUTPUT); - -#if ILI9481_USE_RST gpio_pad_select_gpio(ILI9481_RST); gpio_set_direction(ILI9481_RST, GPIO_MODE_OUTPUT); +#if ILI9481_ENABLE_BACKLIGHT_CONTROL + gpio_pad_select_gpio(ILI9481_BCKL); + gpio_set_direction(ILI9481_BCKL, GPIO_MODE_OUTPUT); +#endif + //Reset the display gpio_set_level(ILI9481_RST, 0); vTaskDelay(100 / portTICK_RATE_MS); gpio_set_level(ILI9481_RST, 1); vTaskDelay(100 / portTICK_RATE_MS); -#endif ESP_LOGI(TAG, "ILI9481 initialization."); @@ -105,6 +107,8 @@ void ili9481_init(void) cmd++; } + ili9481_enable_backlight(true); + ili9481_set_orientation(ILI9481_DISPLAY_ORIENTATION); } @@ -164,6 +168,22 @@ void ili9481_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * col heap_caps_free(mybuf); } +void ili9481_enable_backlight(bool backlight) +{ +#if ILI9481_ENABLE_BACKLIGHT_CONTROL + ESP_LOGI(TAG, "%s backlight.", backlight ? "Enabling" : "Disabling"); + uint32_t tmp = 0; + +#if (ILI9481_BCKL_ACTIVE_LVL==1) + tmp = backlight ? 1 : 0; +#else + tmp = backlight ? 0 : 1; +#endif + + gpio_set_level(ILI9481_BCKL, tmp); +#endif +} + /********************** * STATIC FUNCTIONS **********************/ diff --git a/lvgl_tft/ili9481.h b/lvgl_tft/ili9481.h index 15623987..79321908 100644 --- a/lvgl_tft/ili9481.h +++ b/lvgl_tft/ili9481.h @@ -25,12 +25,19 @@ extern "C" { /********************* * DEFINES *********************/ -#define ILI9481_DC CONFIG_LV_DISP_PIN_DC -#define ILI9481_RST CONFIG_LV_DISP_PIN_RST -#define ILI9481_USE_RST CONFIG_LV_DISP_USE_RST -#define ILI9481_INVERT_COLORS CONFIG_LV_INVERT_COLORS +#define ILI9481_DC CONFIG_LV_DISP_PIN_DC +#define ILI9481_RST CONFIG_LV_DISP_PIN_RST +#define ILI9481_BCKL CONFIG_LV_DISP_PIN_BCKL + +#define ILI9481_ENABLE_BACKLIGHT_CONTROL CONFIG_LV_ENABLE_BACKLIGHT_CONTROL +#define ILI9481_INVERT_COLORS CONFIG_LV_INVERT_COLORS #define ILI9481_DISPLAY_ORIENTATION CONFIG_LV_DISPLAY_ORIENTATION +#if CONFIG_LV_BACKLIGHT_ACTIVE_LVL + #define ILI9481_BCKL_ACTIVE_LVL 1 +#else + #define ILI9481_BCKL_ACTIVE_LVL 0 +#endif /******************* * ILI9481 REGS @@ -110,6 +117,7 @@ extern "C" { void ili9481_init(void); void ili9481_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * color_map); +void ili9481_enable_backlight(bool backlight); /********************** * MACROS diff --git a/lvgl_tft/ili9486.c b/lvgl_tft/ili9486.c index 829f0bd8..e9b2b083 100644 --- a/lvgl_tft/ili9486.c +++ b/lvgl_tft/ili9486.c @@ -60,25 +60,37 @@ void ili9486_init(void) {0xE0, {0x0F, 0x1F, 0x1C, 0x0C, 0x0F, 0x08, 0x48, 0x98, 0x37, 0x0A, 0x13, 0x04, 0x11, 0x0D, 0x00}, 15}, {0XE1, {0x0F, 0x32, 0x2E, 0x0B, 0x0D, 0x05, 0x47, 0x75, 0x37, 0x06, 0x10, 0x03, 0x24, 0x20, 0x00}, 15}, {0x20, {0}, 0}, /* display inversion OFF */ - {0x36, {0x48}, 1}, - {0x29, {0}, 0x80}, /* display on */ + {0x36, {0x48}, 1}, + {0x29, {0}, 0x80}, /* display on */ {0x00, {0}, 0xff}, }; +#if ILI9486_BCKL == 15 + gpio_config_t io_conf; + io_conf.intr_type = GPIO_PIN_INTR_DISABLE; + io_conf.mode = GPIO_MODE_OUTPUT; + io_conf.pin_bit_mask = GPIO_SEL_15; + io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE; + io_conf.pull_up_en = GPIO_PULLUP_DISABLE; + gpio_config(&io_conf); +#endif + //Initialize non-SPI GPIOs - gpio_pad_select_gpio(ILI9486_DC); + gpio_pad_select_gpio(ILI9486_DC); gpio_set_direction(ILI9486_DC, GPIO_MODE_OUTPUT); - -#if ILI9486_USE_RST - gpio_pad_select_gpio(ILI9486_RST); + gpio_pad_select_gpio(ILI9486_RST); gpio_set_direction(ILI9486_RST, GPIO_MODE_OUTPUT); +#if ILI9486_ENABLE_BACKLIGHT_CONTROL + gpio_pad_select_gpio(ILI9486_BCKL); + gpio_set_direction(ILI9486_BCKL, GPIO_MODE_OUTPUT); +#endif + //Reset the display gpio_set_level(ILI9486_RST, 0); vTaskDelay(100 / portTICK_RATE_MS); gpio_set_level(ILI9486_RST, 1); vTaskDelay(100 / portTICK_RATE_MS); -#endif ESP_LOGI(TAG, "ILI9486 Initialization."); @@ -93,7 +105,9 @@ void ili9486_init(void) cmd++; } - ili9486_set_orientation(CONFIG_LV_DISPLAY_ORIENTATION); + ili9486_enable_backlight(true); + + ili9486_set_orientation(CONFIG_LV_DISPLAY_ORIENTATION); } void ili9486_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * color_map) @@ -121,10 +135,26 @@ void ili9486_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * col ili9486_send_cmd(0x2C); size = lv_area_get_width(area) * lv_area_get_height(area); - + ili9486_send_color((void*) color_map, size * 2); } +void ili9486_enable_backlight(bool backlight) +{ +#if ILI9486_ENABLE_BACKLIGHT_CONTROL + ESP_LOGI(TAG, "%s backlight.", backlight ? "Enabling" : "Disabling"); + uint32_t tmp = 0; + +#if (ILI9486_BCKL_ACTIVE_LVL==1) + tmp = backlight ? 1 : 0; +#else + tmp = backlight ? 0 : 1; +#endif + + gpio_set_level(ILI9486_BCKL, tmp); +#endif +} + /********************** * STATIC FUNCTIONS **********************/ diff --git a/lvgl_tft/ili9486.h b/lvgl_tft/ili9486.h index 0b3f4fb7..f65dd801 100644 --- a/lvgl_tft/ili9486.h +++ b/lvgl_tft/ili9486.h @@ -25,10 +25,17 @@ extern "C" { /********************* * DEFINES *********************/ -#define ILI9486_DC CONFIG_LV_DISP_PIN_DC -#define ILI9486_RST CONFIG_LV_DISP_PIN_RST -#define ILI9486_USE_RST CONFIG_LV_DISP_USE_RST +#define ILI9486_DC CONFIG_LV_DISP_PIN_DC +#define ILI9486_RST CONFIG_LV_DISP_PIN_RST +#define ILI9486_BCKL CONFIG_LV_DISP_PIN_BCKL +#define ILI9486_ENABLE_BACKLIGHT_CONTROL CONFIG_LV_ENABLE_BACKLIGHT_CONTROL + +#if CONFIG_LV_BACKLIGHT_ACTIVE_LVL + #define ILI9486_BCKL_ACTIVE_LVL 1 +#else + #define ILI9486_BCKL_ACTIVE_LVL 0 +#endif /********************** * TYPEDEFS @@ -40,6 +47,7 @@ extern "C" { void ili9486_init(void); void ili9486_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * color_map); +void ili9486_enable_backlight(bool backlight); /********************** * MACROS diff --git a/lvgl_tft/ili9488.c b/lvgl_tft/ili9488.c index feb9fbaf..74f7139b 100644 --- a/lvgl_tft/ili9488.c +++ b/lvgl_tft/ili9488.c @@ -50,7 +50,7 @@ static void ili9488_send_color(void * data, uint16_t length); /********************** * GLOBAL FUNCTIONS **********************/ -// From github.com/jeremyjh/ESP32_TFT_library +// From github.com/jeremyjh/ESP32_TFT_library // From github.com/mvturnho/ILI9488-lvgl-ESP32-WROVER-B void ili9488_init(void) { @@ -76,26 +76,28 @@ void ili9488_init(void) }; //Initialize non-SPI GPIOs - gpio_pad_select_gpio(ILI9488_DC); + gpio_pad_select_gpio(ILI9488_DC); gpio_set_direction(ILI9488_DC, GPIO_MODE_OUTPUT); - -#if ILI9488_USE_RST - gpio_pad_select_gpio(ILI9488_RST); + gpio_pad_select_gpio(ILI9488_RST); gpio_set_direction(ILI9488_RST, GPIO_MODE_OUTPUT); +#if ILI9488_ENABLE_BACKLIGHT_CONTROL + gpio_pad_select_gpio(ILI9488_BCKL); + gpio_set_direction(ILI9488_BCKL, GPIO_MODE_OUTPUT); +#endif + //Reset the display gpio_set_level(ILI9488_RST, 0); vTaskDelay(100 / portTICK_RATE_MS); gpio_set_level(ILI9488_RST, 1); vTaskDelay(100 / portTICK_RATE_MS); -#endif ESP_LOGI(TAG, "ILI9488 initialization."); // Exit sleep ili9488_send_cmd(0x01); /* Software reset */ vTaskDelay(100 / portTICK_RATE_MS); - + //Send all the commands uint16_t cmd = 0; while (ili_init_cmds[cmd].databytes!=0xff) { @@ -107,7 +109,9 @@ void ili9488_init(void) cmd++; } - ili9488_set_orientation(CONFIG_LV_DISPLAY_ORIENTATION); + ili9488_enable_backlight(true); + + ili9488_set_orientation(CONFIG_LV_DISPLAY_ORIENTATION); } // Flush function based on mvturnho repo @@ -142,7 +146,7 @@ void ili9488_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * col (uint8_t) (area->x2 >> 8) & 0xFF, (uint8_t) (area->x2) & 0xFF, }; - + /* Page addresses */ uint8_t yb[] = { (uint8_t) (area->y1 >> 8) & 0xFF, @@ -166,6 +170,22 @@ void ili9488_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * col heap_caps_free(mybuf); } +void ili9488_enable_backlight(bool backlight) +{ +#if ILI9488_ENABLE_BACKLIGHT_CONTROL + ESP_LOGI(TAG, "%s backlight.", backlight ? "Enabling" : "Disabling"); + uint32_t tmp = 0; + +#if (ILI9488_BCKL_ACTIVE_LVL==1) + tmp = backlight ? 1 : 0; +#else + tmp = backlight ? 0 : 1; +#endif + + gpio_set_level(ILI9488_BCKL, tmp); +#endif +} + /********************** * STATIC FUNCTIONS **********************/ diff --git a/lvgl_tft/ili9488.h b/lvgl_tft/ili9488.h index 1c6c6f93..45a70454 100644 --- a/lvgl_tft/ili9488.h +++ b/lvgl_tft/ili9488.h @@ -25,9 +25,17 @@ extern "C" { /********************* * DEFINES *********************/ -#define ILI9488_DC CONFIG_LV_DISP_PIN_DC -#define ILI9488_RST CONFIG_LV_DISP_PIN_RST -#define ILI9488_USE_RST CONFIG_LV_DISP_USE_RSTS +#define ILI9488_DC CONFIG_LV_DISP_PIN_DC +#define ILI9488_RST CONFIG_LV_DISP_PIN_RST +#define ILI9488_BCKL CONFIG_LV_DISP_PIN_BCKL + +#define ILI9488_ENABLE_BACKLIGHT_CONTROL CONFIG_LV_ENABLE_BACKLIGHT_CONTROL + +#if CONFIG_LV_BACKLIGHT_ACTIVE_LVL + #define ILI9488_BCKL_ACTIVE_LVL 1 +#else + #define ILI9488_BCKL_ACTIVE_LVL 0 +#endif /******************* * ILI9488 REGS @@ -146,6 +154,7 @@ typedef struct { void ili9488_init(void); void ili9488_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * color_map); +void ili9488_enable_backlight(bool backlight); /********************** * MACROS diff --git a/lvgl_tft/ra8875.c b/lvgl_tft/ra8875.c index b4f8e2ac..98eea028 100644 --- a/lvgl_tft/ra8875.c +++ b/lvgl_tft/ra8875.c @@ -148,18 +148,29 @@ void ra8875_init(void) ESP_LOGI(TAG, "Initializing RA8875..."); - // Initialize non-SPI GPIOs +#if (CONFIG_LV_DISP_PIN_BCKL == 15) + gpio_config_t io_conf; + io_conf.intr_type = GPIO_PIN_INTR_DISABLE; + io_conf.mode = GPIO_MODE_OUTPUT; + io_conf.pin_bit_mask = GPIO_SEL_15; + io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE; + io_conf.pull_up_en = GPIO_PULLUP_DISABLE; + gpio_config(&io_conf); +#endif -#if RA8875_USE_RST + // Initialize non-SPI GPIOs gpio_pad_select_gpio(RA8875_RST); gpio_set_direction(RA8875_RST, GPIO_MODE_OUTPUT); +#ifdef CONFIG_LV_DISP_PIN_BCKL + gpio_pad_select_gpio(CONFIG_LV_DISP_PIN_BCKL); + gpio_set_direction(CONFIG_LV_DISP_PIN_BCKL, GPIO_MODE_OUTPUT); +#endif // Reset the RA8875 gpio_set_level(RA8875_RST, 0); vTaskDelay(DIV_ROUND_UP(100, portTICK_RATE_MS)); gpio_set_level(RA8875_RST, 1); vTaskDelay(DIV_ROUND_UP(100, portTICK_RATE_MS)); -#endif // Initalize RA8875 clocks (SPI must be decelerated before initializing clocks) disp_spi_change_device_speed(SPI_CLOCK_SPEED_SLOW_HZ); @@ -183,8 +194,28 @@ void ra8875_init(void) ESP_LOGW(TAG, "WARNING: Memory clear timed out; RA8875 may be unresponsive."); } - // Enable the display + // Enable the display and backlight ra8875_enable_display(true); + ra8875_enable_backlight(true); +} + +void ra8875_enable_backlight(bool backlight) +{ +#if CONFIG_LV_ENABLE_BACKLIGHT_CONTROL + ESP_LOGI(TAG, "%s backlight.", backlight ? "Enabling" : "Disabling"); + uint32_t tmp = 0; + + #if CONFIG_LV_BACKLIGHT_ACTIVE_LVL + tmp = backlight ? 1 : 0; + #else + tmp = backlight ? 0 : 1; + #endif + +#ifdef CONFIG_LV_DISP_PIN_BCKL + gpio_set_level(CONFIG_LV_DISP_PIN_BCKL, tmp); +#endif + +#endif } void ra8875_enable_display(bool enable) diff --git a/lvgl_tft/ra8875.h b/lvgl_tft/ra8875.h index 28c77f9d..a6d1fe5d 100644 --- a/lvgl_tft/ra8875.h +++ b/lvgl_tft/ra8875.h @@ -24,8 +24,7 @@ extern "C" { /********************* * DEFINES *********************/ -#define RA8875_RST CONFIG_LV_DISP_PIN_RST -#define RA8875_USE_RST CONFIG_LV_DISP_USE_RST +#define RA8875_RST CONFIG_LV_DISP_PIN_RST // System & Configuration Registers #define RA8875_REG_PWRR (0x01) // Power and Display Control Register (PWRR) @@ -97,6 +96,7 @@ extern "C" { **********************/ void ra8875_init(void); +void ra8875_enable_backlight(bool backlight); void ra8875_enable_display(bool enable); void ra8875_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * color_map); diff --git a/lvgl_tft/sh1107.c b/lvgl_tft/sh1107.c index d7f60676..d8d8c848 100644 --- a/lvgl_tft/sh1107.c +++ b/lvgl_tft/sh1107.c @@ -94,8 +94,6 @@ void sh1107_init(void) //Initialize non-SPI GPIOs gpio_pad_select_gpio(SH1107_DC); gpio_set_direction(SH1107_DC, GPIO_MODE_OUTPUT); - -#if SH1107_USE_RST gpio_pad_select_gpio(SH1107_RST); gpio_set_direction(SH1107_RST, GPIO_MODE_OUTPUT); @@ -104,7 +102,6 @@ void sh1107_init(void) vTaskDelay(100 / portTICK_RATE_MS); gpio_set_level(SH1107_RST, 1); vTaskDelay(100 / portTICK_RATE_MS); -#endif //Send all the commands uint16_t cmd = 0; diff --git a/lvgl_tft/sh1107.h b/lvgl_tft/sh1107.h index ba77a618..7a0db68b 100644 --- a/lvgl_tft/sh1107.h +++ b/lvgl_tft/sh1107.h @@ -25,9 +25,8 @@ extern "C" { /********************* * DEFINES *********************/ -#define SH1107_DC CONFIG_LV_DISP_PIN_DC -#define SH1107_RST CONFIG_LV_DISP_PIN_RST -#define SH1107_USE_RST CONFIG_LV_DISP_USE_RST +#define SH1107_DC CONFIG_LV_DISP_PIN_DC +#define SH1107_RST CONFIG_LV_DISP_PIN_RST /********************** * TYPEDEFS diff --git a/lvgl_tft/sharp_mip.cpp b/lvgl_tft/sharp_mip.cpp new file mode 100644 index 00000000..ad8d3aa6 --- /dev/null +++ b/lvgl_tft/sharp_mip.cpp @@ -0,0 +1,110 @@ +#include "esp_log.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "driver/gpio.h" + +#include "sharp_mip.h" +#include + +/** test Display dimensions + * Do not forget to set: menuconfig -> Components -> LVGL configuration + * Max. Horizontal resolution 400 -> WIDTH of your LCD + * Max. Vertical resolution 240 -> HEIGHT + */ + +/* + * Return the draw_buf byte index corresponding to the pixel + * relatives coordinates (x, y) in the area. + * The area is rounded to a whole screen line. + */ +#define BUFIDX(x, y) (((x) >> 3) + ((y) * (2 + (LV_HOR_RES_MAX >> 3))) + 2) + +// SHARP LCD Class +// PCB Pins for LCD SPI +#define SHARP_SCK 6 +#define SHARP_MOSI 0 +#define SHARP_SS 7 + +// External COM Inversion Signal +#define LCD_EXTMODE GPIO_NUM_3 +#define LCD_DISP GPIO_NUM_2 +// Set the size of the display here, e.g. 128x128 +Adafruit_SharpMem display(SHARP_SCK, SHARP_MOSI, SHARP_SS, LV_HOR_RES_MAX, LV_VER_RES_MAX); + +/********************* + * DEFINES + *********************/ +#define TAG "SHARP" + +uint16_t flushcalls = 0; + +void delay(uint32_t period_ms) { + vTaskDelay(pdMS_TO_TICKS(period_ms)); +} + +/* Display initialization routine */ +void sharp_init(void) +{ + printf("SHAROP LCD init\n"); + // Display pins config + gpio_set_direction(LCD_EXTMODE, GPIO_MODE_OUTPUT); + gpio_set_direction(LCD_DISP, GPIO_MODE_OUTPUT);// Display On(High)/Off(Low) + gpio_set_level(LCD_DISP, 1); + gpio_set_level(LCD_EXTMODE, 1); + display.begin(); +} + +/** + * @brief rounds area before writing + * + * @param disp_drv + * @param area + * @deprecated + */ +void sharp_mip_rounder(lv_disp_drv_t * disp_drv, lv_area_t * area) { + /* Round area to the whole LINE */ + area->x1 = 0; + area->x2 = LV_HOR_RES_MAX - 1; +} + +/* Required by LVGL */ +void sharp_flush(lv_disp_drv_t *drv, lv_area_t *area, lv_color_t *color_map) +{ + /* Round area to the whole LINE */ + /* area->x1 = 0; + area->x2 = LV_HOR_RES_MAX - 1; */ + //lv_refr_set_round_cb(sharp_mip_rounder); // NOT applicable to this version of LVGL + // FORCE Flushing Whole display (Really unnecesary, just a demo, since I don't know how to refresh an *LCD partial only*) + + ++flushcalls; + // x2:%d y2:%d + printf("flush %d x1:%d y1:%d x2:%d y2:%d w:%d h:%d\n", + flushcalls,area->x1,area->y1,area->x2,area->y2,lv_area_get_width(area),lv_area_get_height(area)); + + // FULL Refresh does not work nice unless you force it on newer versions of LVGL (see lv_refr_set_round_cb) + //display.refresh(); + display.refreshLines(area->x1, area->x1, area->y1,area->y2); + /* IMPORTANT: + * Inform the graphics library that you are ready with the flushing */ + lv_disp_flush_ready(drv); +} + +/* Called for each pixel */ +void sharp_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) +{ + // Test using RGB232: Otherwise you can directly use color.full if MONOCHROME + int16_t lcd_color = 1; // WHITE + + // Color setting use: RGB232 + // Only monochrome: All what is not white, turn black + if (color.full<254) { + lcd_color = 0; + } + display.drawPixel((int16_t)x, (int16_t)y, lcd_color); + + //If not drawing anything: Debug to see if this function is called: + //printf("set_px %d %d R:%d G:%d B:%d\n",(int16_t)x,(int16_t)y, color.ch.red, color.ch.green, color.ch.blue); + +} diff --git a/lvgl_tft/sharp_mip.h b/lvgl_tft/sharp_mip.h new file mode 100644 index 00000000..c334b080 --- /dev/null +++ b/lvgl_tft/sharp_mip.h @@ -0,0 +1,35 @@ +/** + * Display class for generic e-Paper driven by EPDiy class +*/ +#pragma once + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +#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 sharp_init(void); + +/* LVGL callbacks */ +void sharp_flush(lv_disp_drv_t *drv, 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 sharp_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); + +void sharp_rounder(lv_disp_drv_t * disp_drv, lv_area_t * area); +#ifdef __cplusplus +} /* extern "C" */ +#endif + diff --git a/lvgl_tft/ssd1306.c b/lvgl_tft/ssd1306.c index c845eac6..43e5966c 100644 --- a/lvgl_tft/ssd1306.c +++ b/lvgl_tft/ssd1306.c @@ -13,9 +13,10 @@ /********************* * INCLUDES *********************/ +#include "driver/i2c.h" #include "assert.h" -#include "lvgl_i2c/i2c_manager.h" +#include "lvgl_i2c_conf.h" #include "ssd1306.h" @@ -24,7 +25,6 @@ *********************/ #define TAG "SSD1306" -#define OLED_I2C_PORT (CONFIG_LV_I2C_DISPLAY_PORT) // SLA (0x3C) + WRITE_MODE (0x00) = 0x78 (0b01111000) #define OLED_I2C_ADDRESS 0x3C #define OLED_WIDTH 128 @@ -70,6 +70,8 @@ // Charge Pump (pg.62) #define OLED_CMD_SET_CHARGE_PUMP 0x8D // follow with 0x14 +#define OLED_IIC_FREQ_HZ 400000 // I2C colock frequency + /********************** * TYPEDEFS **********************/ @@ -99,10 +101,10 @@ void ssd1306_init(void) uint8_t orientation_1 = 0; uint8_t orientation_2 = 0; -#if defined (CONFIG_LV_DISPLAY_ORIENTATION_LANDSCAPE) +#if defined (CONFIG_DISPLAY_ORIENTATION_LANDSCAPE) orientation_1 = OLED_CMD_SET_SEGMENT_REMAP; orientation_2 = OLED_CMD_SET_COM_SCAN_MODE_REMAP; -#elif defined (CONFIG_LV_DISPLAY_ORIENTATION_LANDSCAPE_INVERTED) +#elif defined (CONFIG_DISPLAY_ORIENTATION_LANDSCAPE_INVERTED) orientation_1 = 0xA0; orientation_2 = OLED_CMD_SET_COM_SCAN_MODE_NORMAL; #else @@ -211,15 +213,44 @@ void ssd1306_sleep_out(void) static uint8_t send_data(lv_disp_drv_t *disp_drv, void *bytes, size_t bytes_len) { (void) disp_drv; + esp_err_t err; uint8_t *data = (uint8_t *) bytes; - return lvgl_i2c_write(OLED_I2C_PORT, OLED_I2C_ADDRESS, data[0], data + 1, bytes_len - 1 ); + i2c_cmd_handle_t cmd = i2c_cmd_link_create(); + + i2c_master_start(cmd); + i2c_master_write_byte(cmd, (OLED_I2C_ADDRESS << 1) | I2C_MASTER_WRITE, true); + + for (size_t idx = 0; idx < bytes_len; idx++) { + i2c_master_write_byte(cmd, data[idx], true); + } + + i2c_master_stop(cmd); + + /* Send queued commands */ + err = i2c_master_cmd_begin(DISP_I2C_PORT, cmd, 10 / portTICK_PERIOD_MS); + i2c_cmd_link_delete(cmd); + + return ESP_OK == err ? 0 : 1; } static uint8_t send_pixels(lv_disp_drv_t *disp_drv, void *color_buffer, size_t buffer_len) { (void) disp_drv; + esp_err_t err; + + i2c_cmd_handle_t cmd = i2c_cmd_link_create(); + i2c_master_start(cmd); + i2c_master_write_byte(cmd, (OLED_I2C_ADDRESS << 1) | I2C_MASTER_WRITE, true); + + i2c_master_write_byte(cmd, OLED_CONTROL_BYTE_DATA_STREAM, true); + i2c_master_write(cmd, (uint8_t *) color_buffer, buffer_len, true); + i2c_master_stop(cmd); + + /* Send queued commands */ + err = i2c_master_cmd_begin(DISP_I2C_PORT, cmd, 10 / portTICK_PERIOD_MS); + i2c_cmd_link_delete(cmd); - return lvgl_i2c_write(OLED_I2C_PORT, OLED_I2C_ADDRESS, OLED_CONTROL_BYTE_DATA_STREAM, color_buffer, buffer_len); + return ESP_OK == err ? 0 : 1; } diff --git a/lvgl_tft/ssd1306.h b/lvgl_tft/ssd1306.h index 62bd0e69..21454931 100644 --- a/lvgl_tft/ssd1306.h +++ b/lvgl_tft/ssd1306.h @@ -25,6 +25,8 @@ extern "C" { /********************* * DEFINES *********************/ +#define SSD1306_SDA CONFIG_LV_DISP_PIN_SDA +#define SSD1306_SCL CONFIG_LV_DISP_PIN_SCL #define SSD1306_DISPLAY_ORIENTATION TFT_ORIENTATION_LANDSCAPE /********************** diff --git a/lvgl_tft/st7735s.c b/lvgl_tft/st7735s.c index 8be725be..861904c0 100644 --- a/lvgl_tft/st7735s.c +++ b/lvgl_tft/st7735s.c @@ -8,15 +8,12 @@ *********************/ #include "st7735s.h" #include "disp_spi.h" +#include "driver/i2c.h" #include "driver/gpio.h" #include "esp_log.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" -#ifdef CONFIG_LV_M5STICKC_HANDLE_AXP192 - #include "lvgl_i2c/i2c_manager.h" -#endif - /********************* * DEFINES *********************/ @@ -41,6 +38,7 @@ static void st7735s_send_cmd(uint8_t cmd); static void st7735s_send_data(void * data, uint16_t length); static void st7735s_send_color(void * data, uint16_t length); static void st7735s_set_orientation(uint8_t orientation); +static void i2c_master_init(); static void axp192_write_byte(uint8_t addr, uint8_t data); static void axp192_init(); static void axp192_sleep_in(); @@ -62,6 +60,7 @@ uint8_t st7735s_portrait_mode = 0; void st7735s_init(void) { #ifdef CONFIG_LV_M5STICKC_HANDLE_AXP192 + i2c_master_init(); axp192_init(); #endif @@ -100,8 +99,6 @@ void st7735s_init(void) //Initialize non-SPI GPIOs gpio_pad_select_gpio(ST7735S_DC); gpio_set_direction(ST7735S_DC, GPIO_MODE_OUTPUT); - -#if ST7735S_USE_RST gpio_pad_select_gpio(ST7735S_RST); gpio_set_direction(ST7735S_RST, GPIO_MODE_OUTPUT); @@ -110,7 +107,6 @@ void st7735s_init(void) vTaskDelay(100 / portTICK_RATE_MS); gpio_set_level(ST7735S_RST, 1); vTaskDelay(100 / portTICK_RATE_MS); -#endif ESP_LOGI(TAG, "ST7735S initialization."); @@ -164,16 +160,12 @@ void st7735s_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * col void st7735s_sleep_in() { st7735s_send_cmd(0x10); - #ifdef CONFIG_LV_M5STICKC_HANDLE_AXP192 - axp192_sleep_in(); - #endif + axp192_sleep_in(); } void st7735s_sleep_out() { - #ifdef CONFIG_LV_M5STICKC_HANDLE_AXP192 - axp192_sleep_out(); - #endif + axp192_sleep_out(); st7735s_send_cmd(0x11); } @@ -223,35 +215,55 @@ static void st7735s_set_orientation(uint8_t orientation) st7735s_send_data((void *) &data[orientation], 1); } -#ifdef CONFIG_LV_M5STICKC_HANDLE_AXP192 +static void i2c_master_init() +{ + i2c_config_t i2c_config = { + .mode = I2C_MODE_MASTER, + .sda_io_num = AXP192_SDA, + .scl_io_num = AXP192_SCL, + .sda_pullup_en = GPIO_PULLUP_ENABLE, + .scl_pullup_en = GPIO_PULLUP_ENABLE, + .master.clk_speed = 400000 + }; + i2c_param_config(I2C_NUM_0, &i2c_config); + i2c_driver_install(I2C_NUM_0, I2C_MODE_MASTER, 0, 0, 0); +} - static void axp192_write_byte(uint8_t addr, uint8_t data) - { - err = lvgl_i2c_write(CONFIG_LV_I2C_DISPLAY_PORT, AXP192_I2C_ADDRESS, addr, &data, 1); - if (ret != ESP_OK) { - ESP_LOGE(TAG, "AXP192 send failed. code: 0x%.2X", ret); - } - } - - static void axp192_init() - { - // information on how to init and use AXP192 ifor M5StickC taken from - // https://forum.m5stack.com/topic/1025/m5stickc-turn-off-screen-completely - - axp192_write_byte(0x10, 0xFF); // OLED_VPP Enable - axp192_write_byte(0x28, 0xCC); // Enable LDO2&LDO3, LED&TFT 3.0V - axp192_sleep_out(); - ESP_LOGI(TAG, "AXP192 initialized, power enabled for LDO2 and LDO3"); - } - - static void axp192_sleep_in() - { - axp192_write_byte(0x12, 0x4b); - } - - static void axp192_sleep_out() - { - axp192_write_byte(0x12, 0x4d); - } +static void axp192_write_byte(uint8_t addr, uint8_t data) +{ + esp_err_t ret; + i2c_cmd_handle_t cmd = i2c_cmd_link_create(); + + i2c_master_start(cmd); + i2c_master_write_byte(cmd, (AXP192_I2C_ADDRESS << 1) | I2C_MASTER_WRITE, true); + i2c_master_write_byte(cmd, addr, true); + i2c_master_write_byte(cmd, data, true); + i2c_master_stop(cmd); + + ret = i2c_master_cmd_begin(I2C_NUM_0, cmd, 10/portTICK_PERIOD_MS); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "AXP192 send failed. code: 0x%.2X", ret); + } + i2c_cmd_link_delete(cmd); +} -#endif +static void axp192_init() +{ + // information on how to init and use AXP192 ifor M5StickC taken from + // https://forum.m5stack.com/topic/1025/m5stickc-turn-off-screen-completely + + axp192_write_byte(0x10, 0xFF); // OLED_VPP Enable + axp192_write_byte(0x28, 0xCC); // Enable LDO2&LDO3, LED&TFT 3.0V + axp192_sleep_out(); + ESP_LOGI(TAG, "AXP192 initialized, power enabled for LDO2 and LDO3"); +} + +static void axp192_sleep_in() +{ + axp192_write_byte(0x12, 0x4b); +} + +static void axp192_sleep_out() +{ + axp192_write_byte(0x12, 0x4d); +} diff --git a/lvgl_tft/st7735s.h b/lvgl_tft/st7735s.h index 2d02ed05..de471409 100644 --- a/lvgl_tft/st7735s.h +++ b/lvgl_tft/st7735s.h @@ -25,9 +25,11 @@ extern "C" { *********************/ #define DISP_BUF_SIZE (LV_HOR_RES_MAX * 40) -#define ST7735S_DC CONFIG_LV_DISP_PIN_DC -#define ST7735S_RST CONFIG_LV_DISP_PIN_RST -#define ST7735S_USE_RST CONFIG_LV_DISP_USE_RST +#define ST7735S_DC CONFIG_LV_DISP_PIN_DC +#define ST7735S_RST CONFIG_LV_DISP_PIN_RST + +#define AXP192_SDA CONFIG_LV_AXP192_PIN_SDA +#define AXP192_SCL CONFIG_LV_AXP192_PIN_SCL #define ST7735S_INVERT_COLORS CONFIG_LV_INVERT_COLORS @@ -131,6 +133,7 @@ extern "C" { void st7735s_init(void); void st7735s_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * color_map); +void st7735s_enable_backlight(bool backlight); void st7735s_sleep_in(void); void st7735s_sleep_out(void); diff --git a/lvgl_tft/st7789.c b/lvgl_tft/st7789.c index de7b35aa..2b5bd7ee 100644 --- a/lvgl_tft/st7789.c +++ b/lvgl_tft/st7789.c @@ -35,7 +35,9 @@ typedef struct { **********************/ static void st7789_set_orientation(uint8_t orientation); -static void st7789_send_color(void *data, size_t length); +static void st7789_send_cmd(uint8_t cmd); +static void st7789_send_data(void *data, uint16_t length); +static void st7789_send_color(void *data, uint16_t length); /********************** * STATIC VARIABLES @@ -89,13 +91,18 @@ void st7789_init(void) gpio_pad_select_gpio(ST7789_DC); gpio_set_direction(ST7789_DC, GPIO_MODE_OUTPUT); -#if !defined(ST7789_SOFT_RST) +#if !defined(CONFIG_LV_DISP_ST7789_SOFT_RESET) gpio_pad_select_gpio(ST7789_RST); gpio_set_direction(ST7789_RST, GPIO_MODE_OUTPUT); #endif +#if ST7789_ENABLE_BACKLIGHT_CONTROL + gpio_pad_select_gpio(ST7789_BCKL); + gpio_set_direction(ST7789_BCKL, GPIO_MODE_OUTPUT); +#endif + //Reset the display -#if !defined(ST7789_SOFT_RST) +#if !defined(CONFIG_LV_DISP_ST7789_SOFT_RESET) gpio_set_level(ST7789_RST, 0); vTaskDelay(100 / portTICK_RATE_MS); gpio_set_level(ST7789_RST, 1); @@ -117,12 +124,30 @@ void st7789_init(void) cmd++; } + st7789_enable_backlight(true); + st7789_set_orientation(CONFIG_LV_DISPLAY_ORIENTATION); } -/* The ST7789 display controller can drive up to 320*240 displays, when using a 240*240 or 240*135 - * displays there's a gap of 80px or 40/52/53px respectively. 52px or 53x offset depends on display orientation. - * We need to edit the coordinates to take into account those gaps, this is not necessary in all orientations. */ +void st7789_enable_backlight(bool backlight) +{ +#if ST7789_ENABLE_BACKLIGHT_CONTROL + printf("%s backlight.\n", backlight ? "Enabling" : "Disabling"); + uint32_t tmp = 0; + +#if (ST7789_BCKL_ACTIVE_LVL==1) + tmp = backlight ? 1 : 0; +#else + tmp = backlight ? 0 : 1; +#endif + + gpio_set_level(ST7789_BCKL, tmp); +#endif +} + +/* The ST7789 display controller can drive 320*240 displays, when using a 240*240 + * display there's a gap of 80px, we need to edit the coordinates to take into + * account that gap, this is not necessary in all orientations. */ void st7789_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * color_map) { uint8_t data[4] = {0}; @@ -139,29 +164,13 @@ void st7789_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * colo offsety2 += CONFIG_LV_TFT_DISPLAY_Y_OFFSET; #elif (LV_HOR_RES_MAX == 240) && (LV_VER_RES_MAX == 240) - #if (CONFIG_LV_DISPLAY_ORIENTATION_PORTRAIT) - offsetx1 += 80; - offsetx2 += 80; - #elif (CONFIG_LV_DISPLAY_ORIENTATION_LANDSCAPE_INVERTED) - offsety1 += 80; - offsety2 += 80; - #endif -#elif (LV_HOR_RES_MAX == 240) && (LV_VER_RES_MAX == 135) - #if (CONFIG_LV_DISPLAY_ORIENTATION_PORTRAIT) || \ - (CONFIG_LV_DISPLAY_ORIENTATION_PORTRAIT_INVERTED) - offsetx1 += 40; - offsetx2 += 40; - offsety1 += 53; - offsety2 += 53; - #endif -#elif (LV_HOR_RES_MAX == 135) && (LV_VER_RES_MAX == 240) - #if (CONFIG_LV_DISPLAY_ORIENTATION_LANDSCAPE) || \ - (CONFIG_LV_DISPLAY_ORIENTATION_LANDSCAPE_INVERTED) - offsetx1 += 52; - offsetx2 += 52; - offsety1 += 40; - offsety2 += 40; - #endif +#if (CONFIG_LV_DISPLAY_ORIENTATION_PORTRAIT) + offsetx1 += 80; + offsetx2 += 80; +#elif (CONFIG_LV_DISPLAY_ORIENTATION_LANDSCAPE_INVERTED) + offsety1 += 80; + offsety2 += 80; +#endif #endif /*Column addresses*/ @@ -183,7 +192,7 @@ void st7789_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * colo /*Memory write*/ st7789_send_cmd(ST7789_RAMWR); - size_t size = (size_t)lv_area_get_width(area) * (size_t)lv_area_get_height(area); + uint32_t size = lv_area_get_width(area) * lv_area_get_height(area); st7789_send_color((void*)color_map, size * 2); @@ -192,21 +201,21 @@ void st7789_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * colo /********************** * STATIC FUNCTIONS **********************/ -void st7789_send_cmd(uint8_t cmd) +static void st7789_send_cmd(uint8_t cmd) { disp_wait_for_pending_transactions(); gpio_set_level(ST7789_DC, 0); disp_spi_send_data(&cmd, 1); } -void st7789_send_data(void * data, uint16_t length) +static void st7789_send_data(void * data, uint16_t length) { disp_wait_for_pending_transactions(); gpio_set_level(ST7789_DC, 1); disp_spi_send_data(data, length); } -static void st7789_send_color(void * data, size_t length) +static void st7789_send_color(void * data, uint16_t length) { disp_wait_for_pending_transactions(); gpio_set_level(ST7789_DC, 1); diff --git a/lvgl_tft/st7789.h b/lvgl_tft/st7789.h index cacb31ba..31753299 100644 --- a/lvgl_tft/st7789.h +++ b/lvgl_tft/st7789.h @@ -23,17 +23,17 @@ extern "C" #define ST7789_DC CONFIG_LV_DISP_PIN_DC #define ST7789_RST CONFIG_LV_DISP_PIN_RST +#define ST7789_BCKL CONFIG_LV_DISP_PIN_BCKL -#if CONFIG_LV_DISP_USE_RST - #if CONFIG_LV_DISP_ST7789_SOFT_RESET - #define ST7789_SOFT_RST - #endif +#define ST7789_ENABLE_BACKLIGHT_CONTROL CONFIG_LV_ENABLE_BACKLIGHT_CONTROL +#define ST7789_INVERT_COLORS CONFIG_LV_INVERT_COLORS + +#if CONFIG_LV_BACKLIGHT_ACTIVE_LVL + #define ST7789_BCKL_ACTIVE_LVL 1 #else - #define ST7789_SOFT_RST + #define ST7789_BCKL_ACTIVE_LVL 0 #endif -#define ST7789_INVERT_COLORS CONFIG_LV_INVERT_COLORS - /* ST7789 commands */ #define ST7789_NOP 0x00 #define ST7789_SWRESET 0x01 @@ -112,9 +112,7 @@ extern "C" void st7789_init(void); void st7789_flush(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_map); - -void st7789_send_cmd(uint8_t cmd); -void st7789_send_data(void *data, uint16_t length); +void st7789_enable_backlight(bool backlight); #ifdef __cplusplus } /* extern "C" */ diff --git a/lvgl_tft/st7796s.c b/lvgl_tft/st7796s.c index 7de92ef0..457b7079 100644 --- a/lvgl_tft/st7796s.c +++ b/lvgl_tft/st7796s.c @@ -81,20 +81,31 @@ void st7796s_init(void) {0, {0}, 0xff}, }; +#if ST7796S_BCKL == 15 + gpio_config_t io_conf; + io_conf.intr_type = GPIO_PIN_INTR_DISABLE; + io_conf.mode = GPIO_MODE_OUTPUT; + io_conf.pin_bit_mask = GPIO_SEL_15; + io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE; + io_conf.pull_up_en = GPIO_PULLUP_DISABLE; + gpio_config(&io_conf); +#endif + //Initialize non-SPI GPIOs gpio_pad_select_gpio(ST7796S_DC); gpio_set_direction(ST7796S_DC, GPIO_MODE_OUTPUT); - -#if ST7796S_USE_RST gpio_pad_select_gpio(ST7796S_RST); gpio_set_direction(ST7796S_RST, GPIO_MODE_OUTPUT); +#if ST7796S_ENABLE_BACKLIGHT_CONTROL + gpio_pad_select_gpio(ST7796S_BCKL); + gpio_set_direction(ST7796S_BCKL, GPIO_MODE_OUTPUT); +#endif //Reset the display gpio_set_level(ST7796S_RST, 0); vTaskDelay(100 / portTICK_RATE_MS); gpio_set_level(ST7796S_RST, 1); vTaskDelay(100 / portTICK_RATE_MS); -#endif ESP_LOGI(TAG, "Initialization."); @@ -111,6 +122,8 @@ void st7796s_init(void) cmd++; } + st7796s_enable_backlight(true); + st7796s_set_orientation(CONFIG_LV_DISPLAY_ORIENTATION); #if ST7796S_INVERT_COLORS == 1 @@ -148,6 +161,22 @@ void st7796s_flush(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_ st7796s_send_color((void *)color_map, size * 2); } +void st7796s_enable_backlight(bool backlight) +{ +#if ST7796S_ENABLE_BACKLIGHT_CONTROL + ESP_LOGI(TAG, "%s backlight.", backlight ? "Enabling" : "Disabling"); + uint32_t tmp = 0; + +#if (ST7796S_BCKL_ACTIVE_LVL == 1) + tmp = backlight ? 1 : 0; +#else + tmp = backlight ? 0 : 1; +#endif + + gpio_set_level(ST7796S_BCKL, tmp); +#endif +} + void st7796s_sleep_in() { uint8_t data[] = {0x08}; diff --git a/lvgl_tft/st7796s.h b/lvgl_tft/st7796s.h index 95c6d4fe..418ec9b7 100644 --- a/lvgl_tft/st7796s.h +++ b/lvgl_tft/st7796s.h @@ -26,12 +26,19 @@ extern "C" /********************* * DEFINES *********************/ -#define ST7796S_DC CONFIG_LV_DISP_PIN_DC -#define ST7796S_RST CONFIG_LV_DISP_PIN_RST -#define ST7796S_USE_RST CONFIG_LV_DISP_USE_RST -#define ST7796S_INVERT_COLORS CONFIG_LV_INVERT_COLORS +#define ST7796S_DC CONFIG_LV_DISP_PIN_DC +#define ST7796S_RST CONFIG_LV_DISP_PIN_RST +#define ST7796S_BCKL CONFIG_LV_DISP_PIN_BCKL + +#define ST7796S_ENABLE_BACKLIGHT_CONTROL CONFIG_LV_ENABLE_BACKLIGHT_CONTROL +#define ST7796S_INVERT_COLORS CONFIG_LV_INVERT_COLORS #define ST7796S_DISPLAY_ORIENTATION CONFIG_LV_DISPLAY_ORIENTATION +#if CONFIG_LV_BACKLIGHT_ACTIVE_LVL +#define ST7796S_BCKL_ACTIVE_LVL 1 +#else +#define ST7796S_BCKL_ACTIVE_LVL 0 +#endif /******************* * ST7796S REGS @@ -111,6 +118,7 @@ extern "C" void st7796s_init(void); void st7796s_flush(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_map); + void st7796s_enable_backlight(bool backlight); /********************** * MACROS diff --git a/lvgl_touch/Kconfig b/lvgl_touch/Kconfig index 859ea18e..ad6f4f3b 100644 --- a/lvgl_touch/Kconfig +++ b/lvgl_touch/Kconfig @@ -1,29 +1,28 @@ menu "LVGL Touch controller" config LV_TOUCH_CONTROLLER - int - default 0 if LV_TOUCH_CONTROLLER_NONE - default 1 if LV_TOUCH_CONTROLLER_XPT2046 - default 2 if LV_TOUCH_CONTROLLER_FT6X06 - default 3 if LV_TOUCH_CONTROLLER_STMPE610 + int + default 0 if LV_TOUCH_CONTROLLER_NONE + default 1 if LV_TOUCH_CONTROLLER_XPT2046 + default 2 if LV_TOUCH_CONTROLLER_FT6X06 + default 3 if LV_TOUCH_CONTROLLER_STMPE610 default 4 if LV_TOUCH_CONTROLLER_ADCRAW default 5 if LV_TOUCH_CONTROLLER_FT81X default 6 if LV_TOUCH_CONTROLLER_RA8875 - default 7 if LV_TOUCH_CONTROLLER_GT911 - default 8 if LV_TOUCH_CONTROLLER_L58 + default 7 if LV_TOUCH_CONTROLLER_L58 choice - prompt "Select a touch panel controller model." - default LV_TOUCH_CONTROLLER_NONE - help - Select the controller for your touch panel. - - config LV_TOUCH_CONTROLLER_NONE - bool "None" - config LV_TOUCH_CONTROLLER_XPT2046 + prompt "Select a touch panel controller model." + default LV_TOUCH_CONTROLLER_NONE + help + Select the controller for your touch panel. + + config LV_TOUCH_CONTROLLER_NONE + bool "None" + config LV_TOUCH_CONTROLLER_XPT2046 select LV_TOUCH_DRIVER_PROTOCOL_SPI bool "XPT2046" - config LV_TOUCH_CONTROLLER_FT6X06 - select LV_I2C_TOUCH + config LV_TOUCH_CONTROLLER_FT6X06 + select LV_TOUCH_DRIVER_PROTOCOL_I2C bool "FT6X06" config LV_TOUCH_CONTROLLER_L58 @@ -43,17 +42,14 @@ menu "LVGL Touch controller" config LV_TOUCH_CONTROLLER_RA8875 select LV_TOUCH_DRIVER_DISPLAY bool "RA8875" - config LV_TOUCH_CONTROLLER_GT911 - select LV_I2C_TOUCH - bool "GT911" endchoice - + config LV_TOUCH_DRIVER_PROTOCOL_SPI bool help Touch controller protocol SPI - config LV_I2C_TOUCH + config LV_TOUCH_DRIVER_PROTOCOL_I2C bool help Touch controller protocol I2C @@ -67,20 +63,37 @@ menu "LVGL Touch controller" bool help Touch controller uses same interface/device as display - (Note: Display must be initialized before touch) + (Note: Display must be initialized before touch) + + choice + prompt "Touch I2C port" + depends on LV_TOUCH_DRIVER_PROTOCOL_I2C + + default LV_TOUCH_I2C_PORT_0 + help + Select the I2C port used by the touch controller. + config LV_TOUCH_I2C_PORT_0 + bool "I2C PORT 0" + config LV_TOUCH_I2C_PORT_1 + bool "I2C PORT 1" + endchoice + choice prompt "Touch Controller SPI Bus." depends on LV_TOUCH_DRIVER_PROTOCOL_SPI - - default LV_TOUCH_CONTROLLER_SPI2_HOST + + default LV_TOUCH_CONTROLLER_SPI_VSPI if !IDF_TARGET_ESP32S2 + default LV_TOUCH_CONTROLLER_SPI_FSPI if IDF_TARGET_ESP32S2 help - Select the SPI Bus the touch controller is attached to. - - config LV_TOUCH_CONTROLLER_SPI2_HOST - bool "SPI2_HOST" - config LV_TOUCH_CONTROLLER_SPI3_HOST - bool "SPI3_HOST" + Select the SPI Bus the TFT Display is attached to. + + config LV_TOUCH_CONTROLLER_SPI_HSPI + bool "HSPI" + config LV_TOUCH_CONTROLLER_SPI_VSPI + bool "VSPI" if !IDF_TARGET_ESP32S2 + config LV_TOUCH_CONTROLLER_SPI_FSPI + bool "FSPI" if IDF_TARGET_ESP32S2 endchoice menu "Touchpanel (L58) Lilygo Pin Assignments" @@ -120,7 +133,9 @@ menu "LVGL Touch controller" config LV_TOUCH_SPI_MISO int prompt "GPIO for MISO (Master In Slave Out)" - + range 0 39 if IDF_TARGET_ESP32 + range 0 43 if IDF_TARGET_ESP32S2 + default 35 if LV_PREDEFINED_PINS_38V1 default 19 help @@ -129,6 +144,8 @@ menu "LVGL Touch controller" config LV_TOUCH_SPI_MOSI int prompt "GPIO for MOSI (Master Out Slave In)" + range 0 39 if IDF_TARGET_ESP32 + range 0 43 if IDF_TARGET_ESP32S2 default 32 if LV_PREDEFINED_PINS_38V1 default 23 @@ -137,7 +154,9 @@ menu "LVGL Touch controller" config LV_TOUCH_SPI_CLK int "GPIO for CLK (SCK / Serial Clock)" - + range 0 39 if IDF_TARGET_ESP32 + range 0 43 if IDF_TARGET_ESP32S2 + default 26 if LV_PREDEFINED_PINS_38V1 default 18 help @@ -145,7 +164,9 @@ menu "LVGL Touch controller" config LV_TOUCH_SPI_CS int "GPIO for CS (Slave Select)" - + range 0 39 if IDF_TARGET_ESP32 + range 0 43 if IDF_TARGET_ESP32S2 + default 33 if LV_PREDEFINED_PINS_38V1 default 5 help @@ -153,13 +174,15 @@ menu "LVGL Touch controller" config LV_TOUCH_PIN_IRQ int "GPIO for IRQ (Interrupt Request)" - + range 0 39 if IDF_TARGET_ESP32 + range 0 43 if IDF_TARGET_ESP32S2 + default 27 if LV_PREDEFINED_PINS_38V4 default 25 help Configure the touchpanel IRQ pin here. endmenu - + menu "Touchpanel Configuration (XPT2046)" depends on LV_TOUCH_CONTROLLER_XPT2046 @@ -186,11 +209,11 @@ menu "LVGL Touch controller" prompt "Maximum Y coordinate value." default 4095 if LV_PREDEFINED_PINS_38V4 default 1900 - - config LV_TOUCH_XY_SWAP - bool - prompt "Swap XY." - default y + + config LV_TOUCH_XY_SWAP + bool + prompt "Swap XY." + default y config LV_TOUCH_INVERT_X bool @@ -217,13 +240,36 @@ menu "LVGL Touch controller" endchoice endmenu + menu "Touchpanel (FT6X06) Pin Assignments" + depends on LV_TOUCH_CONTROLLER_FT6X06 + + config LV_TOUCH_I2C_SDA + int + prompt "GPIO for SDA (I2C)" + range 0 39 if IDF_TARGET_ESP32 + range 0 43 if IDF_TARGET_ESP32S2 + + default 21 + help + Configure the I2C touchpanel SDA pin here. + + config LV_TOUCH_I2C_SCL + int "GPIO for clock signal SCL (I2C)" + range 0 39 if IDF_TARGET_ESP32 + range 0 43 if IDF_TARGET_ESP32S2 + + default 22 + help + Configure the I2C touchpanel SCL pin here. + endmenu + menu "Touchpanel Configuration (FT6X06)" depends on LV_TOUCH_CONTROLLER_FT6X06 - config LV_FT6X36_SWAPXY - bool - prompt "Swap X with Y coordinate." - default n + config LV_FT6X36_SWAPXY + bool + prompt "Swap X with Y coordinate." + default y config LV_FT6X36_INVERT_X bool @@ -233,24 +279,19 @@ menu "LVGL Touch controller" config LV_FT6X36_INVERT_Y bool prompt "Invert Y coordinate value." - default n - - config LV_FT6X36_COORDINATES_QUEUE - bool - prompt "Send coordinates to FreeRTOS queue." - default n - help - Receive from the FreeRTOS queue using the handle 'ft6x36_touch_queue_handle'. + default y endmenu - + menu "Touchpanel (STMPE610) Pin Assignments" depends on LV_TOUCH_CONTROLLER_STMPE610 config LV_TOUCH_SPI_MISO int prompt "GPIO for MISO (Master In Slave Out)" - + range 0 39 if IDF_TARGET_ESP32 + range 0 43 if IDF_TARGET_ESP32S2 + default 35 if LV_PREDEFINED_PINS_38V1 default 19 if LV_PREDEFINED_DISPLAY_ADA_FEATHERWING default 19 @@ -259,9 +300,10 @@ menu "LVGL Touch controller" Configure the touchpanel MISO pin here. config LV_TOUCH_SPI_MOSI - # TODO Fix default for ESP32C3 int prompt "GPIO for MOSI (Master Out Slave In)" + range 0 39 if IDF_TARGET_ESP32 + range 0 43 if IDF_TARGET_ESP32S2 default 32 if LV_PREDEFINED_PINS_38V1 default 18 if LV_PREDEFINED_DISPLAY_ADA_FEATHERWING @@ -272,6 +314,8 @@ menu "LVGL Touch controller" config LV_TOUCH_SPI_CLK int "GPIO for CLK (SCK / Serial Clock)" + range 0 39 if IDF_TARGET_ESP32 + range 0 43 if IDF_TARGET_ESP32S2 default 26 if LV_PREDEFINED_PINS_38V1 default 5 if LV_PREDEFINED_DISPLAY_ADA_FEATHERWING @@ -281,6 +325,9 @@ menu "LVGL Touch controller" config LV_TOUCH_SPI_CS int "GPIO for CS (Slave Select)" + range 0 39 if IDF_TARGET_ESP32 + range 0 43 if IDF_TARGET_ESP32S2 + default 33 if LV_PREDEFINED_PINS_38V1 default 32 if LV_PREDEFINED_DISPLAY_ADA_FEATHERWING default 5 @@ -310,11 +357,11 @@ menu "LVGL Touch controller" int prompt "Maximum Y coordinate value." default 3800 - + config LV_TOUCH_XY_SWAP - bool - prompt "Swap XY." - default n + bool + prompt "Swap XY." + default n config LV_TOUCH_INVERT_X bool @@ -326,7 +373,7 @@ menu "LVGL Touch controller" prompt "Invert Y coordinate value." default y endmenu - + menu "Touchpanel (ADCRAW) Pin Assignments" depends on LV_TOUCH_CONTROLLER_ADCRAW @@ -347,7 +394,7 @@ menu "LVGL Touch controller" help Configure the touchpanel Y- pin. Must be ADC input. - + config LV_TOUCHSCREEN_RESISTIVE_PIN_XL int prompt "GPIO X-" @@ -413,25 +460,25 @@ menu "LVGL Touch controller" config LV_TOUCH_X_MIN int prompt "Minimum X coordinate ADC value" - range 0 1023 + range 0 1023 default 0 config LV_TOUCH_Y_MIN int prompt "Minimum Y coordinate ADC value" - range 0 1023 + range 0 1023 default 0 config LV_TOUCH_X_MAX int prompt "Maximum X coordinate ADC value" - range 0 1023 + range 0 1023 default 1023 config LV_TOUCH_Y_MAX int prompt "Maximum Y coordinate ADC value" - range 0 1023 + range 0 1023 default 1023 config LV_TOUCH_XY_SWAP @@ -452,13 +499,13 @@ menu "LVGL Touch controller" config LV_TOUCH_RA8875_SAMPLE_TIME int prompt "TP Sample Time Adjusting" - range 0 7 + range 0 7 default 0 config LV_TOUCH_RA8875_ADC_CLOCK int prompt "ADC Clock Setting" - range 0 7 + range 0 7 default 0 config LV_TOUCH_RA8875_WAKEUP_ENABLE @@ -478,57 +525,4 @@ menu "LVGL Touch controller" endmenu - menu "Touchpanel Configuration (GT911)" - depends on LV_TOUCH_CONTROLLER_GT911 - - config LV_GT911_SWAPXY - bool - prompt "Swap X with Y coordinate." - default y - - config LV_GT911_INVERT_X - bool - prompt "Invert X coordinate value." - default n - - config LV_GT911_INVERT_Y - bool - prompt "Invert Y coordinate value." - default y - - endmenu - - choice - prompt "Select an I2C port for the touch panel" - default LV_I2C_TOUCH_PORT_0 - depends on LV_I2C_TOUCH - - config LV_I2C_TOUCH_PORT_0 - bool - prompt "I2C port 0" - help - I2C is shared peripheral managed by I2C Manager. In order to configure I2C Manager (pinout, etc.) see menu - Component config->I2C Port Settings. - - config LV_I2C_TOUCH_PORT_1 - bool - prompt "I2C port 1" - help - I2C is shared peripheral managed by I2C Manager. In order to configure I2C Manager (pinout, etc.) see menu - Component config->I2C Port Settings. - - endchoice - - config LV_I2C - bool - default y if LV_I2C_TOUCH - - config LV_I2C_TOUCH_PORT - int - default 1 if LV_I2C_TOUCH_PORT_1 - default 0 - endmenu - - - diff --git a/lvgl_touch/ft6x36.c b/lvgl_touch/ft6x36.c index dae736c2..71965b6b 100644 --- a/lvgl_touch/ft6x36.c +++ b/lvgl_touch/ft6x36.c @@ -1,45 +1,55 @@ /* * Copyright © 2020 Wolfgang Christl -* Permission is hereby granted, free of charge, to any person obtaining a copy of this -* software and associated documentation files (the “Software”), to deal in the Software -* without restriction, including without limitation the rights to use, copy, modify, merge, -* publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +* Permission is hereby granted, free of charge, to any person obtaining a copy of this +* software and associated documentation files (the “Software”), to deal in the Software +* without restriction, including without limitation the rights to use, copy, modify, merge, +* publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons * to whom the Software is furnished to do so, subject to the following conditions: * -* The above copyright notice and this permission notice shall be included in all copies or +* The above copyright notice and this permission notice shall be included in all copies or * substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -* FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* +* THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +* FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include +#include #ifdef LV_LVGL_H_INCLUDE_SIMPLE #include #else #include #endif #include "ft6x36.h" -#include "lvgl_i2c/i2c_manager.h" +#include "tp_i2c.h" +#include "../lvgl_i2c_conf.h" #define TAG "FT6X36" -#define FT6X36_TOUCH_QUEUE_ELEMENTS 1 -static ft6x36_status_t ft6x36_status; -static uint8_t current_dev_addr; // set during init -static ft6x36_touch_t touch_inputs = { -1, -1, LV_INDEV_STATE_REL }; // -1 coordinates to designate it was never touched -#if CONFIG_LV_FT6X36_COORDINATES_QUEUE -QueueHandle_t ft6x36_touch_queue_handle; -#endif +ft6x36_status_t ft6x36_status; +uint8_t current_dev_addr; // set during init + +esp_err_t ft6x06_i2c_read8(uint8_t slave_addr, uint8_t register_addr, uint8_t *data_buf) { + i2c_cmd_handle_t i2c_cmd = i2c_cmd_link_create(); + + i2c_master_start(i2c_cmd); + i2c_master_write_byte(i2c_cmd, (slave_addr << 1) | I2C_MASTER_WRITE, true); + i2c_master_write_byte(i2c_cmd, register_addr, I2C_MASTER_ACK); -static esp_err_t ft6x06_i2c_read8(uint8_t slave_addr, uint8_t register_addr, uint8_t *data_buf) { - return lvgl_i2c_read(CONFIG_LV_I2C_TOUCH_PORT, slave_addr, register_addr, data_buf, 1); + i2c_master_start(i2c_cmd); + i2c_master_write_byte(i2c_cmd, (slave_addr << 1) | I2C_MASTER_READ, true); + + i2c_master_read_byte(i2c_cmd, data_buf, I2C_MASTER_NACK); + i2c_master_stop(i2c_cmd); + esp_err_t ret = i2c_master_cmd_begin(TOUCH_I2C_PORT, i2c_cmd, 1000 / portTICK_RATE_MS); + i2c_cmd_link_delete(i2c_cmd); + return ret; } /** @@ -65,38 +75,42 @@ uint8_t ft6x36_get_gesture_id() { * @retval None */ void ft6x06_init(uint16_t dev_addr) { + if (!ft6x36_status.inited) { - ft6x36_status.inited = true; - current_dev_addr = dev_addr; - uint8_t data_buf; - esp_err_t ret; - ESP_LOGI(TAG, "Found touch panel controller"); - if ((ret = ft6x06_i2c_read8(dev_addr, FT6X36_PANEL_ID_REG, &data_buf) != ESP_OK)) - ESP_LOGE(TAG, "Error reading from device: %s", - esp_err_to_name(ret)); // Only show error the first time - ESP_LOGI(TAG, "\tDevice ID: 0x%02x", data_buf); - - ft6x06_i2c_read8(dev_addr, FT6X36_CHIPSELECT_REG, &data_buf); - ESP_LOGI(TAG, "\tChip ID: 0x%02x", data_buf); - - ft6x06_i2c_read8(dev_addr, FT6X36_DEV_MODE_REG, &data_buf); - ESP_LOGI(TAG, "\tDevice mode: 0x%02x", data_buf); - - ft6x06_i2c_read8(dev_addr, FT6X36_FIRMWARE_ID_REG, &data_buf); - ESP_LOGI(TAG, "\tFirmware ID: 0x%02x", data_buf); - - ft6x06_i2c_read8(dev_addr, FT6X36_RELEASECODE_REG, &data_buf); - ESP_LOGI(TAG, "\tRelease code: 0x%02x", data_buf); - -#if CONFIG_LV_FT6X36_COORDINATES_QUEUE - ft6x36_touch_queue_handle = xQueueCreate( FT6X36_TOUCH_QUEUE_ELEMENTS, sizeof( ft6x36_touch_t ) ); - if( ft6x36_touch_queue_handle == NULL ) - { - ESP_LOGE( TAG, "\tError creating touch input FreeRTOS queue" ); - return; - } - xQueueSend( ft6x36_touch_queue_handle, &touch_inputs, 0 ); +/* I2C master is initialized before calling this function */ +#if 0 + esp_err_t code = i2c_master_init(); +#else + esp_err_t code = ESP_OK; #endif + + if (code != ESP_OK) { + ft6x36_status.inited = false; + ESP_LOGE(TAG, "Error during I2C init %s", esp_err_to_name(code)); + } else { + ft6x36_status.inited = true; + current_dev_addr = dev_addr; + uint8_t data_buf; + esp_err_t ret; + ESP_LOGI(TAG, "Found touch panel controller"); + if ((ret = ft6x06_i2c_read8(dev_addr, FT6X36_PANEL_ID_REG, &data_buf) != ESP_OK)) + ESP_LOGE(TAG, "Error reading from device: %s", + esp_err_to_name(ret)); // Only show error the first time + ESP_LOGI(TAG, "\tDevice ID: 0x%02x", data_buf); + + ft6x06_i2c_read8(dev_addr, FT6X36_CHIPSELECT_REG, &data_buf); + ESP_LOGI(TAG, "\tChip ID: 0x%02x", data_buf); + + ft6x06_i2c_read8(dev_addr, FT6X36_DEV_MODE_REG, &data_buf); + ESP_LOGI(TAG, "\tDevice mode: 0x%02x", data_buf); + + ft6x06_i2c_read8(dev_addr, FT6X36_FIRMWARE_ID_REG, &data_buf); + ESP_LOGI(TAG, "\tFirmware ID: 0x%02x", data_buf); + + ft6x06_i2c_read8(dev_addr, FT6X36_RELEASECODE_REG, &data_buf); + ESP_LOGI(TAG, "\tRelease code: 0x%02x", data_buf); + } + } } /** @@ -106,55 +120,84 @@ void ft6x06_init(uint16_t dev_addr) { * @retval Always false */ bool ft6x36_read(lv_indev_drv_t *drv, lv_indev_data_t *data) { - if (!ft6x36_status.inited) { - ESP_LOGE(TAG, "Init first!"); - return 0x00; + uint8_t data_xy[4]; // 2 bytes X | 2 bytes Y + uint8_t touch_pnt_cnt; // Number of detected touch points + static int16_t last_x = 0; // 12bit pixel value + static int16_t last_y = 0; // 12bit pixel value + + ft6x06_i2c_read8(current_dev_addr, FT6X36_TD_STAT_REG, &touch_pnt_cnt); + if (touch_pnt_cnt != 1) { // ignore no touch & multi touch + data->point.x = last_x; + data->point.y = last_y; + data->state = LV_INDEV_STATE_REL; + return false; } - uint8_t data_buf[5]; // 1 byte status, 2 bytes X, 2 bytes Y - esp_err_t ret = lvgl_i2c_read(CONFIG_LV_I2C_TOUCH_PORT, current_dev_addr, FT6X36_TD_STAT_REG, &data_buf[0], 5); + // Read X value + i2c_cmd_handle_t i2c_cmd = i2c_cmd_link_create(); + + i2c_master_start(i2c_cmd); + i2c_master_write_byte(i2c_cmd, (current_dev_addr << 1) | I2C_MASTER_WRITE, true); + i2c_master_write_byte(i2c_cmd, FT6X36_P1_XH_REG, I2C_MASTER_ACK); + + i2c_master_start(i2c_cmd); + i2c_master_write_byte(i2c_cmd, (current_dev_addr << 1) | I2C_MASTER_READ, true); + + i2c_master_read_byte(i2c_cmd, &data_xy[0], I2C_MASTER_ACK); // reads FT6X36_P1_XH_REG + i2c_master_read_byte(i2c_cmd, &data_xy[1], I2C_MASTER_NACK); // reads FT6X36_P1_XL_REG + i2c_master_stop(i2c_cmd); + esp_err_t ret = i2c_master_cmd_begin(TOUCH_I2C_PORT, i2c_cmd, 1000 / portTICK_RATE_MS); + i2c_cmd_link_delete(i2c_cmd); if (ret != ESP_OK) { - ESP_LOGE(TAG, "Error talking to touch IC: %s", esp_err_to_name(ret)); + ESP_LOGE(TAG, "Error getting X coordinates: %s", esp_err_to_name(ret)); + data->point.x = last_x; + data->point.y = last_y; + data->state = LV_INDEV_STATE_REL; // no touch detected + return false; } - uint8_t touch_pnt_cnt = data_buf[0]; // Number of detected touch points - - if (ret != ESP_OK || touch_pnt_cnt != 1) { // ignore no touch & multi touch - if ( touch_inputs.current_state != LV_INDEV_STATE_REL) - { - touch_inputs.current_state = LV_INDEV_STATE_REL; -#if CONFIG_LV_FT6X36_COORDINATES_QUEUE - xQueueOverwrite( ft6x36_touch_queue_handle, &touch_inputs ); -#endif - } - data->point.x = touch_inputs.last_x; - data->point.y = touch_inputs.last_y; - data->state = touch_inputs.current_state; + + // Read Y value + i2c_cmd = i2c_cmd_link_create(); + + i2c_master_start(i2c_cmd); + i2c_master_write_byte(i2c_cmd, (current_dev_addr << 1) | I2C_MASTER_WRITE, true); + i2c_master_write_byte(i2c_cmd, FT6X36_P1_YH_REG, I2C_MASTER_ACK); + + i2c_master_start(i2c_cmd); + i2c_master_write_byte(i2c_cmd, (current_dev_addr << 1) | I2C_MASTER_READ, true); + + i2c_master_read_byte(i2c_cmd, &data_xy[2], I2C_MASTER_ACK); // reads FT6X36_P1_YH_REG + i2c_master_read_byte(i2c_cmd, &data_xy[3], I2C_MASTER_NACK); // reads FT6X36_P1_YL_REG + i2c_master_stop(i2c_cmd); + ret = i2c_master_cmd_begin(TOUCH_I2C_PORT, i2c_cmd, 1000 / portTICK_RATE_MS); + i2c_cmd_link_delete(i2c_cmd); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Error getting Y coordinates: %s", esp_err_to_name(ret)); + data->point.x = last_x; + data->point.y = last_y; + data->state = LV_INDEV_STATE_REL; // no touch detected return false; } - touch_inputs.current_state = LV_INDEV_STATE_PR; - touch_inputs.last_x = ((data_buf[1] & FT6X36_MSB_MASK) << 8) | (data_buf[2] & FT6X36_LSB_MASK); - touch_inputs.last_y = ((data_buf[3] & FT6X36_MSB_MASK) << 8) | (data_buf[4] & FT6X36_LSB_MASK); + last_x = ((data_xy[0] & FT6X36_MSB_MASK) << 8) | (data_xy[1] & FT6X36_LSB_MASK); + last_y = ((data_xy[2] & FT6X36_MSB_MASK) << 8) | (data_xy[3] & FT6X36_LSB_MASK); #if CONFIG_LV_FT6X36_SWAPXY - int16_t swap_buf = touch_inputs.last_x; - touch_inputs.last_x = touch_inputs.last_y; - touch_inputs.last_y = swap_buf; + int16_t swap_buf = last_x; + last_x = last_y; + last_y = swap_buf; #endif #if CONFIG_LV_FT6X36_INVERT_X - touch_inputs.last_x = LV_HOR_RES - touch_inputs.last_x; + last_x = LV_HOR_RES - last_x; #endif #if CONFIG_LV_FT6X36_INVERT_Y - touch_inputs.last_y = LV_VER_RES - touch_inputs.last_y; + last_y = LV_VER_RES - last_y; #endif - data->point.x = touch_inputs.last_x; - data->point.y = touch_inputs.last_y; - data->state = touch_inputs.current_state; - ESP_LOGD(TAG, "X=%u Y=%u", data->point.x, data->point.y); - -#if CONFIG_LV_FT6X36_COORDINATES_QUEUE - xQueueOverwrite( ft6x36_touch_queue_handle, &touch_inputs ); -#endif - + //uint16_t lcd_x = p.x *1.37; // Max 240 + //uint16_t lcd_y = p.y *1.51; // Max 400 + data->point.x = last_x *1.37; + data->point.y = last_y *1.51; + data->state = LV_INDEV_STATE_PR; + ESP_LOGV(TAG, "X=%u Y=%u", data->point.x, data->point.y); return false; } diff --git a/lvgl_touch/ft6x36.h b/lvgl_touch/ft6x36.h index c4074dc3..da466b6c 100644 --- a/lvgl_touch/ft6x36.h +++ b/lvgl_touch/ft6x36.h @@ -2,20 +2,20 @@ /* * Copyright © 2020 Wolfgang Christl -* Permission is hereby granted, free of charge, to any person obtaining a copy of this -* software and associated documentation files (the “Software”), to deal in the Software -* without restriction, including without limitation the rights to use, copy, modify, merge, -* publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +* Permission is hereby granted, free of charge, to any person obtaining a copy of this +* software and associated documentation files (the “Software”), to deal in the Software +* without restriction, including without limitation the rights to use, copy, modify, merge, +* publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons * to whom the Software is furnished to do so, subject to the following conditions: * -* The above copyright notice and this permission notice shall be included in all copies or +* The above copyright notice and this permission notice shall be included in all copies or * substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -* FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* +* THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +* FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ @@ -23,10 +23,6 @@ #include #include -#if CONFIG_LV_FT6X36_COORDINATES_QUEUE -#include "freertos/FreeRTOS.h" -#include "freertos/queue.h" -#endif #ifdef LV_LVGL_H_INCLUDE_SIMPLE #include "lvgl.h" #else @@ -149,16 +145,6 @@ typedef struct { bool inited; } ft6x36_status_t; -typedef struct -{ - int16_t last_x; - int16_t last_y; - lv_indev_state_t current_state; -} ft6x36_touch_t; - -#if CONFIG_LV_FT6X36_COORDINATES_QUEUE -extern QueueHandle_t ft6x36_touch_queue_handle; -#endif /** * @brief Initialize for FT6x36 communication via I2C * @param dev_addr: Device address on communication Bus (I2C slave address of FT6X36). diff --git a/lvgl_touch/l58.cpp b/lvgl_touch/l58.cpp index 62ac1d67..de4329d8 100644 --- a/lvgl_touch/l58.cpp +++ b/lvgl_touch/l58.cpp @@ -25,6 +25,7 @@ #include #endif #include "l58.h" +#include "../lvgl_i2c_conf.h" // Cale touch implementation #include "L58Touch.h" L58Touch Touch(CONFIG_LV_TOUCH_INT); diff --git a/lvgl_touch/touch_driver.c b/lvgl_touch/touch_driver.c index a59ac6bc..4508810c 100644 --- a/lvgl_touch/touch_driver.c +++ b/lvgl_touch/touch_driver.c @@ -4,11 +4,10 @@ #include "touch_driver.h" #include "tp_spi.h" - +#include "tp_i2c.h" // Is not being included in CMakeLists.txt (Research why) #include "l58.h" - void touch_driver_init(void) { #if defined (CONFIG_LV_TOUCH_CONTROLLER_XPT2046) @@ -25,16 +24,10 @@ void touch_driver_init(void) /* nothing to do */ #elif defined (CONFIG_LV_TOUCH_CONTROLLER_RA8875) ra8875_touch_init(); -#elif defined (CONFIG_LV_TOUCH_CONTROLLER_GT911) - gt911_init(GT911_I2C_SLAVE_ADDR); #endif } -#if LVGL_VERSION_MAJOR >= 8 -void touch_driver_read(lv_indev_drv_t *drv, lv_indev_data_t *data) -#else bool touch_driver_read(lv_indev_drv_t *drv, lv_indev_data_t *data) -#endif { bool res = false; @@ -53,14 +46,8 @@ bool touch_driver_read(lv_indev_drv_t *drv, lv_indev_data_t *data) res = FT81x_read(drv, data); #elif defined (CONFIG_LV_TOUCH_CONTROLLER_RA8875) res = ra8875_touch_read(drv, data); -#elif defined (CONFIG_LV_TOUCH_CONTROLLER_GT911) - res = gt911_read(drv, data); #endif -#if LVGL_VERSION_MAJOR >= 8 - data->continue_reading = res; -#else return res; -#endif } diff --git a/lvgl_touch/touch_driver.h b/lvgl_touch/touch_driver.h index 0d014e2e..bc92f4fe 100644 --- a/lvgl_touch/touch_driver.h +++ b/lvgl_touch/touch_driver.h @@ -32,8 +32,6 @@ extern "C" { #include "FT81x.h" #elif defined (CONFIG_LV_TOUCH_CONTROLLER_RA8875) #include "ra8875_touch.h" -#elif defined (CONFIG_LV_TOUCH_CONTROLLER_GT911) -#include "gt911.h" #endif /********************* @@ -44,12 +42,7 @@ extern "C" { * GLOBAL PROTOTYPES **********************/ void touch_driver_init(void); - -#if LVGL_VERSION_MAJOR >= 8 -void touch_driver_read(lv_indev_drv_t *drv, lv_indev_data_t *data); -#else bool touch_driver_read(lv_indev_drv_t *drv, lv_indev_data_t *data); -#endif #ifdef __cplusplus } /* extern "C" */ diff --git a/lvgl_touch/tp_i2c.c b/lvgl_touch/tp_i2c.c new file mode 100644 index 00000000..dc3371c3 --- /dev/null +++ b/lvgl_touch/tp_i2c.c @@ -0,0 +1,43 @@ +/* +* Copyright © 2020 Wolfgang Christl + +* Permission is hereby granted, free of charge, to any person obtaining a copy of this +* software and associated documentation files (the “Software”), to deal in the Software +* without restriction, including without limitation the rights to use, copy, modify, merge, +* publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +* to whom the Software is furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all copies or +* substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +* FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +#include +#include + +#define I2C_MASTER_FREQ_HZ 100000 /* 100kHz*/ +#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 */ + +/** + * @brief ESP32 I2C init as master + * @ret ESP32 error code + */ +esp_err_t i2c_master_init(void) { + int i2c_master_port = I2C_NUM_0; + i2c_config_t conf; + conf.mode = I2C_MODE_MASTER; + conf.sda_io_num = CONFIG_LV_TOUCH_I2C_SDA; + conf.sda_pullup_en = GPIO_PULLUP_ENABLE; + conf.scl_io_num = CONFIG_LV_TOUCH_I2C_SCL; + conf.scl_pullup_en = GPIO_PULLUP_ENABLE; + conf.master.clk_speed = I2C_MASTER_FREQ_HZ; + i2c_param_config(i2c_master_port, &conf); + return i2c_driver_install(i2c_master_port, conf.mode, I2C_MASTER_RX_BUF_DISABLE, I2C_MASTER_TX_BUF_DISABLE, 0); +} diff --git a/lvgl_touch/tp_i2c.h b/lvgl_touch/tp_i2c.h new file mode 100644 index 00000000..5c1eb55f --- /dev/null +++ b/lvgl_touch/tp_i2c.h @@ -0,0 +1,36 @@ +/* +* Copyright © 2020 Wolfgang Christl + +* Permission is hereby granted, free of charge, to any person obtaining a copy of this +* software and associated documentation files (the “Software”), to deal in the Software +* without restriction, including without limitation the rights to use, copy, modify, merge, +* publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +* to whom the Software is furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all copies or +* substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +* FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +#ifndef __TS_H +#define __TS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +esp_err_t i2c_master_init(void); + +#ifdef __cplusplus +} +#endif + +#endif /* __TS_H */ From 9445dab325c0b3559ae6816e8c12c4ab5b9b221a Mon Sep 17 00:00:00 2001 From: martinberlin Date: Sat, 26 Aug 2023 12:23:37 +0200 Subject: [PATCH 27/31] epdiy V7 made a bit faster --- lvgl_helpers.h | 2 +- lvgl_tft/epdiy_epaper.c | 9 ++++ lvgl_tft/epdiy_epaper.cpp | 24 ++++------ lvgl_tft/epdiy_epaper_v1.cpp | 92 ------------------------------------ 4 files changed, 19 insertions(+), 108 deletions(-) delete mode 100644 lvgl_tft/epdiy_epaper_v1.cpp diff --git a/lvgl_helpers.h b/lvgl_helpers.h index db76c700..ad66cd75 100644 --- a/lvgl_helpers.h +++ b/lvgl_helpers.h @@ -42,7 +42,7 @@ extern "C" { #define DISP_BUF_SIZE (LV_HOR_RES_MAX * 40) #elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_ST7796S #define DISP_BUF_SIZE (LV_HOR_RES_MAX * LV_VER_RES_MAX/3) -// IMPORTANT: This will render the screen in 8 times (Max more and it skips lines) +// IMPORTANT: This will render the screen in 8 times (more and it skips lines, supposedly limited by PSRAM speed) #elif defined (CONFIG_LV_EPAPER_EPDIY_DISPLAY_CONTROLLER) #define DISP_BUF_SIZE LV_HOR_RES_MAX*(LV_VER_RES_MAX/ 8) diff --git a/lvgl_tft/epdiy_epaper.c b/lvgl_tft/epdiy_epaper.c index 784096a9..e532a797 100644 --- a/lvgl_tft/epdiy_epaper.c +++ b/lvgl_tft/epdiy_epaper.c @@ -1,3 +1,12 @@ +/************************************************************************************************** + * NOTE: This file is the first version that writes directly on the set_px callback + * each pixel into the epaper display buffer. The second version is 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 + * + * BOTH are oriented to latest version of epdiy driver that uses LCD module for parallel communication + * BRANCH: s3_lcd + **************************************************************************************************/ #include "esp_log.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" diff --git a/lvgl_tft/epdiy_epaper.cpp b/lvgl_tft/epdiy_epaper.cpp index 9fb3ef73..30aecd61 100644 --- a/lvgl_tft/epdiy_epaper.cpp +++ b/lvgl_tft/epdiy_epaper.cpp @@ -3,7 +3,6 @@ #include "freertos/task.h" #include "epdiy_epaper.h" #include "epdiy.h" -//#include "epd_highlevel.h" EpdiyHighlevelState hl; uint16_t flushcalls = 0; @@ -21,17 +20,16 @@ void epdiy_init(void) // This will print an error if unsupported. In this case, // set VCOM using the hardware potentiometer and delete this line. epd_set_vcom(1760); - - // Only for older versions epdiy - //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: + //Clear all display in initialization to remove any ghosts epd_fullclear(&hl, temperature); } -/* Suggested by @kisvegabor https://forum.lvgl.io/t/lvgl-port-to-be-used-with-epaper-displays/5630/26 */ +/* Suggested by @kisvegabor https://forum.lvgl.io/t/lvgl-port-to-be-used-with-epaper-displays/5630/26 + * @deprecated +*/ void buf_area_to_framebuffer(const lv_area_t *area, const uint8_t *image_data) { assert(framebuffer != NULL); uint8_t *fb_ptr = &framebuffer[area->y1 * epd_width() / 2 + area->x1 / 2]; @@ -48,8 +46,7 @@ void buf_copy_to_framebuffer(EpdRect image_area, const uint8_t *image_data) { assert(framebuffer != NULL); for (uint32_t i = 0; i < image_area.width * image_area.height; i++) { - uint8_t val = (i % 2) ? (image_data[i / 2] & 0xF0) >> 4 - : image_data[i / 2] & 0x0F; + uint8_t val = (i % 2) ? (image_data[i / 2] & 0xF0) >> 4 : image_data[i / 2] & 0x0F; int xx = image_area.x + i % image_area.width; if (xx < 0 || xx >= epd_width()) { continue; @@ -83,17 +80,14 @@ void epdiy_flush(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_ma uint8_t* buf = (uint8_t *) color_map; // Buffer debug - /* - for (int index=0; index<400; index++) { + /* for (int index=0; index<400; index++) { printf("%x ", buf[index]); } */ - - // UNCOMMENT only one of this options - // SAFE Option with EPDiy copy of epd_copy_to_framebuffer - buf_copy_to_framebuffer(update_area, buf); + // This is the slower version that works good without leaving any white line + //buf_copy_to_framebuffer(update_area, buf); //Faster mode suggested in LVGL forum (Leaves ghosting&prints bad sections / experimental) NOTE: Do NOT use in production - //buf_area_to_framebuffer(area, buf); + buf_area_to_framebuffer(area, buf); epd_hl_update_area(&hl, updateMode, temperature, update_area); //update_area diff --git a/lvgl_tft/epdiy_epaper_v1.cpp b/lvgl_tft/epdiy_epaper_v1.cpp deleted file mode 100644 index 38cd948f..00000000 --- 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); - } -} From 5ffb67f1939eba7da1b780c4bb0123dfd18dbce0 Mon Sep 17 00:00:00 2001 From: martinberlin Date: Sun, 3 Sep 2023 00:20:11 +0200 Subject: [PATCH 28/31] Add GT911 using esp_lcd_touch_gt911 --- CMakeLists.txt | 4 +- lvgl_helpers.c | 6 +- lvgl_tft/epdiy_epaper.cpp | 4 +- lvgl_touch/Kconfig | 35 +++++++-- lvgl_touch/gt911.c | 150 ++++++++++++++------------------------ lvgl_touch/gt911.h | 41 ----------- lvgl_touch/touch_driver.c | 5 +- lvgl_touch/touch_driver.h | 2 + 8 files changed, 95 insertions(+), 152 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6b3942dd..9613d9ff 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -69,6 +69,8 @@ if(CONFIG_LV_TOUCH_CONTROLLER) list(APPEND SOURCES "lvgl_touch/ft6x36.c") elseif(CONFIG_LV_TOUCH_CONTROLLER_L58) list(APPEND SOURCES "lvgl_touch/l58.cpp") + elseif(CONFIG_LV_TOUCH_CONTROLLER_GT911) + list(APPEND SOURCES "lvgl_touch/gt911.c") elseif(CONFIG_LV_TOUCH_CONTROLLER_STMPE610) list(APPEND SOURCES "lvgl_touch/stmpe610.c") elseif(CONFIG_LV_TOUCH_CONTROLLER_ADCRAW) @@ -89,7 +91,7 @@ endif() idf_component_register(SRCS ${SOURCES} INCLUDE_DIRS ${LVGL_INCLUDE_DIRS} REQUIRES epdiy - lvgl CalEPD sharp-lcd + lvgl CalEPD sharp-lcd espressif__esp_lcd_touch_gt911 ) target_compile_definitions(${COMPONENT_LIB} PUBLIC "-DLV_LVGL_H_INCLUDE_SIMPLE") diff --git a/lvgl_helpers.c b/lvgl_helpers.c index 334f1f3c..84285fca 100644 --- a/lvgl_helpers.c +++ b/lvgl_helpers.c @@ -148,9 +148,7 @@ void lvgl_driver_init(void) touch_driver_init(); #elif defined (CONFIG_LV_TOUCH_DRIVER_PROTOCOL_I2C) ESP_LOGI(TAG, "Initializing I2C master for touch"); - lvgl_i2c_driver_init(TOUCH_I2C_PORT, - TOUCH_I2C_SDA, TOUCH_I2C_SCL, - TOUCH_I2C_SPEED_HZ); + //lvgl_i2c_driver_init(TOUCH_I2C_PORT, TOUCH_I2C_SDA, TOUCH_I2C_SCL, TOUCH_I2C_SPEED_HZ); touch_driver_init(); #elif defined (CONFIG_LV_TOUCH_DRIVER_ADC) @@ -197,7 +195,7 @@ bool lvgl_i2c_driver_init(int port, int sda_pin, int scl_pin, int speed_hz) I2C_MODE_MASTER, 0, 0 /*I2C_MASTER_RX_BUF_DISABLE, I2C_MASTER_TX_BUF_DISABLE */, 0 /* intr_alloc_flags */); - assert(ESP_OK == err); + //assert(ESP_OK == err); return ESP_OK != err; } diff --git a/lvgl_tft/epdiy_epaper.cpp b/lvgl_tft/epdiy_epaper.cpp index 30aecd61..11f989fc 100644 --- a/lvgl_tft/epdiy_epaper.cpp +++ b/lvgl_tft/epdiy_epaper.cpp @@ -84,10 +84,10 @@ void epdiy_flush(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_ma printf("%x ", buf[index]); } */ // This is the slower version that works good without leaving any white line - //buf_copy_to_framebuffer(update_area, buf); + buf_copy_to_framebuffer(update_area, buf); //Faster mode suggested in LVGL forum (Leaves ghosting&prints bad sections / experimental) NOTE: Do NOT use in production - buf_area_to_framebuffer(area, buf); + //buf_area_to_framebuffer(area, buf); epd_hl_update_area(&hl, updateMode, temperature, update_area); //update_area diff --git a/lvgl_touch/Kconfig b/lvgl_touch/Kconfig index ad6f4f3b..9ed4255a 100644 --- a/lvgl_touch/Kconfig +++ b/lvgl_touch/Kconfig @@ -2,14 +2,15 @@ menu "LVGL Touch controller" config LV_TOUCH_CONTROLLER int - default 0 if LV_TOUCH_CONTROLLER_NONE - default 1 if LV_TOUCH_CONTROLLER_XPT2046 - default 2 if LV_TOUCH_CONTROLLER_FT6X06 - default 3 if LV_TOUCH_CONTROLLER_STMPE610 + default 0 if LV_TOUCH_CONTROLLER_NONE + default 1 if LV_TOUCH_CONTROLLER_XPT2046 + default 2 if LV_TOUCH_CONTROLLER_FT6X06 + default 3 if LV_TOUCH_CONTROLLER_STMPE610 default 4 if LV_TOUCH_CONTROLLER_ADCRAW default 5 if LV_TOUCH_CONTROLLER_FT81X default 6 if LV_TOUCH_CONTROLLER_RA8875 default 7 if LV_TOUCH_CONTROLLER_L58 + default 8 if LV_TOUCH_CONTROLLER_GT911 choice prompt "Select a touch panel controller model." default LV_TOUCH_CONTROLLER_NONE @@ -29,7 +30,9 @@ menu "LVGL Touch controller" # Start only touch without protocol: select CONFIG_LV_TOUCH_DRIVER_DISPLAY bool "L58" - + config LV_TOUCH_CONTROLLER_GT911 + select LV_TOUCH_DRIVER_PROTOCOL_I2C + bool "GT911" config LV_TOUCH_CONTROLLER_STMPE610 select LV_TOUCH_DRIVER_PROTOCOL_SPI bool "STMPE610" @@ -522,7 +525,27 @@ menu "LVGL Touch controller" bool prompt "De-bounce Circuit Enable for Touch Panel Interrupt" default y - endmenu + menu "Touchpanel GT911 Pin Assignments" + depends on LV_TOUCH_CONTROLLER_GT911 + + config LV_TOUCH_I2C_SDA + int + prompt "GPIO for SDA (I2C)" + range 0 39 if IDF_TARGET_ESP32 + range 0 43 if IDF_TARGET_ESP32S3 + + default 39 + help + Configure the I2C touchpanel SDA pin here. + config LV_TOUCH_I2C_SCL + int "GPIO for clock signal SCL (I2C)" + range 0 39 if IDF_TARGET_ESP32 + range 0 43 if IDF_TARGET_ESP32S3 + + default 40 + help + Configure the I2C touchpanel SCL pin here. + endmenu endmenu diff --git a/lvgl_touch/gt911.c b/lvgl_touch/gt911.c index 03c3d9d4..baf9b485 100644 --- a/lvgl_touch/gt911.c +++ b/lvgl_touch/gt911.c @@ -1,5 +1,5 @@ /* -* Copyright © 2021 Sturnus Inc. +* Copyright © 2023 Fasani Corp. * Permission is hereby granted, free of charge, to any person obtaining a copy of this * software and associated documentation files (the “Software”), to deal in the Software @@ -17,8 +17,12 @@ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_lcd_touch_gt911.h" #include +#include "driver/i2c.h" + #ifdef LV_LVGL_H_INCLUDE_SIMPLE #include #else @@ -26,62 +30,46 @@ #endif #include "gt911.h" -#include "lvgl_i2c/i2c_manager.h" - #define TAG "GT911" -gt911_status_t gt911_status; - -//TODO: handle multibyte read and refactor to just one read transaction -esp_err_t gt911_i2c_read(uint8_t slave_addr, uint16_t register_addr, uint8_t *data_buf, uint8_t len) { - return lvgl_i2c_read(CONFIG_LV_I2C_TOUCH_PORT, slave_addr, register_addr | I2C_REG_16, data_buf, len); -} - -esp_err_t gt911_i2c_write8(uint8_t slave_addr, uint16_t register_addr, uint8_t data) { - uint8_t buffer = data; - return lvgl_i2c_write(CONFIG_LV_I2C_TOUCH_PORT, slave_addr, register_addr | I2C_REG_16, &buffer, 1); -} +#ifdef CONFIG_LV_TOUCH_I2C_PORT_0 + #define I2C_PORT I2C_NUM_0 +#endif +#ifdef CONFIG_LV_TOUCH_I2C_PORT_1 + #define I2C_PORT I2C_NUM_1 +#endif +// When the touch panel has different pixels definition +float x_adjust = 1.55; +float y_adjust = 0.8; +esp_lcd_touch_handle_t tp; /** * @brief Initialize for GT911 communication via I2C - * @param dev_addr: Device address on communication Bus (I2C slave address of GT911). * @retval None */ void gt911_init(uint8_t dev_addr) { - if (!gt911_status.inited) { - gt911_status.i2c_dev_addr = dev_addr; - uint8_t data_buf; - esp_err_t ret; - - ESP_LOGI(TAG, "Checking for GT911 Touch Controller"); - if ((ret = gt911_i2c_read(dev_addr, GT911_PRODUCT_ID1, &data_buf, 1) != ESP_OK)) { - ESP_LOGE(TAG, "Error reading from device: %s", - esp_err_to_name(ret)); // Only show error the first time - return; - } - - // Read 4 bytes for Product ID in ASCII - for (int i = 0; i < GT911_PRODUCT_ID_LEN; i++) { - gt911_i2c_read(dev_addr, (GT911_PRODUCT_ID1 + i), (uint8_t *)&(gt911_status.product_id[i]), 1); - } - ESP_LOGI(TAG, "\tProduct ID: %s", gt911_status.product_id); - - gt911_i2c_read(dev_addr, GT911_VENDOR_ID, &data_buf, 1); - ESP_LOGI(TAG, "\tVendor ID: 0x%02x", data_buf); - - gt911_i2c_read(dev_addr, GT911_X_COORD_RES_L, &data_buf, 1); - gt911_status.max_x_coord = data_buf; - gt911_i2c_read(dev_addr, GT911_X_COORD_RES_H, &data_buf, 1); - gt911_status.max_x_coord |= ((uint16_t)data_buf << 8); - ESP_LOGI(TAG, "\tX Resolution: %d", gt911_status.max_x_coord); - - gt911_i2c_read(dev_addr, GT911_Y_COORD_RES_L, &data_buf, 1); - gt911_status.max_y_coord = data_buf; - gt911_i2c_read(dev_addr, GT911_Y_COORD_RES_H, &data_buf, 1); - gt911_status.max_y_coord |= ((uint16_t)data_buf << 8); - ESP_LOGI(TAG, "\tY Resolution: %d", gt911_status.max_y_coord); - gt911_status.inited = true; - } + esp_lcd_panel_io_handle_t tp_io_handle = NULL; + esp_lcd_panel_io_i2c_config_t tp_io_config = ESP_LCD_TOUCH_IO_I2C_GT911_CONFIG(); + + esp_lcd_touch_config_t tp_cfg = { + .x_max = 1025, + .y_max = 770, + .rst_gpio_num = -1, + .int_gpio_num = -1, + .levels = { + .reset = 0, + .interrupt = 0, + }, + .flags = { + .swap_xy = 1, + .mirror_x = 1, + .mirror_y = 0, + }, + }; + + esp_lcd_new_panel_io_i2c((esp_lcd_i2c_bus_handle_t)I2C_PORT, &tp_io_config, &tp_io_handle); + + esp_lcd_touch_new_i2c_gt911(tp_io_handle, &tp_cfg, &tp); } /** @@ -91,54 +79,22 @@ void gt911_init(uint8_t dev_addr) { * @retval Always false */ bool gt911_read(lv_indev_drv_t *drv, lv_indev_data_t *data) { - uint8_t touch_pnt_cnt; // Number of detected touch points - static int16_t last_x = 0; // 12bit pixel value - static int16_t last_y = 0; // 12bit pixel value - uint8_t data_buf; - uint8_t status_reg; - - gt911_i2c_read(gt911_status.i2c_dev_addr, GT911_STATUS_REG, &status_reg, 1); -// ESP_LOGI(TAG, "\tstatus: 0x%02x", status_reg); - touch_pnt_cnt = status_reg & 0x0F; - if ((status_reg & 0x80) || (touch_pnt_cnt < 6)) { - //Reset Status Reg Value - gt911_i2c_write8(gt911_status.i2c_dev_addr, GT911_STATUS_REG, 0x00); - } - if (touch_pnt_cnt != 1) { // ignore no touch & multi touch - data->point.x = last_x; - data->point.y = last_y; + esp_lcd_touch_read_data(tp); + + uint16_t touch_x[2]; + uint16_t touch_y[2]; + uint16_t touch_strength[2]; + uint8_t touch_cnt = 0; + bool touchpad_pressed = esp_lcd_touch_get_coordinates(tp, touch_x, touch_y, touch_strength, &touch_cnt, 2); + if (touchpad_pressed) { + data->state = LV_INDEV_STATE_PR; + data->point.x = (int)(touch_x[0]*x_adjust); + data->point.y = (int)(touch_y[0]*y_adjust); + ESP_LOGI(TAG, "X=%d Y=%d", (int)data->point.x, (int)data->point.y); + } else { data->state = LV_INDEV_STATE_REL; - return false; + data->point.x = -1; + data->point.y = -1; } - -// gt911_i2c_read(gt911_status.i2c_dev_addr, GT911_TRACK_ID1, &data_buf, 1); -// ESP_LOGI(TAG, "\ttrack_id: %d", data_buf); - - gt911_i2c_read(gt911_status.i2c_dev_addr, GT911_PT1_X_COORD_L, &data_buf, 1); - last_x = data_buf; - gt911_i2c_read(gt911_status.i2c_dev_addr, GT911_PT1_X_COORD_H, &data_buf, 1); - last_x |= ((uint16_t)data_buf << 8); - - gt911_i2c_read(gt911_status.i2c_dev_addr, GT911_PT1_Y_COORD_L, &data_buf, 1); - last_y = data_buf; - gt911_i2c_read(gt911_status.i2c_dev_addr, GT911_PT1_Y_COORD_H, &data_buf, 1); - last_y |= ((uint16_t)data_buf << 8); - -#if CONFIG_LV_GT911_INVERT_X - last_x = gt911_status.max_x_coord - last_x; -#endif -#if CONFIG_LV_GT911_INVERT_Y - last_y = gt911_status.max_y_coord - last_y; -#endif -#if CONFIG_LV_GT911_SWAPXY - int16_t swap_buf = last_x; - last_x = last_y; - last_y = swap_buf; -#endif - data->point.x = last_x; - data->point.y = last_y; - data->state = LV_INDEV_STATE_PR; - ESP_LOGI(TAG, "X=%u Y=%u", data->point.x, data->point.y); - ESP_LOGV(TAG, "X=%u Y=%u", data->point.x, data->point.y); return false; } diff --git a/lvgl_touch/gt911.h b/lvgl_touch/gt911.h index 6a110bdf..96643b70 100644 --- a/lvgl_touch/gt911.h +++ b/lvgl_touch/gt911.h @@ -22,7 +22,6 @@ #define __GT911_H #include -#include #ifdef LV_LVGL_H_INCLUDE_SIMPLE #include "lvgl.h" #else @@ -33,46 +32,6 @@ extern "C" { #endif -#define GT911_I2C_SLAVE_ADDR 0x5D - -#define GT911_PRODUCT_ID_LEN 4 - -/* Register Map of GT911 */ -#define GT911_PRODUCT_ID1 0x8140 -#define GT911_PRODUCT_ID2 0x8141 -#define GT911_PRODUCT_ID3 0x8142 -#define GT911_PRODUCT_ID4 0x8143 -#define GT911_FIRMWARE_VER_L 0x8144 -#define GT911_FIRMWARE_VER_H 0x8145 -#define GT911_X_COORD_RES_L 0x8146 -#define GT911_X_COORD_RES_H 0x8147 -#define GT911_Y_COORD_RES_L 0x8148 -#define GT911_Y_COORD_RES_H 0x8149 -#define GT911_VENDOR_ID 0x814A - -#define GT911_STATUS_REG 0x814E -#define GT911_STATUS_REG_BUF 0x80 -#define GT911_STATUS_REG_LARGE 0x40 -#define GT911_STATUS_REG_PROX_VALID 0x20 -#define GT911_STATUS_REG_HAVEKEY 0x10 -#define GT911_STATUS_REG_PT_MASK 0x0F - -#define GT911_TRACK_ID1 0x814F -#define GT911_PT1_X_COORD_L 0x8150 -#define GT911_PT1_X_COORD_H 0x8151 -#define GT911_PT1_Y_COORD_L 0x8152 -#define GT911_PT1_Y_COORD_H 0x8153 -#define GT911_PT1_X_SIZE_L 0x8154 -#define GT911_PT1_X_SIZE_H 0x8155 - -typedef struct { - bool inited; - char product_id[GT911_PRODUCT_ID_LEN]; - uint16_t max_x_coord; - uint16_t max_y_coord; - uint8_t i2c_dev_addr; -} gt911_status_t; - /** * @brief Initialize for GT911 communication via I2C * @param dev_addr: Device address on communication Bus (I2C slave address of GT911). diff --git a/lvgl_touch/touch_driver.c b/lvgl_touch/touch_driver.c index 4508810c..499f5cff 100644 --- a/lvgl_touch/touch_driver.c +++ b/lvgl_touch/touch_driver.c @@ -16,6 +16,8 @@ void touch_driver_init(void) ft6x06_init(FT6236_I2C_SLAVE_ADDR); #elif defined (CONFIG_LV_TOUCH_CONTROLLER_L58) l58_init(); +#elif defined (CONFIG_LV_TOUCH_CONTROLLER_GT911) + gt911_init(0x5d); #elif defined (CONFIG_LV_TOUCH_CONTROLLER_STMPE610) stmpe610_init(); #elif defined (CONFIG_LV_TOUCH_CONTROLLER_ADCRAW) @@ -37,7 +39,8 @@ bool touch_driver_read(lv_indev_drv_t *drv, lv_indev_data_t *data) res = ft6x36_read(drv, data); #elif defined (CONFIG_LV_TOUCH_CONTROLLER_L58) res = l58_read(drv, data); - +#elif defined (CONFIG_LV_TOUCH_CONTROLLER_GT911) + res = gt911_read(drv, data); #elif defined (CONFIG_LV_TOUCH_CONTROLLER_STMPE610) res = stmpe610_read(drv, data); #elif defined (CONFIG_LV_TOUCH_CONTROLLER_ADCRAW) diff --git a/lvgl_touch/touch_driver.h b/lvgl_touch/touch_driver.h index bc92f4fe..44378db7 100644 --- a/lvgl_touch/touch_driver.h +++ b/lvgl_touch/touch_driver.h @@ -32,6 +32,8 @@ extern "C" { #include "FT81x.h" #elif defined (CONFIG_LV_TOUCH_CONTROLLER_RA8875) #include "ra8875_touch.h" +#elif defined (CONFIG_LV_TOUCH_CONTROLLER_GT911) +#include "gt911.h" #endif /********************* From 03cf7ec5cd6b205005602d8b9f91f3c1fd502bde Mon Sep 17 00:00:00 2001 From: martinberlin Date: Sun, 10 Mar 2024 17:59:30 +0100 Subject: [PATCH 29/31] Exclude CalEPD and other tests from main CMakeLists.txt --- CMakeLists.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9613d9ff..bccf670a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -91,7 +91,10 @@ endif() idf_component_register(SRCS ${SOURCES} INCLUDE_DIRS ${LVGL_INCLUDE_DIRS} REQUIRES epdiy - lvgl CalEPD sharp-lcd espressif__esp_lcd_touch_gt911 + lvgl + #CalEPD + #sharp-lcd + #espressif__esp_lcd_touch_gt911 ) target_compile_definitions(${COMPONENT_LIB} PUBLIC "-DLV_LVGL_H_INCLUDE_SIMPLE") From 58d5febe70db18127551843c2ec440ef1d8bda77 Mon Sep 17 00:00:00 2001 From: Laurence Bank Date: Mon, 11 Mar 2024 10:21:25 +0000 Subject: [PATCH 30/31] Updated for color output on Kaleido e-paper --- lvgl_tft/epdiy_epaper.cpp | 90 +++++++++++++++++++++++---------------- 1 file changed, 53 insertions(+), 37 deletions(-) diff --git a/lvgl_tft/epdiy_epaper.cpp b/lvgl_tft/epdiy_epaper.cpp index 11f989fc..7bc829e7 100644 --- a/lvgl_tft/epdiy_epaper.cpp +++ b/lvgl_tft/epdiy_epaper.cpp @@ -15,7 +15,8 @@ enum EpdDrawMode updateMode = MODE_DU; /* Display initialization routine */ void epdiy_init(void) { - epd_init(&epd_board_v7, &ED097TC2, EPD_LUT_64K); +// epd_init(&epd_board_v7, &ED097TC2, EPD_LUT_64K); + epd_init(&epd_board_v7, &EC060KH3, EPD_LUT_64K); // Set VCOM for boards that allow to set this in software (in mV). // This will print an error if unsupported. In this case, // set VCOM using the hardware potentiometer and delete this line. @@ -44,29 +45,45 @@ void buf_area_to_framebuffer(const lv_area_t *area, const uint8_t *image_data) { /* A copy from epd_copy_to_framebuffer with temporary lenght prediction */ void buf_copy_to_framebuffer(EpdRect image_area, const uint8_t *image_data) { assert(framebuffer != NULL); - - for (uint32_t i = 0; i < image_area.width * image_area.height; i++) { - uint8_t val = (i % 2) ? (image_data[i / 2] & 0xF0) >> 4 : image_data[i / 2] & 0x0F; - int xx = image_area.x + i % image_area.width; - if (xx < 0 || xx >= epd_width()) { - continue; - } - int yy = image_area.y + i / image_area.width; - if (yy < 0 || yy >= epd_height()) { - continue; - } - uint8_t *buf_ptr = &framebuffer[yy * epd_width() / 2 + xx / 2]; - if (xx % 2) { - *buf_ptr = (*buf_ptr & 0x0F) | (val << 4); - } else { - *buf_ptr = (*buf_ptr & 0xF0) | val; - } - } -} + int x, xx = image_area.x; + int y, yy = image_area.y; + int w = image_area.width; + int h = image_area.height; + const uint8_t ucCLRMask[3] = {0xc0,0x38,0x7}; + uint8_t uc, *s, *d; +// source data is one byte per pixel (RGB233) + for (y=yy; y<(yy + h); y++) { + int i = (xx+y) % 3; // which color filter is in use? + s = (uint8_t *)&image_data[(y-yy) * w]; + d = &framebuffer[(y * epd_width() / 2) + (xx / 2)]; + x = xx; + if (x & 1) { + uc = d[0] & 0xf0; // special case for odd starting pixel + if (s[0] & ucCLRMask[i]) + uc |= 0xf; + i++; + s++; + *d++ = uc; + x++; + if (i >= 3) i-=3; + } + for (; x<(xx + w); x+=2) { // work 2 pixels at a time + uc = 0; + if (s[0] & ucCLRMask[i]) uc |= 0xf; + i++; if (i >= 3) i -= 3; + if (s[1] & ucCLRMask[i]) uc |= 0xf0; + i++; if (i >= 3) i -= 3; + *d++ = uc; + s += 2; + } // for x + } // for y +} /* buf_copy_to_framebuffer() */ /* Required by LVGL. Sends the color_map to the screen with a partial update */ void epdiy_flush(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_map) { +static int x1=65535,y1=65535,x2=-1,y2=-1; + ++flushcalls; uint16_t w = lv_area_get_width(area); uint16_t h = lv_area_get_height(area); @@ -78,6 +95,12 @@ void epdiy_flush(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_ma .height = h }; + // capture the upper left and lower right corners + if (area->x1 < x1) x1 = area->x1; + if (area->y1 < y1) y1 = area->y1; + if (area->x2 > x2) x2 = area->x2; + if (area->y2 > y2) y2 = area->y2; + uint8_t* buf = (uint8_t *) color_map; // Buffer debug /* for (int index=0; index<400; index++) { @@ -88,12 +111,17 @@ void epdiy_flush(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_ma //Faster mode suggested in LVGL forum (Leaves ghosting&prints bad sections / experimental) NOTE: Do NOT use in production //buf_area_to_framebuffer(area, buf); - - epd_hl_update_area(&hl, updateMode, temperature, update_area); //update_area - + if (lv_disp_flush_is_last(drv)) { // only send to e-paper when complete + update_area.x = x1; + update_area.y = y1; + update_area.width = (x2-x1)+1; + update_area.height = (y2-y1)+1; + epd_hl_update_area(&hl, updateMode, temperature, update_area); //update_area + x1 = y1 = 65535; x2 = y2 = -1; // reset update boundary + } //printf("epdiy_flush %d x:%d y:%d w:%d h:%d\n", flushcalls,(uint16_t)area->x1,(uint16_t)area->y1,w,h); /* Inform the graphics library that you are ready with the flushing */ - lv_disp_flush_ready(drv); + lv_disp_flush_ready(drv); // do this after the check for "is_last" } /* @@ -103,17 +131,5 @@ 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) { - // Test using RGB232 - int16_t epd_color = 255; - if ((int16_t)color.full < 254) { - epd_color = (updateMode==MODE_DU) ? 0 : (int16_t)color.full / 3; - } - - //Instead of using epd_draw_pixel: Set pixel directly in *buf that comes afterwards in flush as *color_map - uint16_t idx = (int16_t)y * buf_w / 2 + (int16_t)x / 2; - if (x % 2) { - buf[idx] = (buf[idx] & 0x0F) | (epd_color & 0xF0); - } else { - buf[idx] = (buf[idx] & 0xF0) | (epd_color >> 4); - } + buf[(y * buf_w)+x] = color.full; } From a1acc7e74fda249485b5c1d97400633b945bbf44 Mon Sep 17 00:00:00 2001 From: martinberlin Date: Tue, 12 Mar 2024 22:30:10 +0100 Subject: [PATCH 31/31] Keep also a copy of epdiy driver for grayscale without color filter eink panels --- .../{epdiy_epaper.c => epdiy_epaper_mono.cpp} | 60 +++++++++---------- 1 file changed, 29 insertions(+), 31 deletions(-) rename lvgl_tft/{epdiy_epaper.c => epdiy_epaper_mono.cpp} (66%) diff --git a/lvgl_tft/epdiy_epaper.c b/lvgl_tft/epdiy_epaper_mono.cpp similarity index 66% rename from lvgl_tft/epdiy_epaper.c rename to lvgl_tft/epdiy_epaper_mono.cpp index e532a797..5f2185ed 100644 --- a/lvgl_tft/epdiy_epaper.c +++ b/lvgl_tft/epdiy_epaper_mono.cpp @@ -1,18 +1,8 @@ -/************************************************************************************************** - * NOTE: This file is the first version that writes directly on the set_px callback - * each pixel into the epaper display buffer. The second version is 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 - * - * BOTH are oriented to latest version of epdiy driver that uses LCD module for parallel communication - * BRANCH: s3_lcd - **************************************************************************************************/ #include "esp_log.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "epdiy_epaper.h" -#include "epd_driver.h" -#include "epd_highlevel.h" +#include "epdiy.h" EpdiyHighlevelState hl; uint16_t flushcalls = 0; @@ -25,22 +15,28 @@ enum EpdDrawMode updateMode = MODE_DU; /* Display initialization routine */ void epdiy_init(void) { - epd_init(EPD_OPTIONS_DEFAULT); + epd_init(&epd_board_v7, &ED060XC3, EPD_LUT_64K); + // Set VCOM for boards that allow to set this in software (in mV). + // This will print an error if unsupported. In this case, + // set VCOM using the hardware potentiometer and delete this line. + epd_set_vcom(1760); hl = epd_hl_init(EPD_BUILTIN_WAVEFORM); framebuffer = epd_hl_get_framebuffer(&hl); epd_poweron(); - //Clear all always in init: + //Clear all display in initialization to remove any ghosts epd_fullclear(&hl, temperature); } -/* Suggested by @kisvegabor https://forum.lvgl.io/t/lvgl-port-to-be-used-with-epaper-displays/5630/26 */ +/* Suggested by @kisvegabor https://forum.lvgl.io/t/lvgl-port-to-be-used-with-epaper-displays/5630/26 + * @deprecated +*/ void buf_area_to_framebuffer(const lv_area_t *area, const uint8_t *image_data) { assert(framebuffer != NULL); - uint8_t *fb_ptr = &framebuffer[area->y1 * EPD_WIDTH / 2 + area->x1 / 2]; + uint8_t *fb_ptr = &framebuffer[area->y1 * epd_width() / 2 + area->x1 / 2]; lv_coord_t img_w = lv_area_get_width(area); for(uint32_t y = area->y1; y < area->y2; y++) { memcpy(fb_ptr, image_data, img_w / 2); - fb_ptr += EPD_WIDTH / 2; + fb_ptr += epd_width() / 2; image_data += img_w / 2; } } @@ -50,17 +46,16 @@ void buf_copy_to_framebuffer(EpdRect image_area, const uint8_t *image_data) { assert(framebuffer != NULL); for (uint32_t i = 0; i < image_area.width * image_area.height; i++) { - uint8_t val = (i % 2) ? (image_data[i / 2] & 0xF0) >> 4 - : image_data[i / 2] & 0x0F; + uint8_t val = (i % 2) ? (image_data[i / 2] & 0xF0) >> 4 : image_data[i / 2] & 0x0F; int xx = image_area.x + i % image_area.width; - if (xx < 0 || xx >= EPD_WIDTH) { + if (xx < 0 || xx >= epd_width()) { continue; } int yy = image_area.y + i / image_area.width; - if (yy < 0 || yy >= EPD_HEIGHT) { + if (yy < 0 || yy >= epd_height()) { continue; } - uint8_t *buf_ptr = &framebuffer[yy * EPD_WIDTH / 2 + xx / 2]; + uint8_t *buf_ptr = &framebuffer[yy * epd_width() / 2 + xx / 2]; if (xx % 2) { *buf_ptr = (*buf_ptr & 0x0F) | (val << 4); } else { @@ -85,21 +80,24 @@ void epdiy_flush(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_ma uint8_t* buf = (uint8_t *) color_map; // Buffer debug - /* - for (int index=0; index<400; index++) { + /* for (int index=0; index<400; index++) { printf("%x ", buf[index]); } */ - - // UNCOMMENT only one of this options - // SAFE Option with EPDiy copy of epd_copy_to_framebuffer + // This is the slower version that works good without leaving any white line buf_copy_to_framebuffer(update_area, buf); //Faster mode suggested in LVGL forum (Leaves ghosting&prints bad sections / experimental) NOTE: Do NOT use in production //buf_area_to_framebuffer(area, buf); - + if (lv_disp_flush_is_last(drv)) { + update_area = { + .x = 0, + .y = 0, + .width = epd_width(), + .height = epd_height() + }; epd_hl_update_area(&hl, updateMode, temperature, update_area); //update_area - - printf("epdiy_flush %d x:%d y:%d w:%d h:%d\n", flushcalls,(uint16_t)area->x1,(uint16_t)area->y1,w,h); + } + //printf("epdiy_flush %d x:%d y:%d w:%d h:%d\n", flushcalls,(uint16_t)area->x1,(uint16_t)area->y1,w,h); /* Inform the graphics library that you are ready with the flushing */ lv_disp_flush_ready(drv); } @@ -113,8 +111,8 @@ void epdiy_set_px_cb(lv_disp_drv_t * disp_drv, uint8_t* buf, { // Test using RGB232 int16_t epd_color = 255; - if ((int16_t)color.full<250) { - epd_color = (updateMode==MODE_DU) ? 0 : (int16_t)color.full/3; + if ((int16_t)color.full < 254) { + epd_color = (updateMode==MODE_DU) ? 0 : (int16_t)color.full / 3; } //Instead of using epd_draw_pixel: Set pixel directly in *buf that comes afterwards in flush as *color_map