From 07ad6bf43e7fc499f8d60089142ec061f88b4190 Mon Sep 17 00:00:00 2001 From: Keagan Ladds Date: Mon, 17 Jan 2022 20:17:19 +0100 Subject: [PATCH] Added support for ILI9225 Added support for ILI9225 display controller. Currently no support for hardware rotation is implemented and only the default portrait resolution 176x220 is supported. --- CMakeLists.txt | 2 + README.md | 1 + lvgl_helpers.c | 4 + lvgl_tft/Kconfig | 9 ++ lvgl_tft/disp_driver.c | 4 + lvgl_tft/disp_driver.h | 2 + lvgl_tft/ili9225.c | 248 +++++++++++++++++++++++++++++++++++++++++ lvgl_tft/ili9225.h | 54 +++++++++ 8 files changed, 324 insertions(+) create mode 100644 lvgl_tft/ili9225.c create mode 100644 lvgl_tft/ili9225.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 407802a..718a5a9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -44,6 +44,8 @@ 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") +elseif(CONFIG_LV_TFT_DISPLAY_CONTROLLER_ILI9225) + list(APPEND SOURCES "lvgl_tft/ili9225.c") else() message(WARNING "LVGL ESP32 drivers: Display controller not defined.") endif() diff --git a/README.md b/README.md index 522c0e1..f49d25d 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,7 @@ swap of RGB565 color on the LVGL configuration menuconfig (it's not handled auto | HX8357B/HX8357D | TFT | SPI | 16: RGB565 | Yes | | ST7789 | TFT | SPI | 16: RGB565 | Yes | | ST7735S | TFT | SPI | 16: RGB565 | Yes | +| ILI9225 | 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 | diff --git a/lvgl_helpers.c b/lvgl_helpers.c index 57ab7dd..c15162b 100644 --- a/lvgl_helpers.c +++ b/lvgl_helpers.c @@ -154,7 +154,11 @@ bool lvgl_spi_driver_init(int host, int dma_channel, int quadwp_pin, int quadhd_pin) { +#ifdef SPI_HOST_MAX assert((0 <= host) && (SPI_HOST_MAX > host)); +#else + assert(0 <= host); +#endif const char *spi_names[] = { "SPI1_HOST", "SPI2_HOST", "SPI3_HOST" }; diff --git a/lvgl_tft/Kconfig b/lvgl_tft/Kconfig index 4a74ad2..8dd3307 100644 --- a/lvgl_tft/Kconfig +++ b/lvgl_tft/Kconfig @@ -178,6 +178,11 @@ menu "LVGL TFT Display controller" bool help PCD8544 display controller (Nokia 3110/5110) + + config LV_TFT_DISPLAY_CONTROLLER_ILI9225 + bool + help + ILI9225 display controller. # Display controller communication protocol # # This symbols define the communication protocol used by the @@ -349,6 +354,10 @@ menu "LVGL TFT Display controller" select LV_TFT_DISPLAY_CONTROLLER_PCD8544 select LV_TFT_DISPLAY_PROTOCOL_SPI select LV_TFT_DISPLAY_MONOCHROME + config LV_TFT_DISPLAY_USER_CONTROLLER_ILI9225 + bool "ILI9225" + select LV_TFT_DISPLAY_CONTROLLER_ILI9225 + select LV_TFT_DISPLAY_PROTOCOL_SPI endchoice config CUSTOM_DISPLAY_BUFFER_SIZE diff --git a/lvgl_tft/disp_driver.c b/lvgl_tft/disp_driver.c index 153ca31..cf55374 100644 --- a/lvgl_tft/disp_driver.c +++ b/lvgl_tft/disp_driver.c @@ -45,6 +45,8 @@ void *disp_driver_init(void) ili9163c_init(); #elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_PCD8544 pcd8544_init(); +#elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_ILI9225 + ili9225_init(); #endif // We still use menuconfig for these settings @@ -111,6 +113,8 @@ void disp_driver_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * ili9163c_flush(drv, area, color_map); #elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_PCD8544 pcd8544_flush(drv, area, color_map); +#elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_ILI9225 + ili9225_flush(drv, area, color_map); #endif } diff --git a/lvgl_tft/disp_driver.h b/lvgl_tft/disp_driver.h index 2f5bcdf..9f4a817 100644 --- a/lvgl_tft/disp_driver.h +++ b/lvgl_tft/disp_driver.h @@ -54,6 +54,8 @@ extern "C" { #include "ili9163c.h" #elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_PCD8544 #include "pcd8544.h" +#elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_ILI9225 +#include "ili9225.h" #endif /********************* diff --git a/lvgl_tft/ili9225.c b/lvgl_tft/ili9225.c new file mode 100644 index 0000000..42a54ae --- /dev/null +++ b/lvgl_tft/ili9225.c @@ -0,0 +1,248 @@ +/** + * @file ili9225.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "ili9225.h" +#include "disp_spi.h" +#include "driver/gpio.h" +#include "esp_log.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +/********************* + * DEFINES + *********************/ +#define TAG "ILI9225" +#define ILI9225_DRIVER_OUTPUT_CTRL 0x01 // Driver Output Control +#define ILI9225_LCD_AC_DRIVING_CTRL 0x02 // LCD AC Driving Control +#define ILI9225_ENTRY_MODE 0x03 // Entry Mode +#define ILI9225_DISP_CTRL1 0x07 // Display Control 1 +#define ILI9225_BLANK_PERIOD_CTRL1 0x08 // Blank Period Control +#define ILI9225_FRAME_CYCLE_CTRL 0x0B // Frame Cycle Control +#define ILI9225_INTERFACE_CTRL 0x0C // Interface Control +#define ILI9225_OSC_CTRL 0x0F // Osc Control +#define ILI9225_POWER_CTRL1 0x10 // Power Control 1 +#define ILI9225_POWER_CTRL2 0x11 // Power Control 2 +#define ILI9225_POWER_CTRL3 0x12 // Power Control 3 +#define ILI9225_POWER_CTRL4 0x13 // Power Control 4 +#define ILI9225_POWER_CTRL5 0x14 // Power Control 5 +#define ILI9225_VCI_RECYCLING 0x15 // VCI Recycling +#define ILI9225_RAM_ADDR_SET1 0x20 // Horizontal GRAM Address Set +#define ILI9225_RAM_ADDR_SET2 0x21 // Vertical GRAM Address Set +#define ILI9225_GRAM_DATA_REG 0x22 // GRAM Data Register +#define ILI9225_GATE_SCAN_CTRL 0x30 // Gate Scan Control Register +#define ILI9225_VERTICAL_SCROLL_CTRL1 0x31 // Vertical Scroll Control 1 Register +#define ILI9225_VERTICAL_SCROLL_CTRL2 0x32 // Vertical Scroll Control 2 Register +#define ILI9225_VERTICAL_SCROLL_CTRL3 0x33 // Vertical Scroll Control 3 Register +#define ILI9225_PARTIAL_DRIVING_POS1 0x34 // Partial Driving Position 1 Register +#define ILI9225_PARTIAL_DRIVING_POS2 0x35 // Partial Driving Position 2 Register +#define ILI9225_HORIZONTAL_WINDOW_ADDR1 0x36 // Horizontal Address Start Position +#define ILI9225_HORIZONTAL_WINDOW_ADDR2 0x37 // Horizontal Address End Position +#define ILI9225_VERTICAL_WINDOW_ADDR1 0x38 // Vertical Address Start Position +#define ILI9225_VERTICAL_WINDOW_ADDR2 0x39 // Vertical Address End Position +#define ILI9225_GAMMA_CTRL1 0x50 // Gamma Control 1 +#define ILI9225_GAMMA_CTRL2 0x51 // Gamma Control 2 +#define ILI9225_GAMMA_CTRL3 0x52 // Gamma Control 3 +#define ILI9225_GAMMA_CTRL4 0x53 // Gamma Control 4 +#define ILI9225_GAMMA_CTRL5 0x54 // Gamma Control 5 +#define ILI9225_GAMMA_CTRL6 0x55 // Gamma Control 6 +#define ILI9225_GAMMA_CTRL7 0x56 // Gamma Control 7 +#define ILI9225_GAMMA_CTRL8 0x57 // Gamma Control 8 +#define ILI9225_GAMMA_CTRL9 0x58 // Gamma Control 9 +#define ILI9225_GAMMA_CTRL10 0x59 // Gamma Control 10 + +/********************** + * 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 ili9225_send_cmd(uint8_t cmd); +static void ili9225_send_cmds(void *data, uint16_t length); +static void ili9225_send_data(void *data, uint16_t length); +static void ili9225_send_color(void *data, uint16_t length); +static void ili9225_set_window(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2); + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +void ili9225_init(void) +{ + lcd_init_cmd_t ili_init_cmds[] = { + {ILI9225_POWER_CTRL1, {0x00, 0x00}, 2}, // Set SAP,DSTB,STB + {ILI9225_POWER_CTRL2, {0x00, 0x00}, 2}, // Set APON,PON,AON,VCI1EN,VC + {ILI9225_POWER_CTRL3, {0x00, 0x00}, 2}, // Set BT,DC1,DC2,DC3 + {ILI9225_POWER_CTRL4, {0x00, 0x00}, 2}, // Set GVDD + {ILI9225_POWER_CTRL5, {0x00, 0x00}, 2 | 0x80}, // Set VCOMH/VCOML voltage, 40ms delay + + {ILI9225_POWER_CTRL2, {0x00, 0x18}, 0x00}, // Set APON,PON,AON,VCI1EN,VC + {ILI9225_POWER_CTRL3, {0x61, 0x21}, 0x00}, // Set BT,DC1,DC2,DC3 + {ILI9225_POWER_CTRL4, {0x00, 0x6F}, 0x00}, // Set GVDD 007F 0088 + {ILI9225_POWER_CTRL5, {0x49, 0x5F}, 0x00}, // Set VCOMH/VCOML voltage + {ILI9225_POWER_CTRL1, {0x08, 0x00}, 2 | 0x80}, // Set SAP,DSTB,STB, 10ms delay + + {ILI9225_POWER_CTRL2, {0x10, 0x3B}, 2 | 0x80}, // Set APON,PON,AON,VCI1EN,VC, 50ms delay + + {ILI9225_DRIVER_OUTPUT_CTRL, {0x01, 0x1C}, 2}, + {ILI9225_LCD_AC_DRIVING_CTRL, {0x01, 0x00}, 2}, + {ILI9225_ENTRY_MODE, {0x10, 0x30}, 2}, + {ILI9225_DISP_CTRL1, {0x00, 0x00}, 2}, + {ILI9225_BLANK_PERIOD_CTRL1, {0x08, 0x08}, 2}, + {ILI9225_FRAME_CYCLE_CTRL, {0x11, 0x00}, 2}, + {ILI9225_INTERFACE_CTRL, {0x00, 0x00}, 2}, + {ILI9225_OSC_CTRL, {0x0D, 0x01}, 2}, + {ILI9225_VCI_RECYCLING, {0x00, 0x20}, 2}, + {ILI9225_RAM_ADDR_SET1, {0x00, 0x00}, 2}, + {ILI9225_RAM_ADDR_SET2, {0x00, 0x00}, 2}, + + {ILI9225_GATE_SCAN_CTRL, {0x00, 0x00}, 2}, + + {ILI9225_GAMMA_CTRL1, {0x00, 0x00}, 2}, + {ILI9225_GAMMA_CTRL2, {0x08, 0x08}, 2}, + {ILI9225_GAMMA_CTRL3, {0x08, 0x0A}, 2}, + {ILI9225_GAMMA_CTRL4, {0x00, 0x0A}, 2}, + {ILI9225_GAMMA_CTRL5, {0x0A, 0x08}, 2}, + {ILI9225_GAMMA_CTRL6, {0x08, 0x08}, 2}, + {ILI9225_GAMMA_CTRL7, {0x00, 0x00}, 2}, + {ILI9225_GAMMA_CTRL8, {0x0A, 0x00}, 2}, + {ILI9225_GAMMA_CTRL9, {0x07, 0x10}, 2}, + {ILI9225_GAMMA_CTRL10, {0x07, 0x10}, 2}, + + {ILI9225_DISP_CTRL1, {0x00, 0x12}, 2 | 0x80}, + {ILI9225_DISP_CTRL1, {0x00, 0x17}, 2}, + {0xFF, {0x00}, 0xFF}}; + + //Initialize non-SPI GPIOs + gpio_pad_select_gpio(ILI9225_DC); + gpio_set_direction(ILI9225_DC, GPIO_MODE_OUTPUT); + +#if ILI9225_USE_RST + gpio_pad_select_gpio(ILI9225_RST); + gpio_set_direction(ILI9225_RST, GPIO_MODE_OUTPUT); + + //Reset the display + gpio_set_level(ILI9225_RST, 1); + vTaskDelay(10 / portTICK_RATE_MS); + gpio_set_level(ILI9225_RST, 0); + vTaskDelay(10 / portTICK_RATE_MS); + gpio_set_level(ILI9225_RST, 1); + vTaskDelay(150 / portTICK_RATE_MS); +#endif + + ESP_LOGI(TAG, "Initialization."); + + //Send all the commands + uint16_t cmd = 0; + while (ili_init_cmds[cmd].databytes != 0xFF) + { + ili9225_send_cmd(ili_init_cmds[cmd].cmd); + ili9225_send_data(ili_init_cmds[cmd].data, ili_init_cmds[cmd].databytes & 0x1F); + if (ili_init_cmds[cmd].databytes & 0x80) + { + vTaskDelay(100 / portTICK_RATE_MS); + } + cmd++; + } +} + +void ili9225_flush(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_map) +{ + uint16_t x1 = area->x1; + uint16_t x2 = area->x2; + + uint16_t y1 = area->y1; + uint16_t y2 = area->y2; + + ili9225_set_window(x1, y1, x2, y2); + + uint8_t data[2]; + ili9225_send_cmd(ILI9225_RAM_ADDR_SET1); + data[0] = (x1 >> 8) & 0xFF; + data[1] = x1 & 0xFF; + ili9225_send_data(data, 2); + + ili9225_send_cmd(ILI9225_RAM_ADDR_SET2); + data[0] = (y1 >> 8) & 0xFF; + data[1] = y1 & 0xFF; + ili9225_send_data(data, 2); + + ili9225_send_cmd(ILI9225_GRAM_DATA_REG); + + uint32_t size = lv_area_get_width(area) * lv_area_get_height(area); + ili9225_send_color((void *)color_map, size * 2); +} + +/********************** + * STATIC FUNCTIONS + **********************/ +static void ili9225_send_cmd(uint8_t cmd) +{ + disp_wait_for_pending_transactions(); + uint8_t data[2]; + data[0] = 0x00; + data[1] = cmd; + + gpio_set_level(ILI9225_DC, 0); /*Command mode*/ + disp_spi_send_data(data, 2); +} + +static void ili9225_send_data(void *data, uint16_t length) +{ + disp_wait_for_pending_transactions(); + gpio_set_level(ILI9225_DC, 1); /*Data mode*/ + disp_spi_send_data(data, length); +} + +static void ili9225_send_color(void *data, uint16_t length) +{ + disp_wait_for_pending_transactions(); + gpio_set_level(ILI9225_DC, 1); /*Data mode*/ + disp_spi_send_colors(data, length); +} + +static void ili9225_set_window(uint16_t h1, uint16_t v1, uint16_t h2, uint16_t v2) +{ + uint8_t data[2]; + + ili9225_send_cmd(ILI9225_HORIZONTAL_WINDOW_ADDR1); // HEA + data[0] = (h2 >> 8) & 0xFF; + data[1] = h2 & 0xFF; + ili9225_send_data(data, 2); + + ili9225_send_cmd(ILI9225_HORIZONTAL_WINDOW_ADDR2); // HSA + data[0] = (h1 >> 8) & 0xFF; + data[1] = h1 & 0xFF; + ili9225_send_data(data, 2); + + ili9225_send_cmd(ILI9225_VERTICAL_WINDOW_ADDR1); // VEA + data[0] = (v2 >> 8) & 0xFF; + data[1] = v2 & 0xFF; + ili9225_send_data(data, 2); + + ili9225_send_cmd(ILI9225_VERTICAL_WINDOW_ADDR2); // VSA + data[0] = (v1 >> 8) & 0xFF; + data[1] = v1 & 0xFF; + ili9225_send_data(data, 2); +} diff --git a/lvgl_tft/ili9225.h b/lvgl_tft/ili9225.h new file mode 100644 index 0000000..2b11000 --- /dev/null +++ b/lvgl_tft/ili9225.h @@ -0,0 +1,54 @@ +/** + * @file lv_templ.h + * + */ + +#ifndef ILI9225_H +#define ILI9225_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include + +#ifdef LV_LVGL_H_INCLUDE_SIMPLE +#include "lvgl.h" +#else +#include "lvgl/lvgl.h" +#endif + +#include "sdkconfig.h" + +/********************* + * DEFINES + *********************/ +#define ILI9225_DC CONFIG_LV_DISP_PIN_DC +#define ILI9225_USE_RST CONFIG_LV_DISP_USE_RST +#define ILI9225_RST CONFIG_LV_DISP_PIN_RST +#define ILI9225_INVERT_COLORS CONFIG_LV_INVERT_COLORS + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +void ili9225_init(void); +void ili9225_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * color_map); + +/********************** + * MACROS + **********************/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*ILI9225_H*/