From b5b0a042da4f729c07e3a5ffff462b94940ab039 Mon Sep 17 00:00:00 2001 From: Yilin Sun Date: Fri, 29 Mar 2024 00:56:17 +0800 Subject: [PATCH] Added GC9B71 driver. Signed-off-by: Yilin Sun --- CMakeLists.txt | 2 + include/epd-spi/driver/lcd_gc9b71.h | 55 ++++++++ include/epd-spi/panel/lcd_h189s001.h | 8 ++ include/epd-spi/panel/lcd_hp32030d.h | 4 - src/driver/lcd_gc9b71.c | 197 +++++++++++++++++++++++++++ src/panel/lcd_h189s001.c | 65 +++++++++ 6 files changed, 327 insertions(+), 4 deletions(-) create mode 100644 include/epd-spi/driver/lcd_gc9b71.h create mode 100644 include/epd-spi/panel/lcd_h189s001.h create mode 100644 src/driver/lcd_gc9b71.c create mode 100644 src/panel/lcd_h189s001.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 20bec76..cc8bd58 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,10 +5,12 @@ project(epd-spi) set(EPD_SOURCES "src/epd_common.c" "src/driver/oled_ssd1327.c" + "src/driver/lcd_gc9b71.c" "src/driver/lcd_st7789.c" "src/panel/epd_wfh0420cz35.c" "src/panel/epd_gdew042t2.c" "src/panel/lcd_h144c121d.c" + "src/panel/lcd_h189s001.c" "src/panel/lcd_hp32030d.c" "src/panel/lcd_jlx256128g_920.c" "src/panel/lcd_tk0096f611.c" diff --git a/include/epd-spi/driver/lcd_gc9b71.h b/include/epd-spi/driver/lcd_gc9b71.h new file mode 100644 index 0000000..826468b --- /dev/null +++ b/include/epd-spi/driver/lcd_gc9b71.h @@ -0,0 +1,55 @@ +#ifndef LCD_GC9B71_H +#define LCD_GC9B71_H + +#include "epd-spi/epd_common.h" + +typedef enum { + LCD_GC9B71_DIR_0 = 0x48U, + LCD_GC9B71_DIR_90 = 0x28U, + LCD_GC9B71_DIR_180 = 0x88U, + LCD_GC9B71_DIR_270 = 0xE8U, +} lcd_gc9b71_direction_t; + +typedef enum { + LCD_GC9B71_GS256 = 0, + LCD_GC9B71_RGB111 = 1, + LCD_GC9B71_RGB444 = 3, + LCD_GC9B71_RGB565 = 5, + LCD_GC9B71_RGB666 = 6, + LCD_GC9B71_RGB888 = 7, +} lcd_gc9b71_pixel_format_t; + +typedef struct { + uint8_t *init_struct; + uint32_t init_struct_length; + + uint16_t ram_size_x; + uint16_t ram_size_y; + + uint16_t ram_offset_x; + uint16_t ram_offset_y; + + uint16_t size_x; + uint16_t size_y; + + bool inversion; + bool bgr_filter; +} gc9b71_panel_config_t; + +typedef struct { + void *user_data; + epd_cb_t cb; + + const gc9b71_panel_config_t *panel_config; + lcd_gc9b71_direction_t direction; + lcd_gc9b71_pixel_format_t pixel_format; +} lcd_gc9b71_t; + +epd_ret_t lcd_gc9b71_init(lcd_gc9b71_t *lcd, const gc9b71_panel_config_t *config); +epd_ret_t lcd_gc9b71_enable_display(lcd_gc9b71_t *lcd, bool on); +epd_ret_t lcd_gc9b71_set_pixel_format(lcd_gc9b71_t *lcd, lcd_gc9b71_pixel_format_t format); +epd_ret_t lcd_gc9b71_set_direction(lcd_gc9b71_t *lcd, lcd_gc9b71_direction_t direction); +epd_ret_t lcd_gc9b71_set_inversion(lcd_gc9b71_t *lcd, bool invert); +epd_ret_t lcd_gc9b71_load(lcd_gc9b71_t *lcd, epd_coord_t *coord, const uint8_t *data); + +#endif // LCD_GC9B71_H diff --git a/include/epd-spi/panel/lcd_h189s001.h b/include/epd-spi/panel/lcd_h189s001.h new file mode 100644 index 0000000..5932f8f --- /dev/null +++ b/include/epd-spi/panel/lcd_h189s001.h @@ -0,0 +1,8 @@ +#ifndef LCD_H189S001_H +#define LCD_H189S001_H + +#include "epd-spi/driver/lcd_gc9b71.h" + +extern const gc9b71_panel_config_t lcd_h189s001_panel_config; + +#endif //LCD_H189S001_H diff --git a/include/epd-spi/panel/lcd_hp32030d.h b/include/epd-spi/panel/lcd_hp32030d.h index 4dbc268..37f48f4 100644 --- a/include/epd-spi/panel/lcd_hp32030d.h +++ b/include/epd-spi/panel/lcd_hp32030d.h @@ -1,7 +1,3 @@ -// -// Created by imi415 on 23/10/21. -// - #ifndef LCD_HP32030D_H #define LCD_HP32030D_H diff --git a/src/driver/lcd_gc9b71.c b/src/driver/lcd_gc9b71.c new file mode 100644 index 0000000..9e74637 --- /dev/null +++ b/src/driver/lcd_gc9b71.c @@ -0,0 +1,197 @@ +#include "driver/lcd_gc9b71.h" + +#include "epd_private.h" + +/* TODO: Summarize MIPI DCS common commands into a separate file. */ +#define GC9B71_CMD_SWRESET (0x01U) +#define GC9B71_CMD_SLPIN (0x10U) +#define GC9B71_CMD_SLPOUT (0x11U) +#define GC9B71_CMD_INVOFF (0x20U) +#define GC9B71_CMD_INVON (0x21U) +#define GC9B71_CMD_DISPOFF (0x28U) +#define GC9B71_CMD_DISPON (0x29U) +#define GC9B71_CMD_CASET (0x2AU) +#define GC9B71_CMD_RASET (0x2BU) +#define GC9B71_CMD_RAMWR (0x2CU) +#define GC9B71_CMD_MADCTL (0x36U) +#define GC9B71_CMD_COLMOD (0x3AU) + +static epd_ret_t lcd_gc9b71_reset(lcd_gc9b71_t *lcd); +static epd_ret_t lcd_gc9b71_sleep(lcd_gc9b71_t *lcd, bool sleep_mode); +static epd_ret_t lcd_gc9b71_panel_config(lcd_gc9b71_t *lcd, const gc9b71_panel_config_t *config); +static epd_ret_t lcd_gc9b71_set_window(lcd_gc9b71_t *lcd, epd_coord_t *coord); + +epd_ret_t lcd_gc9b71_init(lcd_gc9b71_t *lcd, const gc9b71_panel_config_t *config) { + EPD_ERROR_CHECK(lcd_gc9b71_reset(lcd)); + EPD_ERROR_CHECK(lcd->cb.delay_cb(lcd->user_data, 5)); + EPD_ERROR_CHECK(lcd_gc9b71_panel_config(lcd, config)); + EPD_ERROR_CHECK(lcd_gc9b71_set_pixel_format(lcd, LCD_GC9B71_RGB565)); + EPD_ERROR_CHECK(lcd_gc9b71_set_direction(lcd, LCD_GC9B71_DIR_0)); + EPD_ERROR_CHECK(lcd_gc9b71_set_inversion(lcd, false)); + EPD_ERROR_CHECK(lcd_gc9b71_sleep(lcd, false)); + EPD_ERROR_CHECK(lcd->cb.delay_cb(lcd->user_data, 120)); + + if (lcd->cb.backlight_cb) { + EPD_ERROR_CHECK(lcd->cb.backlight_cb(lcd, 1)); + } + + return EPD_OK; +} + +epd_ret_t lcd_gc9b71_load(lcd_gc9b71_t *lcd, epd_coord_t *coord, const uint8_t *data) { + uint32_t pixel_count = (coord->y_end - coord->y_start + 1) * (coord->x_end - coord->x_start + 1); + + uint32_t data_len = 0; + + switch (lcd->pixel_format) { + case LCD_GC9B71_RGB444: + data_len = pixel_count * 3 / 2; + break; + case LCD_GC9B71_RGB565: + data_len = pixel_count * 2; + break; + case LCD_GC9B71_RGB666: + case LCD_GC9B71_RGB888: + data_len = pixel_count * 3; + break; + default: + data_len = pixel_count; + break; + } + + // Set cursor + EPD_ERROR_CHECK(lcd_gc9b71_set_window(lcd, coord)); + + // Write pixel data + EPD_ERROR_CHECK(lcd->cb.write_data_cb(lcd->user_data, data, data_len)); + + return EPD_OK; +} + +epd_ret_t lcd_gc9b71_set_pixel_format(lcd_gc9b71_t *lcd, lcd_gc9b71_pixel_format_t format) { + lcd->pixel_format = format; + + uint8_t command[2] = {GC9B71_CMD_COLMOD, format}; + EPD_ERROR_CHECK(lcd->cb.write_command_cb(lcd->user_data, command, 0x02)); + + return EPD_OK; +} + +epd_ret_t lcd_gc9b71_set_direction(lcd_gc9b71_t *lcd, lcd_gc9b71_direction_t direction) { + lcd->direction = direction; + + uint8_t command[2] = {GC9B71_CMD_MADCTL, direction}; + + if (!lcd->panel_config->bgr_filter) { + command[1] &= ~0x08U; + } + + EPD_ERROR_CHECK(lcd->cb.write_command_cb(lcd->user_data, command, 0x02)); + + return EPD_OK; +} + +epd_ret_t lcd_gc9b71_set_inversion(lcd_gc9b71_t *lcd, bool invert) { + uint8_t command[1]; + + if (lcd->panel_config->inversion) { + command[0] = invert ? GC9B71_CMD_INVOFF : GC9B71_CMD_INVON; + } else { + command[0] = invert ? GC9B71_CMD_INVON : GC9B71_CMD_INVOFF; + } + + EPD_ERROR_CHECK(lcd->cb.write_command_cb(lcd->user_data, command, 0x01)); + + return EPD_OK; +} + +epd_ret_t lcd_gc9b71_enable_display(lcd_gc9b71_t *lcd, bool on) { + uint8_t command[1]; + + if (on) { + command[0] = GC9B71_CMD_DISPON; + } else { + command[0] = GC9B71_CMD_DISPOFF; + } + + EPD_ERROR_CHECK(lcd->cb.write_command_cb(lcd->user_data, command, 0x01)); + + return EPD_OK; +} + +static epd_ret_t lcd_gc9b71_reset(lcd_gc9b71_t *lcd) { + uint8_t cmd_buf[1] = {GC9B71_CMD_SWRESET}; + + if (lcd->cb.reset_cb) { + return lcd->cb.reset_cb(lcd->user_data); + } + + return lcd->cb.write_command_cb(lcd->user_data, cmd_buf, 1U); +} + +static epd_ret_t lcd_gc9b71_sleep(lcd_gc9b71_t *lcd, bool sleep_mode) { + uint8_t cmd_buf[1] = {GC9B71_CMD_SLPOUT}; + + if (sleep_mode) { + cmd_buf[0] = GC9B71_CMD_SLPIN; + } + + return lcd->cb.write_command_cb(lcd->user_data, cmd_buf, 1U); +} + +static epd_ret_t lcd_gc9b71_panel_config(lcd_gc9b71_t *lcd, const gc9b71_panel_config_t *config) { + EPD_ERROR_CHECK( + epd_common_execute_sequence(&lcd->cb, lcd->user_data, config->init_struct, config->init_struct_length)); + + lcd->panel_config = config; + return EPD_OK; +} + +static epd_ret_t lcd_gc9b71_set_window(lcd_gc9b71_t *lcd, epd_coord_t *coord) { + uint16_t real_x_start, real_x_end, real_y_start, real_y_end; + uint16_t x_offset, y_offset; + + switch (lcd->direction) { + case LCD_GC9B71_DIR_0: + x_offset = lcd->panel_config->ram_offset_x; + y_offset = lcd->panel_config->ram_offset_y; + break; + case LCD_GC9B71_DIR_90: + x_offset = lcd->panel_config->ram_offset_y; + y_offset = lcd->panel_config->ram_offset_x; + break; + case LCD_GC9B71_DIR_180: + x_offset = lcd->panel_config->ram_size_x - (lcd->panel_config->ram_offset_x + lcd->panel_config->size_x); + y_offset = lcd->panel_config->ram_size_y - (lcd->panel_config->ram_offset_y + lcd->panel_config->size_y); + break; + case LCD_GC9B71_DIR_270: + x_offset = lcd->panel_config->ram_size_y - (lcd->panel_config->ram_offset_y + lcd->panel_config->size_y); + y_offset = lcd->panel_config->ram_size_x - (lcd->panel_config->ram_offset_x + lcd->panel_config->size_x); + break; + default: + x_offset = 0; + y_offset = 0; + } + + real_x_start = coord->x_start + x_offset; + real_x_end = coord->x_end + x_offset; + real_y_start = coord->y_start + y_offset; + real_y_end = coord->y_end + y_offset; + + uint8_t tx_buf[5] = { + GC9B71_CMD_CASET, ((uint8_t)(real_x_start >> 0x08U) & 0xFFU), + (real_x_start & 0xFFU), ((uint8_t)(real_x_end >> 0x08U) & 0xFFU), + (real_x_end & 0xFFU), + }; + + EPD_ERROR_CHECK(lcd->cb.write_command_cb(lcd->user_data, tx_buf, 0x05)); + + tx_buf[0] = GC9B71_CMD_RASET; + tx_buf[1] = ((uint8_t)(real_y_start >> 0x08U) & 0xFFU); + tx_buf[2] = (real_y_start & 0xFFU); + tx_buf[3] = ((uint8_t)(real_y_end >> 0x08U) & 0xFFU); + tx_buf[4] = (real_y_end & 0xFFU); + + EPD_ERROR_CHECK(lcd->cb.write_command_cb(lcd->user_data, tx_buf, 0x05)); + return EPD_OK; +} \ No newline at end of file diff --git a/src/panel/lcd_h189s001.c b/src/panel/lcd_h189s001.c new file mode 100644 index 0000000..147c977 --- /dev/null +++ b/src/panel/lcd_h189s001.c @@ -0,0 +1,65 @@ +#include "panel/lcd_h189s001.h" + +static uint8_t panel_init_struct[] = { + 0x00, 0xFE, // ?? + 0x00, 0xEF, // ?? + 0x01, 0x80, 0x11, // ?? + 0x01, 0x81, 0x70, // ?? + 0x01, 0x82, 0x09, // ?? + 0x01, 0x83, 0x03, // ?? + 0x01, 0x84, 0x62, // ?? + 0x01, 0x89, 0x18, // ?? + 0x01, 0x8A, 0x40, // ?? + 0x01, 0x8B, 0x0A, // ?? + 0x01, 0x3A, 0x05, // ?? + 0x01, 0x36, 0x40, // ?? + 0x01, 0xEC, 0x07, // ?? + 0x06, 0x74, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, // ?? + 0x01, 0x98, 0x3E, // ?? + 0x01, 0x99, 0x3E, // ?? + 0x02, 0xA1, 0x01, 0x04, // ?? + 0x02, 0xA2, 0x01, 0x04, // ?? + 0x01, 0xCB, 0x02, // ?? + 0x02, 0x7C, 0xB6, 0x24, // ?? + 0x01, 0xAC, 0x74, // ?? + 0x01, 0xF6, 0x80, // ?? + 0x02, 0xB5, 0x09, 0x09, // ?? + 0x02, 0xEB, 0x01, 0x81, // ?? + 0x04, 0x60, 0x38, 0x06, 0x13, 0x56, // ?? + 0x04, 0x63, 0x38, 0x08, 0x13, 0x56, // ?? + 0x04, 0x61, 0x3B, 0x1B, 0x58, 0x38, // ?? + 0x04, 0x62, 0x3B, 0x1B, 0x58, 0x38, // ?? + 0x06, 0x64, 0x38, 0x0A, 0x73, 0x16, 0x13, 0x56, // ?? + 0x06, 0x66, 0x38, 0x0B, 0x73, 0x17, 0x13, 0x56, // ?? + 0x07, 0x68, 0x00, 0x0B, 0x22, 0x0B, 0x22, 0x1C, 0x1C, // ?? + 0x07, 0x69, 0x00, 0x0B, 0x26, 0x0B, 0x26, 0x1C, 0x1C, // ?? + 0x02, 0x6A, 0x15, 0x00, // ?? + 0x20, 0x6E, 0x08, 0x02, 0x1a, 0x00, 0x12, 0x12, 0x11, 0x11, 0x14, 0x14, 0x13, 0x13, 0x04, 0x19, 0x1E, + 0x1D, 0x1D, 0x1E, 0x19, 0x04, 0x0B, 0x0B, 0x0C, 0x0C, 0x09, 0x09, 0x0A, 0x0A, 0x00, 0x1A, 0x01, 0x07, // ?? + 0x07, 0x6C, 0xCC, 0x0C, 0xCC, 0x84, 0xCC, 0x04, 0x50, // ?? + 0x01, 0x7D, 0x72, // ?? + 0x0A, 0x70, 0x02, 0x03, 0x09, 0x07, 0x09, 0x03, 0x09, 0x07, 0x09, 0x03, // ?? + 0x04, 0x90, 0x06, 0x06, 0x05, 0x06, // ?? + 0x03, 0x93, 0x45, 0xFF, 0x00, // ?? + 0x05, 0xC3, 0x15, 0xC4, 0x36, 0xC9, 0x3D, // ?? + 0x06, 0xF0, 0x47, 0x07, 0x0A, 0x0A, 0x00, 0x29, // ?? + 0x06, 0xF2, 0x47, 0x07, 0x0A, 0x0A, 0x00, 0x29, // ?? + 0x06, 0xF1, 0x42, 0x91, 0x10, 0x2D, 0x2F, 0x6F, // ?? + 0x06, 0xF3, 0x42, 0x91, 0x10, 0x2D, 0x2F, 0x6F, // ?? + 0x01, 0xF9, 0x30, // ?? + 0x01, 0xBE, 0x11, // ?? + 0x02, 0xFB, 0x00, 0x00, // ?? +}; + +const gc9b71_panel_config_t lcd_h189s001_panel_config = { + .init_struct = panel_init_struct, + .init_struct_length = sizeof(panel_init_struct), + .ram_size_x = 320, + .ram_size_y = 390, + .ram_offset_x = 0, + .ram_offset_y = 0, + .size_x = 320, + .size_y = 386, + .bgr_filter = false, + .inversion = false, +}; \ No newline at end of file