From 21f81d117b49c8e0097bc9ac435ed3124d39d96f Mon Sep 17 00:00:00 2001 From: Martin Lindberg Mogensen Date: Thu, 29 Apr 2021 09:55:22 +0200 Subject: [PATCH] Support ILI9163c (Sparkfun LCD-15143) --- CMakeLists.txt | 2 + README.md | 1 + lvgl_helpers.h | 2 + lvgl_spi_conf.h | 7 +- lvgl_tft/Kconfig | 15 ++- lvgl_tft/disp_driver.c | 8 +- lvgl_tft/disp_driver.h | 2 + lvgl_tft/ili9163c.c | 270 +++++++++++++++++++++++++++++++++++++++++ lvgl_tft/ili9163c.h | 65 ++++++++++ 9 files changed, 365 insertions(+), 7 deletions(-) create mode 100644 lvgl_tft/ili9163c.c create mode 100644 lvgl_tft/ili9163c.h diff --git a/CMakeLists.txt b/CMakeLists.txt index d86bd33..5832233 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -41,6 +41,8 @@ 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") else() message(WARNING "LVGL ESP32 drivers: Display controller not defined.") endif() diff --git a/README.md b/README.md index 6aeec91..70fa047 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,7 @@ 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 | diff --git a/lvgl_helpers.h b/lvgl_helpers.h index 70ef353..081a843 100644 --- a/lvgl_helpers.h +++ b/lvgl_helpers.h @@ -73,6 +73,8 @@ 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) #else #error "No display controller selected" #endif diff --git a/lvgl_spi_conf.h b/lvgl_spi_conf.h index 16e63b4..b5e7901 100644 --- a/lvgl_spi_conf.h +++ b/lvgl_spi_conf.h @@ -130,7 +130,8 @@ 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_JD79653A) || \ + defined (CONFIG_LV_TFT_DISPLAY_CONTROLLER_ILI9163C) #define SPI_BUS_MAX_TRANSFER_SZ (DISP_BUF_SIZE * 2) @@ -157,7 +158,9 @@ 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_FT81X) +#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) #define SPI_TFT_CLOCK_SPEED_HZ (32*1000*1000) #else #define SPI_TFT_CLOCK_SPEED_HZ (40*1000*1000) diff --git a/lvgl_tft/Kconfig b/lvgl_tft/Kconfig index ddd7f51..e822f60 100644 --- a/lvgl_tft/Kconfig +++ b/lvgl_tft/Kconfig @@ -165,6 +165,11 @@ menu "LVGL TFT Display controller" help ST7796S display controller. + config LV_TFT_DISPLAY_CONTROLLER_ILI9163C + bool + help + ILI9163C display controller. + # Display controller communication protocol # # This symbols define the communication protocol used by the @@ -327,6 +332,10 @@ menu "LVGL TFT 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 endchoice config CUSTOM_DISPLAY_BUFFER_SIZE @@ -586,7 +595,7 @@ menu "LVGL TFT 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 + 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_ILI9163C default y if LV_PREDEFINED_DISPLAY_M5STACK || LV_PREDEFINED_DISPLAY_M5STICKC help If the colors look inverted on your display, try enabling this. @@ -744,11 +753,11 @@ menu "LVGL TFT 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 diff --git a/lvgl_tft/disp_driver.c b/lvgl_tft/disp_driver.c index 9f8e857..adae2ad 100644 --- a/lvgl_tft/disp_driver.c +++ b/lvgl_tft/disp_driver.c @@ -21,7 +21,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(); @@ -39,6 +39,8 @@ 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(); #endif } @@ -76,6 +78,8 @@ 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); #endif } @@ -95,7 +99,7 @@ void disp_driver_rounder(lv_disp_drv_t * disp_drv, lv_area_t * area) } 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); diff --git a/lvgl_tft/disp_driver.h b/lvgl_tft/disp_driver.h index e48d05e..2e369cc 100644 --- a/lvgl_tft/disp_driver.h +++ b/lvgl_tft/disp_driver.h @@ -50,6 +50,8 @@ 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" #endif /********************* diff --git a/lvgl_tft/ili9163c.c b/lvgl_tft/ili9163c.c new file mode 100644 index 0000000..77346e4 --- /dev/null +++ b/lvgl_tft/ili9163c.c @@ -0,0 +1,270 @@ +/** + * @file ILI9163C.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "ili9163c.h" +#include "disp_spi.h" +#include "driver/gpio.h" +#include "esp_log.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "assert.h" + +/********************* + * DEFINES + *********************/ +#define TAG "ILI9163C" + +// ILI9163C specific commands used in init +#define ILI9163C_NOP 0x00 +#define ILI9163C_SWRESET 0x01 +#define ILI9163C_RDDID 0x04 +#define ILI9163C_RDDST 0x09 + +#define ILI9163C_SLPIN 0x10 +#define ILI9163C_SLPOUT 0x11 +#define ILI9163C_PTLON 0x12 +#define ILI9163C_NORON 0x13 + +#define ILI9163C_INVOFF 0x20 +#define ILI9163C_INVON 0x21 +#define ILI9163C_CMD_GAMST 0x26 +#define ILI9163C_DISPOFF 0x28 +#define ILI9163C_DISPON 0x29 +#define ILI9163C_CASET 0x2A +#define ILI9163C_RASET 0x2B +#define ILI9163C_RAMWR 0x2C +#define ILI9163C_COLORSET 0x2D +#define ILI9163C_RAMRD 0x2E + +#define ILI9163C_PTLAR 0x30 +#define ILI9163C_VSCRDEF 0x33 +#define ILI9163C_COLMOD 0x3A +#define ILI9163C_MADCTL 0x36 +#define ILI9163C_VSCRSADD 0x37 + +#define ILI9163C_FRMCTR1 0xB1 +#define ILI9163C_FRMCTR2 0xB2 +#define ILI9163C_FRMCTR3 0xB3 +#define ILI9163C_INVCTR 0xB4 +#define ILI9163C_DISSET5 0xB6 +#define ILI9163C_SDDC 0xB7 + +#define ILI9163C_PWCTR1 0xC0 +#define ILI9163C_PWCTR2 0xC1 +#define ILI9163C_PWCTR3 0xC2 +#define ILI9163C_PWCTR4 0xC3 +#define ILI9163C_PWCTR5 0xC4 +#define ILI9163C_VMCTR1 0xC5 +#define ILI9163C_VMCOFFS 0xC7 + +#define ILI9163C_GAMCTL 0xF2 + +#define ILI9163C_GMCTRP1 0xE0 +#define ILI9163C_GMCTRN1 0xE1 + +#define ST77XX_MADCTL_MY 0x80 +#define ST77XX_MADCTL_MX 0x40 +#define ST77XX_MADCTL_MV 0x20 #define +#define ST77XX_MADCTL_ML 0x10 +#define ST77XX_MADCTL_RGB 0x00 +#define ST77XX_MADCTL_BGR 0x08 + +/********************** + * TYPEDEFS + **********************/ + +/*The LCD needs a bunch of command/argument values to be initialized. They are stored in this struct. */ +typedef struct +{ + uint8_t cmd; + uint8_t data[16]; + uint8_t databytes; //No of data in data; bit 7 = delay after set; 0xFF = end of cmds. +} lcd_init_cmd_t; + +/********************** + * STATIC PROTOTYPES + **********************/ +static void ili9163c_set_orientation(uint8_t orientation); + +static void ili9163c_send_cmd(uint8_t cmd); +static void ili9163c_send_data(void *data, uint16_t length); +static void ili9163c_send_color(void *data, uint16_t length); + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +void ili9163c_init(void) +{ + ESP_LOGD(TAG, "Init"); + + lcd_init_cmd_t ili_init_cmds[] = { + {ILI9163C_SWRESET, {0}, 0x80}, // Software reset, 0 args, w/delay 120ms + {ILI9163C_SLPOUT, {0}, 0x80}, // Out of sleep mode, 0 args, w/delay 5ms + {ILI9163C_CMD_GAMST, {0x04}, 1}, // Gamma Curve + {ILI9163C_FRMCTR1, {0x0C, 0x14}, 2}, // Frame rate ctrl - normal mode + {ILI9163C_INVCTR, {0x07}, 1}, // Display inversion ctrl, 1 arg, no delay:No inversion + {ILI9163C_PWCTR1, {0x0C, 0x05}, 2}, // Power control, 2 args, no delay + {ILI9163C_PWCTR2, {0x02}, 1}, // Power control, 1 arg + {ILI9163C_PWCTR3, {0x02}, 1}, // Power control, 1 arg + {ILI9163C_VMCTR1, {0x20, 0x55}, 2}, // Power control, 1 arg, no delay: + {ILI9163C_VMCOFFS, {0x40}, 1}, // VCOM Offset +#if ILI9163C_INVERT_COLORS == 1 + {ILI9163C_INVON, {0}, 0}, // set inverted mode +#else + {ILI9163C_INVOFF, {0}, 0}, // set non-inverted mode +#endif + {ILI9163C_COLMOD, {0x5}, 1}, // set color mode, 1 arg, no delay: 16-bit color + {ILI9163C_SDDC, {0}, 1}, // set source driver direction control + {ILI9163C_GAMCTL, {0x01}, 1}, // set source driver direction control + {ILI9163C_GMCTRP1, {0x36, 0x29, 0x12, 0x22, 0x1C, 0x15, 0x42, 0xB7, 0x2F, 0x13, 0x12, 0x0A, 0x11, 0x0B, 0x06}, 16}, // 16 args, no delay: + {ILI9163C_GMCTRN1, {0x09, 0x16, 0x2D, 0x0D, 0x13, 0x15, 0x40, 0x48, 0x53, 0x0C, 0x1D, 0x25, 0x2E, 0x34, 0x39}, 16}, // 16 args, no delay: + {ILI9163C_NORON, {0}, 0x80}, // Normal display on, no args, w/delay 10 ms delay + {ILI9163C_DISPON, {0}, 0x80}, // Main screen turn on, no args w/delay 100 ms delay + {0, {0}, 0xff} + }; + + //Initialize non-SPI GPIOs + gpio_pad_select_gpio(ILI9163C_DC); + gpio_set_direction(ILI9163C_DC, GPIO_MODE_OUTPUT); + gpio_pad_select_gpio(ILI9163C_RST); + gpio_set_direction(ILI9163C_RST, GPIO_MODE_OUTPUT); + +#if ILI9163C_ENABLE_BACKLIGHT_CONTROL + gpio_pad_select_gpio(ILI9163C_BCKL); + gpio_set_direction(ILI9163C_BCKL, GPIO_MODE_OUTPUT); +#endif + //Reset the display + gpio_set_level(ILI9163C_RST, 0); + vTaskDelay(100 / portTICK_RATE_MS); + gpio_set_level(ILI9163C_RST, 1); + vTaskDelay(150 / portTICK_RATE_MS); + + //Send all the commands + uint16_t cmd = 0; + while (ili_init_cmds[cmd].databytes != 0xff) + { + ili9163c_send_cmd(ili_init_cmds[cmd].cmd); + ili9163c_send_data(ili_init_cmds[cmd].data, ili_init_cmds[cmd].databytes & 0x1F); + if (ili_init_cmds[cmd].databytes & 0x80) + { + vTaskDelay(150 / portTICK_RATE_MS); + } + cmd++; + } + + ili9163c_enable_backlight(true); + + ili9163c_set_orientation(CONFIG_LV_DISPLAY_ORIENTATION); +} + +void ili9163c_flush(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_map) +{ + uint8_t data[4]; + + /*Column addresses*/ + ili9163c_send_cmd(ILI9163C_CASET); + data[0] = (area->x1 >> 8) & 0xFF; + data[1] = area->x1 & 0xFF; + data[2] = (area->x2 >> 8) & 0xFF; + data[3] = area->x2 & 0xFF; + ili9163c_send_data(data, 4); + + /*Page addresses*/ + ili9163c_send_cmd(ILI9163C_RASET); + data[0] = (area->y1 >> 8) & 0xFF; + data[1] = area->y1 & 0xFF; + data[2] = (area->y2 >> 8) & 0xFF; + data[3] = area->y2 & 0xFF; + ili9163c_send_data(data, 4); + + /*Memory write*/ + ili9163c_send_cmd(ILI9163C_RAMWR); + + uint32_t size = lv_area_get_width(area) * lv_area_get_height(area); + + ili9163c_send_color((void *)color_map, size * 2); +} + +void ili9163c_enable_backlight(bool backlight) +{ +#if ILI9163C_ENABLE_BACKLIGHT_CONTROL + ESP_LOGD(TAG, "%s backlight.", backlight ? "Enabling" : "Disabling"); + uint32_t tmp = 0; + +#if (ILI9163C_BCKL_ACTIVE_LVL == 1) + tmp = backlight ? 1 : 0; +#else + tmp = backlight ? 0 : 1; +#endif + + gpio_set_level(ILI9163C_BCKL, tmp); +#endif +} + +void ili9163c_sleep_in() +{ + uint8_t data[] = {0x08}; + ili9163c_send_cmd(ILI9163C_SLPIN); + ili9163c_send_data(&data, 1); +} + +void ili9163c_sleep_out() +{ + uint8_t data[] = {0x08}; + ili9163c_send_cmd(ILI9163C_SLPOUT); + ili9163c_send_data(&data, 1); +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +static void ili9163c_send_cmd(uint8_t cmd) +{ + disp_wait_for_pending_transactions(); + gpio_set_level(ILI9163C_DC, 0); /*Command mode*/ + disp_spi_send_data(&cmd, 1); +} + +static void ili9163c_send_data(void *data, uint16_t length) +{ + disp_wait_for_pending_transactions(); + gpio_set_level(ILI9163C_DC, 1); /*Data mode*/ + disp_spi_send_data(data, length); +} + +static void ili9163c_send_color(void *data, uint16_t length) +{ + disp_wait_for_pending_transactions(); + gpio_set_level(ILI9163C_DC, 1); /*Data mode*/ + disp_spi_send_colors(data, length); +} + +static void ili9163c_set_orientation(uint8_t orientation) +{ + assert(orientation < 4); + + const char *orientation_str[] = { + "PORTRAIT", "PORTRAIT_INVERTED", "LANDSCAPE", "LANDSCAPE_INVERTED"}; + + ESP_LOGD(TAG, "Display orientation: %s", orientation_str[orientation]); + + uint8_t data[] = {0x48, 0x88, 0xA8, 0x68}; + + ili9163c_send_cmd(ILI9163C_MADCTL); + ili9163c_send_data((void *)&data[orientation], 1); +} diff --git a/lvgl_tft/ili9163c.h b/lvgl_tft/ili9163c.h new file mode 100644 index 0000000..f164ba8 --- /dev/null +++ b/lvgl_tft/ili9163c.h @@ -0,0 +1,65 @@ +/** + * @file lv_templ.h + * + */ + +#ifndef ILI9163C_H +#define ILI9163C_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************* + * INCLUDES + *********************/ +#include + +#ifdef LV_LVGL_H_INCLUDE_SIMPLE +#include "lvgl.h" +#else +#include "lvgl/lvgl.h" +#endif +#include "../lvgl_helpers.h" + +/********************* + * DEFINES + *********************/ +#define ILI9163C_DC CONFIG_LV_DISP_PIN_DC +#define ILI9163C_RST CONFIG_LV_DISP_PIN_RST +#define ILI9163C_BCKL CONFIG_LV_DISP_PIN_BCKL + +#define ILI9163C_ENABLE_BACKLIGHT_CONTROL CONFIG_LV_ENABLE_BACKLIGHT_CONTROL + +#if CONFIG_LV_BACKLIGHT_ACTIVE_LVL +#define ILI9163C_BCKL_ACTIVE_LVL 1 +#else +#define ILI9163C_BCKL_ACTIVE_LVL 0 +#endif + +#define ILI9163C_INVERT_COLORS CONFIG_LV_INVERT_COLORS + + /********************** + * TYPEDEFS + **********************/ + + /********************** + * GLOBAL PROTOTYPES + **********************/ + + void ili9163c_init(void); + void ili9163c_flush(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_map); + void ili9163c_enable_backlight(bool backlight); + void ili9163c_sleep_in(void); + void ili9163c_sleep_out(void); + + /********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*ILI9163C_H*/