diff --git a/CONTRIBUTE_CONTROLLER_SUPPORT.md b/CONTRIBUTE_CONTROLLER_SUPPORT.md new file mode 100644 index 0000000..db4c647 --- /dev/null +++ b/CONTRIBUTE_CONTROLLER_SUPPORT.md @@ -0,0 +1,52 @@ +# Is your driver not listed on the supported drivers list? + +Consider contributing to this demo project by adding support to your driver. + +## Display driver. + +To enable LVGL to work with your display you would need to implement from one up to three callback functions (one function for RGB TFT displays, three functions for monochrome display controllers), you can add more functions to enable backlight control, etc. + +All display controller code is stored on the `components/lvgl_esp32_drivers/lvgl_tft` directory, see `disp_driver` and `CMakeLists.txt` to add your code into the idf project. + +Create a header and source file named after the display controller (in lowercase). On the header file declare the necessary functions, such as: + +```c +/* Configure your display */ +void x_init(void); + +/* LVGL callbacks */ +void x_flush(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_map); +/* Only for monochrome displays */ +void x_rounder(lv_disp_drv_t *disp_drv, lv_area_t *area); +void x_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); +``` + +Where x is the controller name. + +For more information on the function callbacks check LVGL documentation: (Display driver)[https://docs.lvgl.io/v7/en/html/porting/display.html#display-driver]. + +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. + +## 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. + +All touch controller code is stored on the `components/lvgl_esp32_drivers/lvgl_touch` directory. + +Create a header and source file named after the display controller (in lowercase). On the header file declare the necessary functions, such as: + +```c +/* Configure your display */ +void x_init(void); + +/* LVGL callbacks */ +bool x_read(lv_disp_drv_t *drv, lv_indev_data_t *data); +``` + +Where x is the controller name. + +For more information on the function callbacks check LVGL documentation: (Display driver)[https://docs.lvgl.io/v7/en/html/porting/indev.html]. + +## Kconfig and Project Configuration + +The ESP32 SDK (ESP-IDF) uses [kconfiglib](https://github.com/ulfalizer/Kconfiglib) which is a Python-based extension to the [Kconfig](https://www.kernel.org/doc/Documentation/kbuild/kconfig-language.txt) system which provides a compile-time project configuration mechanism. Using `idf.py menuconfig` will update the file sdkconfig and, during build, provide the file sdkconfig.h. diff --git a/README.md b/README.md index 0c61046..6aeec91 100644 --- a/README.md +++ b/README.md @@ -1 +1,65 @@ -# lvgl esp32 drivers +# Display and touchpad drivers for ESP32 using LVGL + +For a ready to use ESP32 project take look at the [lv_port_esp32](https://github.com/lvgl/lv_port_esp32) repository. + +#### Table of content +- [Supported display controllers](#supported-display-controllers) +- [Supported indev controllers](#supported-indev-controllers) +- [Support for predefined development kits](#support-for-predefined-development-kits) + +**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). + + +## Supported display controllers + + +| Display Controller | Type | Interface | Color depth (LV_COLOR_DEPTH) | Swap RGB565 color (LV_COLOR_16_SWAP) | +|---------------------------------------------|------------|------------------------|------------------------------|----------------------------------------| +| ILI9341 | TFT | SPI | 16: RGB565 | Yes | +| ILI9486 | TFT | SPI | 16: RGB565 | Yes | +| ILI9488 | TFT | SPI | 16: RGB565 | No | +| HX8357B/HX8357D | TFT | SPI | 16: RGB565 | Yes | +| ST7789 | TFT | SPI | 16: RGB565 | Yes | +| ST7735S | TFT | SPI | 16: RGB565 | Yes | +| FT81x | TFT | Single, Dual, Quad SPI | 16: RGB565 | No | +| GC9A01 | TFT | SPI | 16: RGB565 | Yes | +| RA8875 | TFT | SPI | 16: RGB565 | Yes | +| SH1107 | Monochrome | SPI | 1: 1byte per pixel | No | +| SSD1306 | Monochrome | I2C | 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 | + +## Supported indev controllers + +- XPT2046 +- FT3236 +- other FT6X36 or the FT6206 controllers should work as well (not tested) +- STMPE610 +- FT81x (Single, Dual, and Quad SPI) + +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) + +## Support for predefined development kits + +You can also use the predefined kits, which selects the correct display controllers on the kit, +and sets the gpio numbers for the interface. + +| Kit name | Display controller | Interface | Hor. Res. | Ver. Res. | +|---------------------------|-----------------------|-----------|-----------|-----------| +| ESP Wrover Kit v4.1 | ILI9341 | SPI | 240 | 320 | +| M5Stack | ILI9341 | SPI | 240 | 320 | +| M5Stick | SH1107 | SPI | - | - | +| M5StickC | ST7735S | SPI | 80 | 160 | +| Adafruit 3.5 Featherwing | HX8357 | SPI | 480 | 320 | +| RPi MPI3501 | ILI9486 | SPI | - | - | +| Wemos Lolin OLED | SSD1306 | SPI | 64 | 128 | +| ER-TFT035-6 | ILI9488 | SPI | 480 | 320 | +| AIRcable ATAGv3 | IL3820 | SPI | 128 | 296 | +| TTGO T-Display | ST7789 | SPI | 135 | 240 | +| TTGO Camera Plus | ST7789 | SPI | 240 | 240 | + +**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. diff --git a/lvgl_helpers.h b/lvgl_helpers.h index 5ae6d75..05bdd2c 100644 --- a/lvgl_helpers.h +++ b/lvgl_helpers.h @@ -30,7 +30,7 @@ extern "C" { #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 -#define DISP_BUF_SIZE (CONFIG_LV_DISPLAY_WIDTH*CONFIG_LV_DISPLAY_HEIGHT) +#define DISP_BUF_SIZE (LV_HOR_RES_MAX * LV_VER_RES_MAX) #elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_ILI9481 #define DISP_BUF_SIZE (LV_HOR_RES_MAX * 40) #elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_ILI9486 @@ -40,20 +40,20 @@ extern "C" { #elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_ILI9341 #define DISP_BUF_SIZE (LV_HOR_RES_MAX * 64) #elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_SSD1306 -#define DISP_BUF_SIZE (CONFIG_LV_DISPLAY_WIDTH*CONFIG_LV_DISPLAY_HEIGHT) +#define DISP_BUF_SIZE (LV_HOR_RES_MAX*LV_VER_RES_MAX) #elif defined (CONFIG_LV_TFT_DISPLAY_CONTROLLER_FT81X) #define DISP_BUF_LINES 40 #define DISP_BUF_SIZE (LV_HOR_RES_MAX * DISP_BUF_LINES) #elif defined (CONFIG_LV_TFT_DISPLAY_CONTROLLER_IL3820) -#define DISP_BUF_SIZE (CONFIG_LV_DISPLAY_HEIGHT * IL3820_COLUMNS) +#define DISP_BUF_SIZE (LV_VER_RES_MAX * IL3820_COLUMNS) #elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_RA8875 #define DISP_BUF_SIZE (LV_HOR_RES_MAX * 40) #elif defined (CONFIG_LV_TFT_DISPLAY_CONTROLLER_GC9A01) #define DISP_BUF_SIZE (LV_HOR_RES_MAX * 40) #elif defined (CONFIG_LV_TFT_DISPLAY_CONTROLLER_JD79653A) -#define DISP_BUF_SIZE ((CONFIG_LV_DISPLAY_HEIGHT * CONFIG_LV_DISPLAY_WIDTH) / 8) // 5KB +#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 ((CONFIG_LV_DISPLAY_HEIGHT * CONFIG_LV_DISPLAY_WIDTH) / 8) // 2888 bytes +#define DISP_BUF_SIZE ((LV_VER_RES_MAX * LV_VER_RES_MAX) / 8) // 2888 bytes #else #error "No display controller selected" #endif diff --git a/lvgl_tft/Kconfig b/lvgl_tft/Kconfig index b682935..f20b9fd 100644 --- a/lvgl_tft/Kconfig +++ b/lvgl_tft/Kconfig @@ -183,9 +183,30 @@ menu "LVGL TFT Display controller" help Display controller protocol I2C + # Used in display init function to send display orientation commands + choice DISPLAY_ORIENTATION + prompt "Display orientation" + default DISPLAY_ORIENTATION_PORTRAIT + config DISPLAY_ORIENTATION_PORTRAIT + bool "Portrait" + config DISPLAY_ORIENTATION_PORTRAIT_INVERTED + bool "Portrait inverted" + config DISPLAY_ORIENTATION_LANDSCAPE + bool "Landscape" + config DISPLAY_ORIENTATION_LANDSCAPE_INVERTED + bool "Landscape inverted" + endchoice + + config LV_DISPLAY_ORIENTATION + int + 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 - help + help Display area doesn't start at address 0 config LV_TFT_DISPLAY_X_OFFSET @@ -468,101 +489,6 @@ menu "LVGL TFT Display controller" bool "I2C PORT 1" endchoice - choice - prompt "Display orientation" - depends on LV_TFT_DISPLAY_CONTROLLER_ILI9341 || \ - LV_TFT_DISPLAY_CONTROLLER_ILI9481 || \ - LV_TFT_DISPLAY_CONTROLLER_ILI9486 || \ - LV_TFT_DISPLAY_CONTROLLER_ILI9488 || \ - LV_TFT_DISPLAY_CONTROLLER_SH1107 || \ - LV_TFT_DISPLAY_CONTROLLER_SSD1306 || \ - LV_TFT_DISPLAY_CONTROLLER_FT81X || \ - LV_TFT_DISPLAY_CONTROLLER_ST7789 || \ - LV_TFT_DISPLAY_CONTROLLER_GC9A01 || \ - LV_TFT_DISPLAY_CONTROLLER_ST7735S || \ - LV_TFT_DISPLAY_CONTROLLER_IL3820 || \ - LV_TFT_DISPLAY_CONTROLLER_RA8875 || \ - LV_TFT_DISPLAY_CONTROLLER_JD79653A || \ - LV_TFT_DISPLAY_CONTROLLER_UC8151D || \ - LV_TFT_DISPLAY_CONTROLLER_ST7796S - default LV_DISPLAY_ORIENTATION_LANDSCAPE \ - if !LV_TFT_DISPLAY_CONTROLLER_JD79653A || \ - !LV_TFT_DISPLAY_CONTROLLER_UC8151D - default LV_DISPLAY_ORIENTATION_PORTRAIT if LV_TFT_DISPLAY_CONTROLLER_JD79653A || LV_TFT_DISPLAY_CONTROLLER_UC8151D - help - Display orientation. - - config LV_DISPLAY_ORIENTATION_PORTRAIT - bool "Portrait" - config LV_DISPLAY_ORIENTATION_PORTRAIT_INVERTED - bool "Inverted Portrait" - depends on !LV_TFT_DISPLAY_CONTROLLER_IL3820 - config LV_DISPLAY_ORIENTATION_LANDSCAPE - bool "Landscape" - depends on !LV_TFT_DISPLAY_CONTROLLER_JD79653A - depends on !LV_TFT_DISPLAY_CONTROLLER_UC8151D - config LV_DISPLAY_ORIENTATION_LANDSCAPE_INVERTED - bool "Inverted Landscape" - depends on !LV_TFT_DISPLAY_CONTROLLER_IL3820 - depends on !LV_TFT_DISPLAY_CONTROLLER_JD79653A - depends on !LV_TFT_DISPLAY_CONTROLLER_UC8151D - endchoice - - - # Display orientation - # This symbol is meant to be used as parameter on the display_set_orientation - # function at init. - 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 - - config LV_DISPLAY_WIDTH - int "TFT display width in pixels." if LV_PREDEFINED_DISPLAY_NONE || \ - LV_TFT_DISPLAY_CONTROLLER_FT81X - default 240 if ( LV_PREDEFINED_DISPLAY_M5STACK || LV_PREDEFINED_DISPLAY_WROVER4 ) && (LV_DISPLAY_ORIENTATION_PORTRAIT) - default 240 if ( LV_PREDEFINED_DISPLAY_M5STACK || LV_PREDEFINED_DISPLAY_WROVER4 ) && (LV_DISPLAY_ORIENTATION_PORTRAIT_INVERTED) - default 320 if ( LV_PREDEFINED_DISPLAY_M5STACK || LV_PREDEFINED_DISPLAY_WROVER4 ) && (LV_DISPLAY_ORIENTATION_LANDSCAPE) - default 320 if ( LV_PREDEFINED_DISPLAY_M5STACK || LV_PREDEFINED_DISPLAY_WROVER4 ) && (LV_DISPLAY_ORIENTATION_LANDSCAPE_INVERTED) - default 480 if LV_PREDEFINED_DISPLAY_WT32_SC01 && (LV_DISPLAY_ORIENTATION_LANDSCAPE || LV_DISPLAY_ORIENTATION_LANDSCAPE_INVERTED) - default 320 if LV_PREDEFINED_DISPLAY_WT32_SC01 && (LV_DISPLAY_ORIENTATION_PORTRAIT || LV_DISPLAY_ORIENTATION_PORTRAIT_INVERTED) - default 480 if LV_PREDEFINED_DISPLAY_ERTFT0356 || LV_PREDEFINED_DISPLAY_ADA_FEATHERWING - default 64 if ( LV_PREDEFINED_DISPLAY_WEMOS_LOLIN || LV_PREDEFINED_DISPLAY_M5STICK ) && LV_DISPLAY_ORIENTATION_PORTRAIT - default 128 if ( LV_PREDEFINED_DISPLAY_WEMOS_LOLIN || LV_PREDEFINED_DISPLAY_M5STICK ) && LV_DISPLAY_ORIENTATION_LANDSCAPE - default 800 if LV_TFT_DISPLAY_CONTROLLER_FT81X - default 128 if LV_PREDEFINED_DISPLAY_ATAG && LV_DISPLAY_ORIENTATION_PORTRAIT - default 296 if LV_PREDEFINED_DISPLAY_ATAG && LV_DISPLAY_ORIENTATION_LANDSCAPE - default 80 if LV_PREDEFINED_DISPLAY_M5STICKC && (LV_DISPLAY_ORIENTATION_PORTRAIT || LV_DISPLAY_ORIENTATION_PORTRAIT_INVERTED) - default 160 if LV_PREDEFINED_DISPLAY_M5STICKC && (LV_DISPLAY_ORIENTATION_LANDSCAPE || LV_DISPLAY_ORIENTATION_LANDSCAPE_INVERTED) - default 135 if LV_PREDEFINED_DISPLAY_TTGO && (LV_DISPLAY_ORIENTATION_PORTRAIT || LV_DISPLAY_ORIENTATION_PORTRAIT_INVERTED) - default 240 if LV_PREDEFINED_DISPLAY_TTGO && (LV_DISPLAY_ORIENTATION_LANDSCAPE || LV_DISPLAY_ORIENTATION_LANDSCAPE_INVERTED) - default 240 if LV_PREDEFINED_DISPLAY_TTGO_CAMERA_PLUS - default 320 - - config LV_DISPLAY_HEIGHT - int "TFT display height in pixels." if LV_PREDEFINED_DISPLAY_NONE || \ - LV_TFT_DISPLAY_CONTROLLER_FT81X - default 320 if ( LV_PREDEFINED_DISPLAY_M5STACK || LV_PREDEFINED_DISPLAY_WROVER4 ) && (LV_DISPLAY_ORIENTATION_PORTRAIT) - default 320 if ( LV_PREDEFINED_DISPLAY_M5STACK || LV_PREDEFINED_DISPLAY_WROVER4 ) && (LV_DISPLAY_ORIENTATION_PORTRAIT_INVERTED) - default 240 if ( LV_PREDEFINED_DISPLAY_M5STACK || LV_PREDEFINED_DISPLAY_WROVER4 ) && (LV_DISPLAY_ORIENTATION_LANDSCAPE) - default 240 if ( LV_PREDEFINED_DISPLAY_M5STACK || LV_PREDEFINED_DISPLAY_WROVER4 ) && (LV_DISPLAY_ORIENTATION_LANDSCAPE_INVERTED) - default 480 if LV_PREDEFINED_DISPLAY_WT32_SC01 && (LV_DISPLAY_ORIENTATION_PORTRAIT || LV_DISPLAY_ORIENTATION_PORTRAIT_INVERTED) - default 320 if LV_PREDEFINED_DISPLAY_WT32_SC01 && (LV_DISPLAY_ORIENTATION_LANDSCAPE || LV_DISPLAY_ORIENTATION_LANDSCAPE_INVERTED) - default 320 if LV_PREDEFINED_DISPLAY_ERTFT0356 || LV_PREDEFINED_DISPLAY_ADA_FEATHERWING - default 128 if ( LV_PREDEFINED_DISPLAY_WEMOS_LOLIN || LV_PREDEFINED_DISPLAY_M5STICK ) && LV_DISPLAY_ORIENTATION_PORTRAIT - default 64 if ( LV_PREDEFINED_DISPLAY_WEMOS_LOLIN || LV_PREDEFINED_DISPLAY_M5STICK ) && LV_DISPLAY_ORIENTATION_LANDSCAPE - default 480 if LV_TFT_DISPLAY_CONTROLLER_FT81X - default 296 if LV_PREDEFINED_DISPLAY_ATAG && LV_DISPLAY_ORIENTATION_PORTRAIT - default 128 if LV_PREDEFINED_DISPLAY_ATAG && LV_DISPLAY_ORIENTATION_LANDSCAPE - default 160 if LV_PREDEFINED_DISPLAY_M5STICKC && (LV_DISPLAY_ORIENTATION_PORTRAIT || LV_DISPLAY_ORIENTATION_PORTRAIT_INVERTED) - default 80 if LV_PREDEFINED_DISPLAY_M5STICKC && (LV_DISPLAY_ORIENTATION_LANDSCAPE || LV_DISPLAY_ORIENTATION_LANDSCAPE_INVERTED) - default 240 if LV_PREDEFINED_DISPLAY_TTGO && (LV_DISPLAY_ORIENTATION_PORTRAIT || LV_DISPLAY_ORIENTATION_PORTRAIT_INVERTED) - default 135 if LV_PREDEFINED_DISPLAY_TTGO && (LV_DISPLAY_ORIENTATION_LANDSCAPE || LV_DISPLAY_ORIENTATION_LANDSCAPE_INVERTED) - default 240 if LV_PREDEFINED_DISPLAY_TTGO_CAMERA_PLUS - default 240 - config LV_TFT_USE_CUSTOM_SPI_CLK_DIVIDER bool "Use custom SPI clock frequency." if LV_TFT_DISPLAY_PROTOCOL_SPI default n diff --git a/lvgl_tft/il3820.c b/lvgl_tft/il3820.c index 8c1c20c..71b3970 100644 --- a/lvgl_tft/il3820.c +++ b/lvgl_tft/il3820.c @@ -49,7 +49,7 @@ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR TH #define BIT_CLEAR(a,b) ((a) &= ~(1U<<(b))) /* Number of pixels? */ -#define IL3820_PIXEL (CONFIG_LV_DISPLAY_WIDTH * CONFIG_LV_DISPLAY_HEIGHT) +#define IL3820_PIXEL (LV_HOR_RES_MAX * LV_VER_RES_MAX) #define EPD_PANEL_NUMOF_COLUMS EPD_PANEL_WIDTH #define EPD_PANEL_NUMOF_ROWS_PER_PAGE 8 diff --git a/lvgl_tft/il3820.h b/lvgl_tft/il3820.h index 15ff090..3969d8f 100644 --- a/lvgl_tft/il3820.h +++ b/lvgl_tft/il3820.h @@ -20,8 +20,8 @@ extern "C" /* Values for Waveshare 2.9inch e-Paper Module, this values shouldn't be * swapped to change display orientation */ -#define EPD_PANEL_WIDTH CONFIG_LV_DISPLAY_WIDTH /* 128 */ -#define EPD_PANEL_HEIGHT CONFIG_LV_DISPLAY_HEIGHT /* 296 */ +#define EPD_PANEL_WIDTH LV_HOR_RES_MAX /* 128 */ +#define EPD_PANEL_HEIGHT LV_VER_RES_MAX /* 296 */ /* 128 = panel width */ #define IL3820_COLUMNS (EPD_PANEL_WIDTH / 8) diff --git a/lvgl_tft/jd79653a.c b/lvgl_tft/jd79653a.c index e39e747..0f4be67 100644 --- a/lvgl_tft/jd79653a.c +++ b/lvgl_tft/jd79653a.c @@ -43,8 +43,8 @@ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR TH #define PIN_BUSY CONFIG_LV_DISP_PIN_BUSY #define PIN_BUSY_BIT ((1ULL << (uint8_t)(CONFIG_LV_DISP_PIN_BUSY))) #define EVT_BUSY (1UL << 0UL) -#define EPD_WIDTH CONFIG_LV_DISPLAY_WIDTH -#define EPD_HEIGHT CONFIG_LV_DISPLAY_HEIGHT +#define EPD_WIDTH LV_HOR_RES_MAX +#define EPD_HEIGHT LV_VER_RES_MAX #define EPD_ROW_LEN (EPD_HEIGHT / 8u) #define EPD_PARTIAL_CNT 5; diff --git a/lvgl_tft/ra8875.c b/lvgl_tft/ra8875.c index 04638d8..98eea02 100644 --- a/lvgl_tft/ra8875.c +++ b/lvgl_tft/ra8875.c @@ -37,8 +37,8 @@ #endif #define BYTES_PER_PIXEL (LV_COLOR_DEPTH / 8) -#define HDWR_VAL (CONFIG_LV_DISPLAY_WIDTH/8 - 1) -#define VDHR_VAL (CONFIG_LV_DISPLAY_HEIGHT - 1) +#define HDWR_VAL (LV_HOR_RES_MAX/8 - 1) +#define VDHR_VAL (LV_VER_RES_MAX - 1) #define VDIR_MASK (1 << 2) #define HDIR_MASK (1 << 3) @@ -248,7 +248,7 @@ void ra8875_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * colo #if DEBUG ESP_LOGI(TAG, "flush: set window (x1,x2): %d,%d -> %d,%d", x1, x2, area->x1, area->x2); #endif - ra8875_set_window(area->x1, area->x2, 0, CONFIG_LV_DISPLAY_HEIGHT-1); + ra8875_set_window(area->x1, area->x2, 0, LV_VER_RES_MAX-1); x1 = area->x1; x2 = area->x2; } @@ -264,7 +264,7 @@ void ra8875_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * colo // Update to future cursor location y = area->y2 + 1; - if (y >= CONFIG_LV_DISPLAY_HEIGHT) { + if (y >= LV_VER_RES_MAX) { y = 0; } diff --git a/lvgl_tft/sh1107.c b/lvgl_tft/sh1107.c index 90388dc..6fc1d5a 100644 --- a/lvgl_tft/sh1107.c +++ b/lvgl_tft/sh1107.c @@ -124,10 +124,10 @@ void sh1107_set_px_cb(struct _disp_drv_t * disp_drv, uint8_t * buf, lv_coord_t b uint8_t bit_index = 0; #if defined CONFIG_LV_DISPLAY_ORIENTATION_LANDSCAPE - byte_index = y + (( x>>3 ) * CONFIG_LV_DISPLAY_HEIGHT); + byte_index = y + (( x>>3 ) * LV_VER_RES_MAX); bit_index = x & 0x7; #elif defined CONFIG_LV_DISPLAY_ORIENTATION_PORTRAIT - byte_index = x + (( y>>3 ) * CONFIG_LV_DISPLAY_WIDTH); + byte_index = x + (( y>>3 ) * LV_HOR_RES_MAX); bit_index = y & 0x7; #endif @@ -159,9 +159,9 @@ void sh1107_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * colo sh1107_send_cmd(0xB0 | i); // Set Page Start Address for Page Addressing Mode size = area->y2 - area->y1 + 1; #if defined CONFIG_LV_DISPLAY_ORIENTATION_LANDSCAPE - ptr = color_map + i * CONFIG_LV_DISPLAY_HEIGHT; + ptr = color_map + i * LV_VER_RES_MAX; #else - ptr = color_map + i * CONFIG_LV_DISPLAY_WIDTH; + ptr = color_map + i * LV_HOR_RES_MAX; #endif if(i != row2){ sh1107_send_data( (void *) ptr, size); @@ -177,8 +177,8 @@ void sh1107_rounder(struct _disp_drv_t * disp_drv, lv_area_t *area) // workaround: always send complete size display buffer area->x1 = 0; area->y1 = 0; - area->x2 = CONFIG_LV_DISPLAY_WIDTH-1; - area->y2 = CONFIG_LV_DISPLAY_HEIGHT-1; + area->x2 = LV_HOR_RES_MAX-1; + area->y2 = LV_VER_RES_MAX-1; } void sh1107_sleep_in() diff --git a/lvgl_tft/ssd1306.c b/lvgl_tft/ssd1306.c index c01efcd..e2be65e 100644 --- a/lvgl_tft/ssd1306.c +++ b/lvgl_tft/ssd1306.c @@ -130,7 +130,7 @@ void ssd1306_init() i2c_cmd_link_delete(cmd); } -void ssd1306_set_px_cb(struct _disp_drv_t * disp_drv, uint8_t * buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y, +void ssd1306_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) { uint16_t byte_index = x + (( y>>3 ) * buf_w); uint8_t bit_index = y & 0x7; @@ -147,13 +147,9 @@ void ssd1306_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t uint8_t row1 = 0, row2 = 0; i2c_cmd_handle_t cmd; -#if defined CONFIG_LV_DISPLAY_ORIENTATION_LANDSCAPE - row1 = area->y1>>3; - row2 = area->y2>>3; -#else - row1 = area->y1>>3; - row2 = area->y2>>3; -#endif + // Divide by 8 + row1 = area->y1 >> 3; + row2 = area->y2 >> 3; cmd = i2c_cmd_link_create(); i2c_master_start(cmd); @@ -185,16 +181,19 @@ void ssd1306_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t lv_disp_flush_ready(disp_drv); } -void ssd1306_rounder(struct _disp_drv_t * disp_drv, lv_area_t *area) +// workaround: always send complete size display buffer, no partial update +void ssd1306_rounder(lv_disp_drv_t * disp_drv, lv_area_t *area) { // area->y1 = (area->y1 & (~0x7)); // area->y2 = (area->y2 & (~0x7)) + 7; - // workaround: always send complete size display buffer + uint8_t hor_max = disp_drv->hor_res; + uint8_t ver_max = disp_drv->ver_res; + area->x1 = 0; area->y1 = 0; - area->x2 = CONFIG_LV_DISPLAY_WIDTH-1; - area->y2 = CONFIG_LV_DISPLAY_HEIGHT-1; + area->x2 = hor_max - 1; + area->y2 = ver_max - 1; } void ssd1306_sleep_in() diff --git a/lvgl_tft/ssd1306.h b/lvgl_tft/ssd1306.h index f859a76..2145493 100644 --- a/lvgl_tft/ssd1306.h +++ b/lvgl_tft/ssd1306.h @@ -38,8 +38,8 @@ extern "C" { **********************/ void ssd1306_init(void); void ssd1306_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * color_map); -void ssd1306_rounder(struct _disp_drv_t * disp_drv, lv_area_t *area); -void ssd1306_set_px_cb(struct _disp_drv_t * disp_drv, uint8_t * buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y, +void ssd1306_rounder(lv_disp_drv_t * disp_drv, lv_area_t *area); +void ssd1306_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 ssd1306_sleep_in(void); diff --git a/lvgl_tft/st7735s.h b/lvgl_tft/st7735s.h index 03672ee..de47140 100644 --- a/lvgl_tft/st7735s.h +++ b/lvgl_tft/st7735s.h @@ -23,7 +23,6 @@ extern "C" { /********************* * DEFINES *********************/ -// #define DISP_BUF_SIZE (CONFIG_LV_DISPLAY_WIDTH*CONFIG_LV_DISPLAY_HEIGHT) #define DISP_BUF_SIZE (LV_HOR_RES_MAX * 40) #define ST7735S_DC CONFIG_LV_DISP_PIN_DC diff --git a/lvgl_tft/uc8151d.c b/lvgl_tft/uc8151d.c index 3332120..d353225 100644 --- a/lvgl_tft/uc8151d.c +++ b/lvgl_tft/uc8151d.c @@ -44,8 +44,8 @@ #define PIN_BUSY CONFIG_LV_DISP_PIN_BUSY #define PIN_BUSY_BIT ((1ULL << (uint8_t)(CONFIG_LV_DISP_PIN_BUSY))) #define EVT_BUSY (1UL << 0UL) -#define EPD_WIDTH CONFIG_LV_DISPLAY_WIDTH -#define EPD_HEIGHT CONFIG_LV_DISPLAY_HEIGHT +#define EPD_WIDTH LV_HOR_RES_MAX +#define EPD_HEIGHT LV_VER_RES_MAX #define EPD_ROW_LEN (EPD_HEIGHT / 8u) #define BIT_SET(a, b) ((a) |= (1U << (b))) diff --git a/lvgl_touch/Kconfig b/lvgl_touch/Kconfig index bbcdad7..659cf02 100644 --- a/lvgl_touch/Kconfig +++ b/lvgl_touch/Kconfig @@ -99,7 +99,6 @@ menu "LVGL Touch controller" range 0 39 default 35 if LV_PREDEFINED_PINS_38V1 default 19 - help Configure the touchpanel MISO pin here. @@ -109,7 +108,6 @@ menu "LVGL Touch controller" range 0 39 default 32 if LV_PREDEFINED_PINS_38V1 default 23 - help Configure the touchpanel MOSI pin here. @@ -135,7 +133,7 @@ menu "LVGL Touch controller" default 27 if LV_PREDEFINED_PINS_38V4 default 25 help - Configure the touchpanel CS pin here. + Configure the touchpanel IRQ pin here. endmenu menu "Touchpanel Configuration (XPT2046)" @@ -180,6 +178,19 @@ menu "LVGL Touch controller" prompt "Invert Y coordinate value." default y + choice + prompt "Select touch detection method." + default LV_TOUCH_DETECT_IRQ + help + Select the controller for your touch panel. + + config LV_TOUCH_DETECT_IRQ + bool "IRQ pin only" + config LV_TOUCH_DETECT_IRQ_PRESSURE + bool "IRQ pin and pressure" + config LV_TOUCH_DETECT_PRESSURE + bool "Pressure only" + endchoice endmenu menu "Touchpanel (FT6X06) Pin Assignments" diff --git a/lvgl_touch/adcraw.h b/lvgl_touch/adcraw.h index 5c555cc..5015d12 100644 --- a/lvgl_touch/adcraw.h +++ b/lvgl_touch/adcraw.h @@ -38,16 +38,16 @@ extern "C" { /*GetMaxX Macro*/ #if CONFIG_LV_DISPLAY_ORIENTATION_LANDSCAPE -#define GetMaxX() (CONFIG_LV_DISPLAY_WIDTH - 1) +#define GetMaxX() (LV_HOR_RES_MAX - 1) #else -#define GetMaxX() (CONFIG_LV_DISPLAY_HEIGHT - 1) +#define GetMaxX() (LV_VER_RES_MAX - 1) #endif /*GetMaxY Macro*/ #if CONFIG_LV_DISPLAY_ORIENTATION_LANDSCAPE -#define GetMaxY() (CONFIG_LV_DISPLAY_HEIGHT - 1) +#define GetMaxY() (LV_VER_RES_MAX - 1) #else -#define GetMaxY() (CONFIG_LV_DISPLAY_WIDTH - 1) +#define GetMaxY() (LV_HOR_RES_MAX - 1) #endif #ifndef CONCAT3 diff --git a/lvgl_touch/ft6x36.c b/lvgl_touch/ft6x36.c index 7cbb45d..6e67d29 100644 --- a/lvgl_touch/ft6x36.c +++ b/lvgl_touch/ft6x36.c @@ -27,6 +27,7 @@ #endif #include "ft6x36.h" #include "tp_i2c.h" +#include "../lvgl_i2c_conf.h" #define TAG "FT6X36" @@ -46,7 +47,7 @@ esp_err_t ft6x06_i2c_read8(uint8_t slave_addr, uint8_t register_addr, uint8_t *d i2c_master_read_byte(i2c_cmd, data_buf, I2C_MASTER_NACK); i2c_master_stop(i2c_cmd); - esp_err_t ret = i2c_master_cmd_begin(I2C_NUM_0, i2c_cmd, 1000 / portTICK_RATE_MS); + 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; } @@ -145,7 +146,7 @@ bool ft6x36_read(lv_indev_drv_t *drv, lv_indev_data_t *data) { 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(I2C_NUM_0, i2c_cmd, 1000 / portTICK_RATE_MS); + 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 getting X coordinates: %s", esp_err_to_name(ret)); @@ -168,7 +169,7 @@ bool ft6x36_read(lv_indev_drv_t *drv, lv_indev_data_t *data) { 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(I2C_NUM_0, i2c_cmd, 1000 / portTICK_RATE_MS); + 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)); diff --git a/lvgl_touch/xpt2046.c b/lvgl_touch/xpt2046.c index b6fe51b..93b4329 100644 --- a/lvgl_touch/xpt2046.c +++ b/lvgl_touch/xpt2046.c @@ -18,18 +18,26 @@ *********************/ #define TAG "XPT2046" -#define CMD_X_READ 0b10010000 -#define CMD_Y_READ 0b11010000 +#define CMD_X_READ 0b10010000 // NOTE: XPT2046 data sheet says this is actually Y +#define CMD_Y_READ 0b11010000 // NOTE: XPT2046 data sheet says this is actually X +#define CMD_Z1_READ 0b10110000 +#define CMD_Z2_READ 0b11000000 /********************** * TYPEDEFS **********************/ +typedef enum { + TOUCH_NOT_DETECTED = 0, + TOUCH_DETECTED = 1, +} xpt2046_touch_detect_t; /********************** * STATIC PROTOTYPES **********************/ static void xpt2046_corr(int16_t * x, int16_t * y); static void xpt2046_avg(int16_t * x, int16_t * y); +static int16_t xpt2046_cmd(uint8_t cmd); +static xpt2046_touch_detect_t xpt2048_is_touch_detected(); /********************** * STATIC VARIABLES @@ -51,6 +59,9 @@ uint8_t avg_last; */ void xpt2046_init(void) { + ESP_LOGI(TAG, "XPT2046 Initialization"); + +#if XPT2046_TOUCH_IRQ || XPT2046_TOUCH_IRQ_PRESS gpio_config_t irq_config = { .pin_bit_mask = BIT64(XPT2046_IRQ), .mode = GPIO_MODE_INPUT, @@ -59,10 +70,9 @@ void xpt2046_init(void) .intr_type = GPIO_INTR_DISABLE, }; - ESP_LOGI(TAG, "XPT2046 Initialization"); - esp_err_t ret = gpio_config(&irq_config); assert(ret == ESP_OK); +#endif } /** @@ -74,39 +84,33 @@ bool xpt2046_read(lv_indev_drv_t * drv, lv_indev_data_t * data) { static int16_t last_x = 0; static int16_t last_y = 0; - bool valid = true; + bool valid = false; - int16_t x = 0; - int16_t y = 0; + int16_t x = last_x; + int16_t y = last_y; + if (xpt2048_is_touch_detected() == TOUCH_DETECTED) + { + valid = true; - uint8_t irq = gpio_get_level(XPT2046_IRQ); + x = xpt2046_cmd(CMD_X_READ); + y = xpt2046_cmd(CMD_Y_READ); + ESP_LOGI(TAG, "P(%d,%d)", x, y); - if (irq == 0) { - uint8_t data[2]; - - tp_spi_read_reg(CMD_X_READ, data, 2); - x = (data[0] << 8) | data[1]; - - tp_spi_read_reg(CMD_Y_READ, data, 2); - y = (data[0] << 8) | data[1]; - ESP_LOGI(TAG, "P(%d,%d)", x, y); - /*Normalize Data back to 12-bits*/ x = x >> 4; y = y >> 4; ESP_LOGI(TAG, "P_norm(%d,%d)", x, y); - + xpt2046_corr(&x, &y); xpt2046_avg(&x, &y); last_x = x; last_y = y; - ESP_LOGI(TAG, "x = %d, y = %d", x, y); - } else { - x = last_x; - y = last_y; + ESP_LOGI(TAG, "x = %d, y = %d", x, y); + } + else + { avg_last = 0; - valid = false; } data->point.x = x; @@ -119,6 +123,42 @@ bool xpt2046_read(lv_indev_drv_t * drv, lv_indev_data_t * data) /********************** * STATIC FUNCTIONS **********************/ +static xpt2046_touch_detect_t xpt2048_is_touch_detected() +{ + // check IRQ pin if we IRQ or IRQ and preessure +#if XPT2046_TOUCH_IRQ || XPT2046_TOUCH_IRQ_PRESS + uint8_t irq = gpio_get_level(XPT2046_IRQ); + + if (irq != 0) { + return TOUCH_NOT_DETECTED; + } +#endif + // check pressure if we are pressure or IRQ and pressure +#if XPT2046_TOUCH_PRESS || XPT2046_TOUCH_IRQ_PRESS + int16_t z1 = xpt2046_cmd(CMD_Z1_READ) >> 3; + int16_t z2 = xpt2046_cmd(CMD_Z2_READ) >> 3; + + // this is not what the confusing datasheet says but it seems to + // be enough to detect real touches on the panel + int16_t z = z1 + 4096 - z2; + + if (z < XPT2046_TOUCH_THRESHOLD) + { + return TOUCH_NOT_DETECTED; + } +#endif + + return TOUCH_DETECTED; +} + +static int16_t xpt2046_cmd(uint8_t cmd) +{ + uint8_t data[2]; + tp_spi_read_reg(cmd, data, 2); + int16_t val = (data[0] << 8) | data[1]; + return val; +} + static void xpt2046_corr(int16_t * x, int16_t * y) { #if XPT2046_XY_SWAP != 0 diff --git a/lvgl_touch/xpt2046.h b/lvgl_touch/xpt2046.h index 8d61ce8..016a351 100644 --- a/lvgl_touch/xpt2046.h +++ b/lvgl_touch/xpt2046.h @@ -27,14 +27,18 @@ extern "C" { *********************/ #define XPT2046_IRQ CONFIG_LV_TOUCH_PIN_IRQ -#define XPT2046_AVG 4 -#define XPT2046_X_MIN CONFIG_LV_TOUCH_X_MIN -#define XPT2046_Y_MIN CONFIG_LV_TOUCH_Y_MIN -#define XPT2046_X_MAX CONFIG_LV_TOUCH_X_MAX -#define XPT2046_Y_MAX CONFIG_LV_TOUCH_Y_MAX -#define XPT2046_X_INV CONFIG_LV_TOUCH_INVERT_X -#define XPT2046_Y_INV CONFIG_LV_TOUCH_INVERT_Y -#define XPT2046_XY_SWAP CONFIG_LV_TOUCH_XY_SWAP +#define XPT2046_AVG 4 +#define XPT2046_X_MIN CONFIG_LV_TOUCH_X_MIN +#define XPT2046_Y_MIN CONFIG_LV_TOUCH_Y_MIN +#define XPT2046_X_MAX CONFIG_LV_TOUCH_X_MAX +#define XPT2046_Y_MAX CONFIG_LV_TOUCH_Y_MAX +#define XPT2046_X_INV CONFIG_LV_TOUCH_INVERT_X +#define XPT2046_Y_INV CONFIG_LV_TOUCH_INVERT_Y +#define XPT2046_XY_SWAP CONFIG_LV_TOUCH_XY_SWAP +#define XPT2046_TOUCH_THRESHOLD 400 // Threshold for touch detection +#define XPT2046_TOUCH_IRQ CONFIG_LV_TOUCH_DETECT_IRQ +#define XPT2046_TOUCH_IRQ_PRESS CONFIG_LV_TOUCH_DETECT_IRQ_PRESSURE +#define XPT2046_TOUCH_PRESS CONFIG_LV_TOUCH_DETECT_PRESSURE /********************** * TYPEDEFS