Skip to content

Commit

Permalink
Merge pull request #232 from Lzw655/feature/update_lcd_drivers
Browse files Browse the repository at this point in the history
Update LCD drivers
  • Loading branch information
espzav authored Oct 27, 2023
2 parents 414f696 + db65d71 commit 21277f5
Show file tree
Hide file tree
Showing 41 changed files with 1,739 additions and 346 deletions.
16 changes: 7 additions & 9 deletions components/lcd/esp_lcd_gc9503/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
idf_component_register(
SRCS
"esp_lcd_gc9503.c"
INCLUDE_DIRS
"include"
PRIV_REQUIRES
"driver"
REQUIRES
"esp_lcd")
idf_component_register(SRCS "esp_lcd_gc9503.c"
INCLUDE_DIRS "include"
PRIV_REQUIRES "driver"
REQUIRES "esp_lcd")

include(package_manager)
cu_pkg_define_version(${CMAKE_CURRENT_LIST_DIR})
21 changes: 13 additions & 8 deletions components/lcd/esp_lcd_gc9503/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,14 @@ It's recommended to use the [esp_lcd_panel_io_additions](https://components.espr
```c
ESP_LOGI(TAG, "Install 3-wire SPI panel IO");
spi_line_config_t line_config = {
.cs_io_type = IO_TYPE_EXPANDER, // Set to `IO_TYPE_GPIO` if using GPIO, same to below
.cs_expander_pin = EXAMPLE_LCD_IO_SPI_CS,
.cs_io_type = IO_TYPE_GPIO, // Set to `IO_TYPE_EXPANDER` if using IO expander
.cs_gpio_num = EXAMPLE_LCD_IO_SPI_CS,
.scl_io_type = IO_TYPE_GPIO,
.scl_expander_pin = EXAMPLE_LCD_IO_SPI_SCK,
.scl_gpio_num = EXAMPLE_LCD_IO_SPI_SCK,
.sda_io_type = IO_TYPE_GPIO,
.sda_expander_pin = EXAMPLE_LCD_IO_SPI_SDO,
.io_expander = expander_handle, // Set to NULL if not using IO expander
.sda_gpio_num = EXAMPLE_LCD_IO_SPI_SDO,
.io_expander = NULL, // Set to device handle if using IO expander

};
esp_lcd_panel_io_3wire_spi_config_t io_config = GC9503_PANEL_IO_3WIRE_SPI_CONFIG(line_config, 0);
esp_lcd_panel_io_handle_t io_handle = NULL;
Expand All @@ -45,7 +46,7 @@ It's recommended to use the [esp_lcd_panel_io_additions](https://components.espr
* The array should be declared as static const and positioned outside the function.
*/
// static const gc9503_lcd_init_cmd_t lcd_init_cmds[] = {
// // cmd data data_size delay_ms
// // {cmd, { data }, data_size, delay_ms}
// {0xc1, (uint8_t []){0x3f}, 1, 0},
// {0xc2, (uint8_t []){0x0e}, 1, 0},
// {0xc6, (uint8_t []){0xf8}, 1, 0},
Expand Down Expand Up @@ -100,12 +101,16 @@ It's recommended to use the [esp_lcd_panel_io_additions](https://components.espr
};
const esp_lcd_panel_dev_config_t panel_config = {
.reset_gpio_num = EXAMPLE_LCD_IO_RST, // Set to -1 if not use
.rgb_endian = LCD_RGB_ENDIAN_RGB, // Implemented by LCD command `B1h`
.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB, // Implemented by LCD command `B1h`
.bits_per_pixel = EXAMPLE_LCD_BIT_PER_PIXEL, // Implemented by LCD command `3Ah` (16/18/24)
.vendor_config = &vendor_config,
};
esp_lcd_panel_handle_t panel_handle = NULL;
ESP_ERROR_CHECK(esp_lcd_new_panel_gc9503(io_handle, &panel_config, &panel_handle));
// Since the LCD initialization is complete, do not call `esp_lcd_panel_reset()` to reset the LCD.
ESP_ERROR_CHECK(esp_lcd_panel_reset(panel_handle));
ESP_ERROR_CHECK(esp_lcd_panel_init(panel_handle));
ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel_handle, true)); /**
* Don't call this function if `auto_del_panel_io` is set to 0
* and `disp_gpio_num` is set to -1
*/
```
117 changes: 89 additions & 28 deletions components/lcd/esp_lcd_gc9503/esp_lcd_gc9503.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,18 @@
typedef struct {
esp_lcd_panel_io_handle_t io;
int reset_gpio_num;
bool reset_level;
uint8_t madctl_val; // Save current value of GC9503_CMD_MADCTL register
uint8_t colmod_cal; // Save surrent value of LCD_CMD_COLMOD register
uint8_t colmod_val; // Save current value of LCD_CMD_COLMOD register
const gc9503_lcd_init_cmd_t *init_cmds;
uint16_t init_cmds_size;
struct {
unsigned int mirror_by_cmd: 1;
unsigned int auto_del_panel_io: 1;
unsigned int display_on_off_use_cmd: 1;
unsigned int reset_level: 1;
} flags;
// To save the original functions of RGB panel
esp_err_t (*init)(esp_lcd_panel_t *panel);
esp_err_t (*del)(esp_lcd_panel_t *panel);
esp_err_t (*reset)(esp_lcd_panel_t *panel);
esp_err_t (*mirror)(esp_lcd_panel_t *panel, bool x_axis, bool y_axis);
Expand All @@ -46,6 +48,7 @@ static const char *TAG = "gc9503";

static esp_err_t panel_gc9503_send_init_cmds(gc9503_panel_t *gc9503);

static esp_err_t panel_gc9503_init(esp_lcd_panel_t *panel);
static esp_err_t panel_gc9503_del(esp_lcd_panel_t *panel);
static esp_err_t panel_gc9503_reset(esp_lcd_panel_t *panel);
static esp_err_t panel_gc9503_mirror(esp_lcd_panel_t *panel, bool mirror_x, bool mirror_y);
Expand All @@ -61,30 +64,39 @@ esp_err_t esp_lcd_new_panel_gc9503(const esp_lcd_panel_io_handle_t io, const esp
ESP_ERR_INVALID_ARG, TAG, "`mirror_by_cmd` and `auto_del_panel_io` cannot work together");

esp_err_t ret = ESP_OK;
gpio_config_t io_conf = { 0 };

gc9503_panel_t *gc9503 = (gc9503_panel_t *)calloc(1, sizeof(gc9503_panel_t));
ESP_RETURN_ON_FALSE(gc9503, ESP_ERR_NO_MEM, TAG, "no mem for gc9503 panel");

if (panel_dev_config->reset_gpio_num >= 0) {
gpio_config_t io_conf = {
.mode = GPIO_MODE_OUTPUT,
.pin_bit_mask = 1ULL << panel_dev_config->reset_gpio_num,
};
io_conf.mode = GPIO_MODE_OUTPUT;
io_conf.pin_bit_mask = 1ULL << panel_dev_config->reset_gpio_num;
ESP_GOTO_ON_ERROR(gpio_config(&io_conf), err, TAG, "configure GPIO for RST line failed");
}

gc9503->madctl_val = GC9503_CMD_MADCTL_DEFAULT;
gc9503->madctl_val |= (panel_dev_config->rgb_endian == LCD_RGB_ENDIAN_BGR) ? GC9503_CMD_BGR_BIT : 0;
switch (panel_dev_config->rgb_ele_order) {
case LCD_RGB_ELEMENT_ORDER_RGB:
gc9503->madctl_val = 0;
break;
case LCD_RGB_ELEMENT_ORDER_BGR:
gc9503->madctl_val |= GC9503_CMD_BGR_BIT;
break;
default:
ESP_GOTO_ON_FALSE(false, ESP_ERR_NOT_SUPPORTED, err, TAG, "unsupported color element order");
break;
}

gc9503->colmod_cal = 0;
gc9503->colmod_val = 0;
switch (panel_dev_config->bits_per_pixel) {
case 16: // RGB565
gc9503->colmod_cal = 0x50;
gc9503->colmod_val = 0x50;
break;
case 18: // RGB666
gc9503->colmod_cal = 0x60;
gc9503->colmod_val = 0x60;
break;
case 24: // RGB888
gc9503->colmod_cal = 0x70;
gc9503->colmod_val = 0x70;
break;
default:
ESP_GOTO_ON_FALSE(false, ESP_ERR_NOT_SUPPORTED, err, TAG, "unsupported pixel width");
Expand All @@ -94,15 +106,29 @@ esp_err_t esp_lcd_new_panel_gc9503(const esp_lcd_panel_io_handle_t io, const esp
gc9503->io = io;
gc9503->init_cmds = vendor_config->init_cmds;
gc9503->init_cmds_size = vendor_config->init_cmds_size;
gc9503->reset_gpio_num = panel_dev_config->reset_gpio_num;
gc9503->flags.reset_level = panel_dev_config->flags.reset_active_high;
gc9503->flags.auto_del_panel_io = vendor_config->flags.auto_del_panel_io;
gc9503->flags.mirror_by_cmd = vendor_config->flags.mirror_by_cmd;
gc9503->flags.display_on_off_use_cmd = (vendor_config->rgb_config->disp_gpio_num >= 0) ? 0 : 1;

/**
* In order to enable the 3-wire SPI interface pins (such as SDA and SCK) to share other pins of the RGB interface
* (such as HSYNC) and save GPIOs, We need to send LCD initialization commands via the 3-wire SPI interface before
* `esp_lcd_new_rgb_panel()` is called.
*/
ESP_GOTO_ON_ERROR(panel_gc9503_send_init_cmds(gc9503), err, TAG, "send init commands failed");
// After sending the initialization commands, the 3-wire SPI interface can be deleted
if (vendor_config->flags.auto_del_panel_io) {
if (gc9503->flags.auto_del_panel_io) {
if (gc9503->reset_gpio_num >= 0) { // Perform hardware reset
gpio_set_level(gc9503->reset_gpio_num, gc9503->flags.reset_level);
vTaskDelay(pdMS_TO_TICKS(10));
gpio_set_level(gc9503->reset_gpio_num, !gc9503->flags.reset_level);
} else { // Perform software reset
ESP_GOTO_ON_ERROR(esp_lcd_panel_io_tx_param(io, LCD_CMD_SWRESET, NULL, 0), err, TAG, "send command failed");
}
vTaskDelay(pdMS_TO_TICKS(120));

/**
* In order to enable the 3-wire SPI interface pins (such as SDA and SCK) to share other pins of the RGB interface
* (such as HSYNC) and save GPIOs, we need to send LCD initialization commands via the 3-wire SPI interface before
* `esp_lcd_new_rgb_panel()` is called.
*/
ESP_GOTO_ON_ERROR(panel_gc9503_send_init_cmds(gc9503), err, TAG, "send init commands failed");
// After sending the initialization commands, the 3-wire SPI interface can be deleted
ESP_GOTO_ON_ERROR(esp_lcd_panel_io_del(io), err, TAG, "delete panel IO failed");
gc9503->io = NULL;
ESP_LOGD(TAG, "delete panel IO");
Expand All @@ -112,23 +138,23 @@ esp_err_t esp_lcd_new_panel_gc9503(const esp_lcd_panel_io_handle_t io, const esp
ESP_GOTO_ON_ERROR(esp_lcd_new_rgb_panel(vendor_config->rgb_config, ret_panel), err, TAG, "create RGB panel failed");
ESP_LOGD(TAG, "new RGB panel @%p", ret_panel);

gc9503->reset_gpio_num = panel_dev_config->reset_gpio_num;
gc9503->reset_level = panel_dev_config->flags.reset_active_high;
gc9503->flags.mirror_by_cmd = vendor_config->flags.mirror_by_cmd;
gc9503->flags.display_on_off_use_cmd = (vendor_config->rgb_config->disp_gpio_num >= 0) ? 0 : 1;
// Save the original functions of RGB panel
gc9503->init = (*ret_panel)->init;
gc9503->del = (*ret_panel)->del;
gc9503->reset = (*ret_panel)->reset;
gc9503->mirror = (*ret_panel)->mirror;
gc9503->disp_on_off = (*ret_panel)->disp_on_off;
// Overwrite the functions of RGB panel
(*ret_panel)->init = panel_gc9503_init;
(*ret_panel)->del = panel_gc9503_del;
(*ret_panel)->reset = panel_gc9503_reset;
(*ret_panel)->mirror = panel_gc9503_mirror;
(*ret_panel)->disp_on_off = panel_gc9503_disp_on_off;
(*ret_panel)->user_data = gc9503;
ESP_LOGD(TAG, "new gc9503 panel @%p", gc9503);

ESP_LOGI(TAG, "LCD panel create success, version: %d.%d.%d", ESP_LCD_GC9503_VER_MAJOR, ESP_LCD_GC9503_VER_MINOR,
ESP_LCD_GC9503_VER_PATCH);
return ESP_OK;

err:
Expand All @@ -143,6 +169,7 @@ esp_err_t esp_lcd_new_panel_gc9503(const esp_lcd_panel_io_handle_t io, const esp

// *INDENT-OFF*
static const gc9503_lcd_init_cmd_t vendor_specific_init_default[] = {
// {cmd, { data }, data_size, delay_ms}
{0xf0, (uint8_t []){0x55, 0xaa, 0x52, 0x08, 0x00}, 5, 0},
{0xf6, (uint8_t []){0x5a, 0x87}, 2, 0},
{0xc1, (uint8_t []){0x3f}, 1, 0},
Expand Down Expand Up @@ -216,22 +243,43 @@ static esp_err_t panel_gc9503_send_init_cmds(gc9503_panel_t *gc9503)
gc9503->madctl_val,
}, 1), TAG, "send command failed");;
ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, LCD_CMD_COLMOD, (uint8_t[]) {
gc9503->colmod_cal,
gc9503->colmod_val,
}, 1), TAG, "send command failed");;

// Vendor specific initialization, it can be different between manufacturers
// should consult the LCD supplier for initialization sequence code
const gc9503_lcd_init_cmd_t *init_cmds = NULL;
uint16_t init_cmds_size = 0;
if (gc9503->init_cmds) {
ESP_LOGD(TAG, "use external initialization commands");
init_cmds = gc9503->init_cmds;
init_cmds_size = gc9503->init_cmds_size;
} else {
init_cmds = vendor_specific_init_default;
init_cmds_size = sizeof(vendor_specific_init_default) / sizeof(gc9503_lcd_init_cmd_t);
}

bool is_cmd_overwritten = false;
for (int i = 0; i < init_cmds_size; i++) {
// Check if the command has been used or conflicts with the internal
switch (init_cmds[i].cmd) {
case LCD_CMD_MADCTL:
is_cmd_overwritten = true;
gc9503->madctl_val = ((uint8_t *)init_cmds[i].data)[0];
break;
case LCD_CMD_COLMOD:
is_cmd_overwritten = true;
gc9503->colmod_val = ((uint8_t *)init_cmds[i].data)[0];
break;
default:
is_cmd_overwritten = false;
break;
}

if (is_cmd_overwritten) {
ESP_LOGW(TAG, "The %02Xh command has been used and will be overwritten by external initialization sequence",
init_cmds[i].cmd);
}

ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, init_cmds[i].cmd, init_cmds[i].data, init_cmds[i].data_bytes),
TAG, "send command failed");
vTaskDelay(pdMS_TO_TICKS(init_cmds[i].delay_ms));
Expand All @@ -241,6 +289,19 @@ static esp_err_t panel_gc9503_send_init_cmds(gc9503_panel_t *gc9503)
return ESP_OK;
}

static esp_err_t panel_gc9503_init(esp_lcd_panel_t *panel)
{
gc9503_panel_t *gc9503 = (gc9503_panel_t *)panel->user_data;

if (!gc9503->flags.auto_del_panel_io) {
ESP_RETURN_ON_ERROR(panel_gc9503_send_init_cmds(gc9503), TAG, "send init commands failed");
}
// Init RGB panel
ESP_RETURN_ON_ERROR(gc9503->init(panel), TAG, "init RGB panel failed");

return ESP_OK;
}

static esp_err_t panel_gc9503_del(esp_lcd_panel_t *panel)
{
gc9503_panel_t *gc9503 = (gc9503_panel_t *)panel->user_data;
Expand All @@ -262,9 +323,9 @@ static esp_err_t panel_gc9503_reset(esp_lcd_panel_t *panel)

// Perform hardware reset
if (gc9503->reset_gpio_num >= 0) {
gpio_set_level(gc9503->reset_gpio_num, gc9503->reset_level);
gpio_set_level(gc9503->reset_gpio_num, gc9503->flags.reset_level);
vTaskDelay(pdMS_TO_TICKS(10));
gpio_set_level(gc9503->reset_gpio_num, !gc9503->reset_level);
gpio_set_level(gc9503->reset_gpio_num, !gc9503->flags.reset_level);
vTaskDelay(pdMS_TO_TICKS(120));
} else if (io) { // Perform software reset
ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, LCD_CMD_SWRESET, NULL, 0), TAG, "send command failed");
Expand Down
5 changes: 3 additions & 2 deletions components/lcd/esp_lcd_gc9503/idf_component.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
version: "2.0.0"
version: "2.1.0"
targets:
- esp32s3
description: ESP LCD GC9503
url: https://github.com/espressif/esp-bsp/tree/master/components/lcd/esp_lcd_gc9503
dependencies:
idf: ">=5.0"
idf: ">=5.0.4"
cmake_utilities: "0.*"
32 changes: 16 additions & 16 deletions components/lcd/esp_lcd_gc9503/include/esp_lcd_gc9503.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@

#include <stdint.h>

#include "hal/lcd_types.h"
#include "esp_lcd_panel_vendor.h"
#include "esp_lcd_panel_rgb.h"

Expand Down Expand Up @@ -43,22 +42,23 @@ typedef struct {
* The array should be declared as `static const` and positioned outside the function.
* Please refer to `vendor_specific_init_default` in source file.
*/
uint16_t init_cmds_size; /*<! Number of commands in above array */
uint16_t init_cmds_size; /*<! Number of commands in above array */
struct {
unsigned int mirror_by_cmd: 1; /*<! The `mirror()` function will be implemented by LCD command if set to 1.
* Otherwise, the function will be implemented by software.
*/
unsigned int auto_del_panel_io: 1; /*<! Delete the panel IO instance automatically if set to 1. All `*_by_cmd` flags will be invalid.
* If the panel IO pins are sharing other pins of the RGB interface to save GPIOs,
* Please set it to 1 to release the panel IO and its pins (except CS signal).
*/
unsigned int mirror_by_cmd: 1; /*<! The `mirror()` function will be implemented by LCD command if set to 1.
* Otherwise, the function will be implemented by software.
*/
unsigned int auto_del_panel_io: 1; /*<! Delete the panel IO instance automatically if set to 1. All `*_by_cmd` flags will be invalid.
* If the panel IO pins are sharing other pins of the RGB interface to save GPIOs,
* Please set it to 1 to release the panel IO and its pins (except CS signal).
*/
} flags;
} gc9503_vendor_config_t;

/**
* @brief Create LCD panel for model GC9503
*
* @note This function first initialize GC9503 with vendor specific initialization, then calls `esp_lcd_new_rgb_panel()` to create a RGB LCD panel.
* @note When `auto_del_panel_io` is set to 1, this function will first initialize the GC9503 with vendor specific initialization and then calls `esp_lcd_new_rgb_panel()` to create an RGB LCD panel. And the `esp_lcd_panel_init()` function will only initialize RGB.
* @note When `auto_del_panel_io` is set to 0, this function will only call `esp_lcd_new_rgb_panel()` to create an RGB LCD panel. And the `esp_lcd_panel_init()` function will initialize both the GC9503 and RGB.
* @note Vendor specific initialization can be different between manufacturers, should consult the LCD supplier for initialization sequence code.
*
* @param[in] io LCD panel IO handle
Expand Down Expand Up @@ -87,11 +87,11 @@ esp_err_t esp_lcd_new_panel_gc9503(const esp_lcd_panel_io_handle_t io, const esp
.lcd_cmd_bytes = 1, \
.lcd_param_bytes = 1, \
.flags = { \
.use_dc_bit = true, \
.dc_zero_on_data = false, \
.lsb_first = false, \
.cs_high_active = false, \
.del_keep_cs_inactive = true, \
.use_dc_bit = 1, \
.dc_zero_on_data = 0, \
.lsb_first = 0, \
.cs_high_active = 0, \
.del_keep_cs_inactive = 1, \
}, \
}

Expand All @@ -114,7 +114,7 @@ esp_err_t esp_lcd_new_panel_gc9503(const esp_lcd_panel_io_handle_t io, const esp
.vsync_pulse_width = 10, \
.vsync_back_porch = 10, \
.vsync_front_porch = 10, \
.flags.pclk_active_neg = false, \
.flags.pclk_active_neg = 0, \
}

#ifdef __cplusplus
Expand Down
6 changes: 6 additions & 0 deletions components/lcd/esp_lcd_gc9503/test_apps/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# The following lines of boilerplate have to be in your project's CMakeLists
# in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
set(EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/unit-test-app/components")
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(test_esp_lcd_gc9503)
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
idf_component_register(SRCS "test_esp_lcd_gc9503.c")
12 changes: 12 additions & 0 deletions components/lcd/esp_lcd_gc9503/test_apps/main/idf_component.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
## IDF Component Manager Manifest File
dependencies:
idf: ">=5.0.0"
esp_lcd_panel_io_additions:
version: "^1"
public: true
esp_io_expander_tca9554:
version: "^1"
public: true
esp_lcd_gc9503:
version: "*"
override_path: "../../../esp_lcd_gc9503"
Loading

0 comments on commit 21277f5

Please sign in to comment.