diff --git a/components/esp_lcd/include/esp_lcd_panel_dev.h b/components/esp_lcd/include/esp_lcd_panel_dev.h new file mode 100644 index 0000000000..1a86d2b964 --- /dev/null +++ b/components/esp_lcd/include/esp_lcd_panel_dev.h @@ -0,0 +1,37 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#include +#include +#include "esp_err.h" +#include "esp_lcd_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Configuration structure for panel device + */ +typedef struct { + int reset_gpio_num; /*!< GPIO used to reset the LCD panel, set to -1 if it's not used */ + union { + lcd_rgb_element_order_t color_space; /*!< @deprecated Set RGB color space, please use rgb_ele_order instead */ + lcd_rgb_element_order_t rgb_endian; /*!< @deprecated Set RGB data endian, please use rgb_ele_order instead */ + lcd_rgb_element_order_t rgb_ele_order; /*!< Set RGB element order, RGB or BGR */ + }; + lcd_rgb_data_endian_t data_endian; /*!< Set the data endian for color data larger than 1 byte */ + uint32_t bits_per_pixel; /*!< Color depth, in bpp */ + struct { + uint32_t reset_active_high: 1; /*!< Setting this if the panel reset is high level active */ + } flags; /*!< LCD panel config flags */ + void *vendor_config; /*!< vendor specific configuration, optional, left as NULL if not used */ +} esp_lcd_panel_dev_config_t; + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_lcd/include/esp_lcd_panel_nt35510.h b/components/esp_lcd/include/esp_lcd_panel_nt35510.h new file mode 100644 index 0000000000..627528f5ef --- /dev/null +++ b/components/esp_lcd/include/esp_lcd_panel_nt35510.h @@ -0,0 +1,31 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#include +#include "esp_err.h" +#include "esp_lcd_panel_dev.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Create LCD panel for model NT35510 + * + * @param[in] io LCD panel IO handle + * @param[in] panel_dev_config general panel device configuration + * @param[out] ret_panel Returned LCD panel handle + * @return + * - ESP_ERR_INVALID_ARG if parameter is invalid + * - ESP_ERR_NO_MEM if out of memory + * - ESP_OK on success + */ +esp_err_t esp_lcd_new_panel_nt35510(const esp_lcd_panel_io_handle_t io, const esp_lcd_panel_dev_config_t *panel_dev_config, esp_lcd_panel_handle_t *ret_panel); + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_lcd/include/esp_lcd_panel_ssd1306.h b/components/esp_lcd/include/esp_lcd_panel_ssd1306.h new file mode 100644 index 0000000000..387e016523 --- /dev/null +++ b/components/esp_lcd/include/esp_lcd_panel_ssd1306.h @@ -0,0 +1,61 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#include +#include "esp_err.h" +#include "esp_lcd_panel_dev.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief SSD1306 configuration structure + * + * To be used as esp_lcd_panel_dev_config_t.vendor_config. + * See esp_lcd_new_panel_ssd1306(). + */ +typedef struct { + /** + * @brief Display's height in pixels (64(default) or 32) + */ + uint8_t height; +} esp_lcd_panel_ssd1306_config_t; + +/** + * @brief Create LCD panel for model SSD1306 + * + * @param[in] io LCD panel IO handle + * @param[in] panel_dev_config general panel device configuration + * @param[out] ret_panel Returned LCD panel handle + * @return + * - ESP_ERR_INVALID_ARG if parameter is invalid + * - ESP_ERR_NO_MEM if out of memory + * - ESP_OK on success + * + * @note The default panel size is 128x64. + * @note Use esp_lcd_panel_ssd1306_config_t to set the correct size. + * Example usage: + * @code {c} + * + * esp_lcd_panel_ssd1306_config_t ssd1306_config = { + * .height = 32 + * }; + * esp_lcd_panel_dev_config_t panel_config = { + * <...> + * .vendor_config = &ssd1306_config + * }; + * + * esp_lcd_panel_handle_t panel_handle = NULL; + * esp_lcd_new_panel_ssd1306(io_handle, &panel_config, &panel_handle); + * @endcode + */ +esp_err_t esp_lcd_new_panel_ssd1306(const esp_lcd_panel_io_handle_t io, const esp_lcd_panel_dev_config_t *panel_dev_config, esp_lcd_panel_handle_t *ret_panel); + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_lcd/include/esp_lcd_panel_st7789.h b/components/esp_lcd/include/esp_lcd_panel_st7789.h new file mode 100644 index 0000000000..d92d03d985 --- /dev/null +++ b/components/esp_lcd/include/esp_lcd_panel_st7789.h @@ -0,0 +1,31 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#include +#include "esp_err.h" +#include "esp_lcd_panel_dev.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Create LCD panel for model ST7789 + * + * @param[in] io LCD panel IO handle + * @param[in] panel_dev_config general panel device configuration + * @param[out] ret_panel Returned LCD panel handle + * @return + * - ESP_ERR_INVALID_ARG if parameter is invalid + * - ESP_ERR_NO_MEM if out of memory + * - ESP_OK on success + */ +esp_err_t esp_lcd_new_panel_st7789(const esp_lcd_panel_io_handle_t io, const esp_lcd_panel_dev_config_t *panel_dev_config, esp_lcd_panel_handle_t *ret_panel); + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_lcd/include/esp_lcd_panel_vendor.h b/components/esp_lcd/include/esp_lcd_panel_vendor.h index 2f5c8fd261..763d022b9c 100644 --- a/components/esp_lcd/include/esp_lcd_panel_vendor.h +++ b/components/esp_lcd/include/esp_lcd_panel_vendor.h @@ -1,75 +1,12 @@ /* - * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ + #pragma once -#include -#include "esp_err.h" -#include "esp_lcd_types.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @brief Configuration structure for panel device - */ -typedef struct { - int reset_gpio_num; /*!< GPIO used to reset the LCD panel, set to -1 if it's not used */ - union { - lcd_rgb_element_order_t color_space; /*!< @deprecated Set RGB color space, please use rgb_ele_order instead */ - lcd_rgb_element_order_t rgb_endian; /*!< @deprecated Set RGB data endian, please use rgb_ele_order instead */ - lcd_rgb_element_order_t rgb_ele_order; /*!< Set RGB element order, RGB or BGR */ - }; - lcd_rgb_data_endian_t data_endian; /*!< Set the data endian for color data larger than 1 byte */ - unsigned int bits_per_pixel; /*!< Color depth, in bpp */ - struct { - unsigned int reset_active_high: 1; /*!< Setting this if the panel reset is high level active */ - } flags; /*!< LCD panel config flags */ - void *vendor_config; /*!< vendor specific configuration, optional, left as NULL if not used */ -} esp_lcd_panel_dev_config_t; - -/** - * @brief Create LCD panel for model ST7789 - * - * @param[in] io LCD panel IO handle - * @param[in] panel_dev_config general panel device configuration - * @param[out] ret_panel Returned LCD panel handle - * @return - * - ESP_ERR_INVALID_ARG if parameter is invalid - * - ESP_ERR_NO_MEM if out of memory - * - ESP_OK on success - */ -esp_err_t esp_lcd_new_panel_st7789(const esp_lcd_panel_io_handle_t io, const esp_lcd_panel_dev_config_t *panel_dev_config, esp_lcd_panel_handle_t *ret_panel); - -/** - * @brief Create LCD panel for model NT35510 - * - * @param[in] io LCD panel IO handle - * @param[in] panel_dev_config general panel device configuration - * @param[out] ret_panel Returned LCD panel handle - * @return - * - ESP_ERR_INVALID_ARG if parameter is invalid - * - ESP_ERR_NO_MEM if out of memory - * - ESP_OK on success - */ -esp_err_t esp_lcd_new_panel_nt35510(const esp_lcd_panel_io_handle_t io, const esp_lcd_panel_dev_config_t *panel_dev_config, esp_lcd_panel_handle_t *ret_panel); - -/** - * @brief Create LCD panel for model SSD1306 - * - * @param[in] io LCD panel IO handle - * @param[in] panel_dev_config general panel device configuration - * @param[out] ret_panel Returned LCD panel handle - * @return - * - ESP_ERR_INVALID_ARG if parameter is invalid - * - ESP_ERR_NO_MEM if out of memory - * - ESP_OK on success - */ -esp_err_t esp_lcd_new_panel_ssd1306(const esp_lcd_panel_io_handle_t io, const esp_lcd_panel_dev_config_t *panel_dev_config, esp_lcd_panel_handle_t *ret_panel); - -#ifdef __cplusplus -} -#endif +#include "esp_lcd_panel_dev.h" +#include "esp_lcd_panel_ssd1306.h" +#include "esp_lcd_panel_st7789.h" +#include "esp_lcd_panel_nt35510.h" diff --git a/components/esp_lcd/include/esp_lcd_types.h b/components/esp_lcd/include/esp_lcd_types.h index 6f5928061c..6c6856d838 100644 --- a/components/esp_lcd/include/esp_lcd_types.h +++ b/components/esp_lcd/include/esp_lcd_types.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -15,6 +15,14 @@ extern "C" { typedef struct esp_lcd_panel_io_t *esp_lcd_panel_io_handle_t; /*!< Type of LCD panel IO handle */ typedef struct esp_lcd_panel_t *esp_lcd_panel_handle_t; /*!< Type of LCD panel handle */ +/** + * @brief RGB element order + */ +typedef enum { + LCD_RGB_ELEMENT_ORDER_RGB, /*!< RGB element order: RGB */ + LCD_RGB_ELEMENT_ORDER_BGR, /*!< RGB element order: BGR */ +} lcd_rgb_element_order_t; + /** @cond */ /** * @brief LCD color space type definition (WRONG!) @@ -30,6 +38,11 @@ typedef enum { // Ensure binary compatibility with lcd_color_rgb_endian_t ESP_STATIC_ASSERT((lcd_rgb_element_order_t)ESP_LCD_COLOR_SPACE_RGB == LCD_RGB_ELEMENT_ORDER_RGB, "ESP_LCD_COLOR_SPACE_RGB is not compatible with LCD_RGB_ORDER_RGB"); ESP_STATIC_ASSERT((lcd_rgb_element_order_t)ESP_LCD_COLOR_SPACE_BGR == LCD_RGB_ELEMENT_ORDER_BGR, "ESP_LCD_COLOR_SPACE_BGR is not compatible with LCD_RGB_ORDER_BGR"); + +/// for backward compatible +typedef lcd_rgb_element_order_t lcd_color_rgb_endian_t; +#define LCD_RGB_ENDIAN_RGB LCD_RGB_ELEMENT_ORDER_RGB +#define LCD_RGB_ENDIAN_BGR LCD_RGB_ELEMENT_ORDER_BGR /** @endcond */ #ifdef __cplusplus diff --git a/components/esp_lcd/src/esp_lcd_panel_io_i2c_v1.c b/components/esp_lcd/src/esp_lcd_panel_io_i2c_v1.c index ba7731b2dc..3928d81ed9 100644 --- a/components/esp_lcd/src/esp_lcd_panel_io_i2c_v1.c +++ b/components/esp_lcd/src/esp_lcd_panel_io_i2c_v1.c @@ -95,7 +95,7 @@ static esp_err_t panel_io_i2c_register_event_callbacks(esp_lcd_panel_io_handle_t lcd_panel_io_i2c_t *i2c_panel_io = __containerof(io, lcd_panel_io_i2c_t, base); if (i2c_panel_io->on_color_trans_done != NULL) { - ESP_LOGW(TAG, "Callback on_color_trans_done was already set and now it was owerwritten!"); + ESP_LOGW(TAG, "Callback on_color_trans_done was already set and now it was overwritten!"); } i2c_panel_io->on_color_trans_done = cbs->on_color_trans_done; diff --git a/components/esp_lcd/src/esp_lcd_panel_io_i2c_v2.c b/components/esp_lcd/src/esp_lcd_panel_io_i2c_v2.c index fa2c834adc..e8a50d8ee4 100644 --- a/components/esp_lcd/src/esp_lcd_panel_io_i2c_v2.c +++ b/components/esp_lcd/src/esp_lcd_panel_io_i2c_v2.c @@ -106,7 +106,7 @@ static esp_err_t panel_io_i2c_register_event_callbacks(esp_lcd_panel_io_handle_t lcd_panel_io_i2c_t *i2c_panel_io = __containerof(io, lcd_panel_io_i2c_t, base); if (i2c_panel_io->on_color_trans_done != NULL) { - ESP_LOGW(TAG, "Callback on_color_trans_done was already set and now it was owerwritten!"); + ESP_LOGW(TAG, "Callback on_color_trans_done was already set and now it was overwritten!"); } i2c_panel_io->on_color_trans_done = cbs->on_color_trans_done; diff --git a/components/esp_lcd/src/esp_lcd_panel_ssd1306.c b/components/esp_lcd/src/esp_lcd_panel_ssd1306.c index d2a94aefb1..4ccb6710a5 100644 --- a/components/esp_lcd/src/esp_lcd_panel_ssd1306.c +++ b/components/esp_lcd/src/esp_lcd_panel_ssd1306.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -17,7 +17,7 @@ #include "freertos/task.h" #include "esp_lcd_panel_interface.h" #include "esp_lcd_panel_io.h" -#include "esp_lcd_panel_vendor.h" +#include "esp_lcd_panel_ssd1306.h" #include "esp_lcd_panel_ops.h" #include "driver/gpio.h" #include "esp_log.h" @@ -34,10 +34,12 @@ static const char *TAG = "lcd_panel.ssd1306"; #define SSD1306_CMD_MIRROR_X_ON 0xA1 #define SSD1306_CMD_INVERT_OFF 0xA6 #define SSD1306_CMD_INVERT_ON 0xA7 +#define SSD1306_CMD_SET_MULTIPLEX 0xA8 #define SSD1306_CMD_DISP_OFF 0xAE #define SSD1306_CMD_DISP_ON 0xAF #define SSD1306_CMD_MIRROR_Y_OFF 0xC0 #define SSD1306_CMD_MIRROR_Y_ON 0xC8 +#define SSD1306_CMD_SET_COMPINS 0xDA static esp_err_t panel_ssd1306_del(esp_lcd_panel_t *panel); static esp_err_t panel_ssd1306_reset(esp_lcd_panel_t *panel); @@ -52,11 +54,12 @@ static esp_err_t panel_ssd1306_disp_on_off(esp_lcd_panel_t *panel, bool off); typedef struct { esp_lcd_panel_t base; esp_lcd_panel_io_handle_t io; + uint8_t height; int reset_gpio_num; - bool reset_level; int x_gap; int y_gap; unsigned int bits_per_pixel; + bool reset_level; bool swap_axes; } ssd1306_panel_t; @@ -69,6 +72,7 @@ esp_err_t esp_lcd_new_panel_ssd1306(const esp_lcd_panel_io_handle_t io, const es ssd1306_panel_t *ssd1306 = NULL; ESP_GOTO_ON_FALSE(io && panel_dev_config && ret_panel, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument"); ESP_GOTO_ON_FALSE(panel_dev_config->bits_per_pixel == 1, ESP_ERR_INVALID_ARG, err, TAG, "bpp must be 1"); + esp_lcd_panel_ssd1306_config_t *ssd1306_spec_config = (esp_lcd_panel_ssd1306_config_t *)panel_dev_config->vendor_config; ssd1306 = calloc(1, sizeof(ssd1306_panel_t)); ESP_GOTO_ON_FALSE(ssd1306, ESP_ERR_NO_MEM, err, TAG, "no mem for ssd1306 panel"); @@ -84,6 +88,7 @@ esp_err_t esp_lcd_new_panel_ssd1306(const esp_lcd_panel_io_handle_t io, const es ssd1306->bits_per_pixel = panel_dev_config->bits_per_pixel; ssd1306->reset_gpio_num = panel_dev_config->reset_gpio_num; ssd1306->reset_level = panel_dev_config->flags.reset_active_high; + ssd1306->height = ssd1306_spec_config ? ssd1306_spec_config->height : 64; ssd1306->base.del = panel_ssd1306_del; ssd1306->base.reset = panel_ssd1306_reset; ssd1306->base.init = panel_ssd1306_init; @@ -138,6 +143,13 @@ static esp_err_t panel_ssd1306_init(esp_lcd_panel_t *panel) { ssd1306_panel_t *ssd1306 = __containerof(panel, ssd1306_panel_t, base); esp_lcd_panel_io_handle_t io = ssd1306->io; + + ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, SSD1306_CMD_SET_MULTIPLEX, (uint8_t[]) { + ssd1306->height - 1 // set multiplex ratio + }, 1), TAG, "io tx param SSD1306_CMD_SET_MULTIPLEX failed"); + ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, SSD1306_CMD_SET_COMPINS, (uint8_t[1]) { + ssd1306->height == 64 ? 0x12 : 0x02 // set COM pins hardware configuration + }, 1), TAG, "io tx param SSD1306_CMD_SET_COMPINS failed"); ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, SSD1306_CMD_DISP_OFF, NULL, 0), TAG, "io tx param SSD1306_CMD_DISP_OFF failed"); ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, SSD1306_CMD_SET_MEMORY_ADDR_MODE, (uint8_t[]) { diff --git a/components/esp_lcd/src/esp_lcd_panel_st7789.c b/components/esp_lcd/src/esp_lcd_panel_st7789.c index 76e26fd6da..fc43f91582 100644 --- a/components/esp_lcd/src/esp_lcd_panel_st7789.c +++ b/components/esp_lcd/src/esp_lcd_panel_st7789.c @@ -77,11 +77,11 @@ esp_lcd_new_panel_st7789(const esp_lcd_panel_io_handle_t io, const esp_lcd_panel ESP_GOTO_ON_ERROR(gpio_config(&io_conf), err, TAG, "configure GPIO for RST line failed"); } - switch (panel_dev_config->rgb_endian) { - case LCD_RGB_ENDIAN_RGB: + switch (panel_dev_config->rgb_ele_order) { + case LCD_RGB_ELEMENT_ORDER_RGB: st7789->madctl_val = 0; break; - case LCD_RGB_ENDIAN_BGR: + case LCD_RGB_ELEMENT_ORDER_BGR: st7789->madctl_val |= LCD_CMD_BGR_BIT; break; default: diff --git a/components/hal/esp32s3/include/hal/lcd_ll.h b/components/hal/esp32s3/include/hal/lcd_ll.h index 2f30e5b210..1be0b4d509 100644 --- a/components/hal/esp32s3/include/hal/lcd_ll.h +++ b/components/hal/esp32s3/include/hal/lcd_ll.h @@ -29,10 +29,6 @@ extern "C" { #define LCD_LL_CLK_FRAC_DIV_AB_MAX 64 // LCD_CLK = LCD_CLK_S / (N + b/a), the a/b register is 6 bit-width #define LCD_LL_PCLK_DIV_MAX 64 // LCD_PCLK = LCD_CLK / MO, the MO register is 6 bit-width -#define LCD_LL_COLOR_RANGE_TO_REG(range) (uint8_t[]){0,1}[(range)] -#define LCD_LL_CONV_STD_TO_REG(std) (uint8_t[]){0,1}[(std)] -#define LCD_LL_YUV_SAMPLE_TO_REG(sample) (uint8_t[]){0,1,2}[(sample)] - /** * @brief Enable clock gating * @@ -92,7 +88,6 @@ static inline void lcd_ll_set_group_clock_coeff(lcd_cam_dev_t *dev, int div_num, dev->lcd_clock.lcd_clkm_div_b = div_b; } - /** * @brief Set the PCLK clock level state when there's no transaction undergoing * @@ -170,7 +165,11 @@ static inline void lcd_ll_set_convert_data_width(lcd_cam_dev_t *dev, uint32_t wi */ static inline void lcd_ll_set_input_color_range(lcd_cam_dev_t *dev, lcd_color_range_t range) { - dev->lcd_rgb_yuv.lcd_conv_data_in_mode = LCD_LL_COLOR_RANGE_TO_REG(range); + if (range == LCD_COLOR_RANGE_LIMIT) { + dev->lcd_rgb_yuv.lcd_conv_data_in_mode = 0; + } else if (range == LCD_COLOR_RANGE_FULL) { + dev->lcd_rgb_yuv.lcd_conv_data_in_mode = 1; + } } /** @@ -181,7 +180,11 @@ static inline void lcd_ll_set_input_color_range(lcd_cam_dev_t *dev, lcd_color_ra */ static inline void lcd_ll_set_output_color_range(lcd_cam_dev_t *dev, lcd_color_range_t range) { - dev->lcd_rgb_yuv.lcd_conv_data_out_mode = LCD_LL_COLOR_RANGE_TO_REG(range); + if (range == LCD_COLOR_RANGE_LIMIT) { + dev->lcd_rgb_yuv.lcd_conv_data_out_mode = 0; + } else if (range == LCD_COLOR_RANGE_FULL) { + dev->lcd_rgb_yuv.lcd_conv_data_out_mode = 1; + } } /** @@ -192,7 +195,11 @@ static inline void lcd_ll_set_output_color_range(lcd_cam_dev_t *dev, lcd_color_r */ static inline void lcd_ll_set_yuv_convert_std(lcd_cam_dev_t *dev, lcd_yuv_conv_std_t std) { - dev->lcd_rgb_yuv.lcd_conv_protocol_mode = LCD_LL_CONV_STD_TO_REG(std); + if (std == LCD_YUV_CONV_STD_BT601) { + dev->lcd_rgb_yuv.lcd_conv_protocol_mode = 0; + } else if (std == LCD_YUV_CONV_STD_BT709) { + dev->lcd_rgb_yuv.lcd_conv_protocol_mode = 1; + } } /** @@ -204,8 +211,20 @@ static inline void lcd_ll_set_yuv_convert_std(lcd_cam_dev_t *dev, lcd_yuv_conv_s static inline void lcd_ll_set_convert_mode_rgb_to_yuv(lcd_cam_dev_t *dev, lcd_yuv_sample_t yuv_sample) { dev->lcd_rgb_yuv.lcd_conv_trans_mode = 1; - dev->lcd_rgb_yuv.lcd_conv_yuv_mode = LCD_LL_YUV_SAMPLE_TO_REG(yuv_sample); dev->lcd_rgb_yuv.lcd_conv_yuv2yuv_mode = 3; + switch (yuv_sample) { + case LCD_YUV_SAMPLE_422: + dev->lcd_rgb_yuv.lcd_conv_yuv_mode = 0; + break; + case LCD_YUV_SAMPLE_420: + dev->lcd_rgb_yuv.lcd_conv_yuv_mode = 1; + break; + case LCD_YUV_SAMPLE_411: + dev->lcd_rgb_yuv.lcd_conv_yuv_mode = 2; + break; + default: + abort(); + } } /** @@ -217,8 +236,20 @@ static inline void lcd_ll_set_convert_mode_rgb_to_yuv(lcd_cam_dev_t *dev, lcd_yu static inline void lcd_ll_set_convert_mode_yuv_to_rgb(lcd_cam_dev_t *dev, lcd_yuv_sample_t yuv_sample) { dev->lcd_rgb_yuv.lcd_conv_trans_mode = 0; - dev->lcd_rgb_yuv.lcd_conv_yuv_mode = LCD_LL_YUV_SAMPLE_TO_REG(yuv_sample); dev->lcd_rgb_yuv.lcd_conv_yuv2yuv_mode = 3; + switch (yuv_sample) { + case LCD_YUV_SAMPLE_422: + dev->lcd_rgb_yuv.lcd_conv_yuv_mode = 0; + break; + case LCD_YUV_SAMPLE_420: + dev->lcd_rgb_yuv.lcd_conv_yuv_mode = 1; + break; + case LCD_YUV_SAMPLE_411: + dev->lcd_rgb_yuv.lcd_conv_yuv_mode = 2; + break; + default: + abort(); + } } /** @@ -232,8 +263,32 @@ static inline void lcd_ll_set_convert_mode_yuv_to_yuv(lcd_cam_dev_t *dev, lcd_yu { HAL_ASSERT(src_sample != dst_sample); dev->lcd_rgb_yuv.lcd_conv_trans_mode = 1; - dev->lcd_rgb_yuv.lcd_conv_yuv_mode = LCD_LL_YUV_SAMPLE_TO_REG(src_sample); - dev->lcd_rgb_yuv.lcd_conv_yuv2yuv_mode = LCD_LL_YUV_SAMPLE_TO_REG(dst_sample); + switch (src_sample) { + case LCD_YUV_SAMPLE_422: + dev->lcd_rgb_yuv.lcd_conv_yuv_mode = 0; + break; + case LCD_YUV_SAMPLE_420: + dev->lcd_rgb_yuv.lcd_conv_yuv_mode = 1; + break; + case LCD_YUV_SAMPLE_411: + dev->lcd_rgb_yuv.lcd_conv_yuv_mode = 2; + break; + default: + abort(); + } + switch (dst_sample) { + case LCD_YUV_SAMPLE_422: + dev->lcd_rgb_yuv.lcd_conv_yuv2yuv_mode = 0; + break; + case LCD_YUV_SAMPLE_420: + dev->lcd_rgb_yuv.lcd_conv_yuv2yuv_mode = 1; + break; + case LCD_YUV_SAMPLE_411: + dev->lcd_rgb_yuv.lcd_conv_yuv2yuv_mode = 2; + break; + default: + abort(); + } } /** diff --git a/components/hal/include/hal/color_types.h b/components/hal/include/hal/color_types.h index 5890da3f42..5ccd6b4ad3 100644 --- a/components/hal/include/hal/color_types.h +++ b/components/hal/include/hal/color_types.h @@ -12,13 +12,6 @@ extern "C" { #endif -/** - * @background - * - * Color Space: a specific representation of colors, e.g. RGB, YUV, etc. - * Color Pixel Format: a specific pixel format of a certain color space, e.g. RGB565, YUV422, etc. - */ - /*--------------------------------------------------------------- Color Space ---------------------------------------------------------------*/ @@ -33,7 +26,7 @@ typedef enum { } color_space_t; /*--------------------------------------------------------------- - Color Space Format + Color Pixel Format ---------------------------------------------------------------*/ /** * @brief Raw Format @@ -59,6 +52,7 @@ typedef enum { COLOR_PIXEL_YUV444, ///< 24 bits, 8 bits per Y/U/V value COLOR_PIXEL_YUV422, ///< 16 bits, 8-bit Y per pixel, 8-bit U and V per two pixels COLOR_PIXEL_YUV420, ///< 12 bits, 8-bit Y per pixel, 8-bit U and V per four pixels + COLOR_PIXEL_YUV411, ///< 12 bits, 8-bit Y per pixel, 8-bit U and V per four pixels } color_pixel_yuv_format_t; /** @@ -70,16 +64,18 @@ typedef enum { } color_pixel_gray_format_t; /*--------------------------------------------------------------- - Color Space Struct Type + Color Space Pixel Struct Type ---------------------------------------------------------------*/ -///< Bitwidth of the `color_space_format_t:color_space` field +///< Bitwidth of the `color_space_pixel_format_t::color_space` field #define COLOR_SPACE_BITWIDTH 8 -///< Bitwidth of the `color_space_format_t:pixel_format` field +///< Bitwidth of the `color_space_pixel_format_t::pixel_format` field #define COLOR_PIXEL_FORMAT_BITWIDTH 24 -///< Helper to get `color_space_format_t:color_space` from its `color_space_pixel_format_t:color_type_id` +///< Helper to get the color_space from a unique color type ID #define COLOR_SPACE_TYPE(color_type_id) (((color_type_id) >> COLOR_PIXEL_FORMAT_BITWIDTH) & ((1 << COLOR_SPACE_BITWIDTH) - 1)) -///< Helper to get `color_space_format_t:pixel_format` from its `color_space_pixel_format_t:color_type_id` +///< Helper to get the pixel_format from a unique color type ID #define COLOR_PIXEL_FORMAT(color_type_id) ((color_type_id) & ((1 << COLOR_PIXEL_FORMAT_BITWIDTH) - 1)) +///< Make a unique ID of a color based on the value of color space and pixel format +#define COLOR_TYPE_ID(color_space, pixel_format) (((color_space) << COLOR_PIXEL_FORMAT_BITWIDTH) | (pixel_format)) /** * @brief Color Space Info Structure @@ -92,6 +88,26 @@ typedef union { uint32_t color_type_id; ///< Unique type of a certain color pixel format } color_space_pixel_format_t; +/*--------------------------------------------------------------- + Color Conversion +---------------------------------------------------------------*/ +/** + * @brief LCD color range + * @note The difference between a full range color and a limited range color is + * the amount of shades of black and white that they can display. + */ +typedef enum { + COLOR_RANGE_LIMIT, /*!< Limited color range, 16 is the darkest black and 235 is the brightest white */ + COLOR_RANGE_FULL, /*!< Full color range, 0 is the darkest black and 255 is the brightest white */ +} color_range_t; + +/** + * @brief The standard used for conversion between RGB and YUV + */ +typedef enum { + COLOR_CONV_STD_RGB_YUV_BT601, /*!< YUV<->RGB conversion standard: BT.601 */ + COLOR_CONV_STD_RGB_YUV_BT709, /*!< YUV<->RGB conversion standard: BT.709 */ +} color_conv_std_rgb_yuv_t; #ifdef __cplusplus } diff --git a/components/hal/include/hal/isp_types.h b/components/hal/include/hal/isp_types.h index 27d7e0bc12..cbbb2fd00c 100644 --- a/components/hal/include/hal/isp_types.h +++ b/components/hal/include/hal/isp_types.h @@ -36,13 +36,13 @@ typedef enum { * @brief ISP Color Type */ typedef enum { - ISP_COLOR_RAW8 = (COLOR_SPACE_RAW << COLOR_PIXEL_FORMAT_BITWIDTH) + COLOR_PIXEL_RAW8, ///< RAW8 - ISP_COLOR_RAW10 = (COLOR_SPACE_RAW << COLOR_PIXEL_FORMAT_BITWIDTH) + COLOR_PIXEL_RAW10, ///< RAW10 - ISP_COLOR_RAW12 = (COLOR_SPACE_RAW << COLOR_PIXEL_FORMAT_BITWIDTH) + COLOR_PIXEL_RAW12, ///< RAW12 - ISP_COLOR_RGB888 = (COLOR_SPACE_RGB << COLOR_PIXEL_FORMAT_BITWIDTH) + COLOR_PIXEL_RGB888, ///< RGB888 - ISP_COLOR_RGB565 = (COLOR_SPACE_RGB << COLOR_PIXEL_FORMAT_BITWIDTH) + COLOR_PIXEL_RGB565, ///< RGB565 - ISP_COLOR_YUV422 = (COLOR_SPACE_YUV << COLOR_PIXEL_FORMAT_BITWIDTH) + COLOR_PIXEL_YUV422, ///< YUV422 - ISP_COLOR_YUV420 = (COLOR_SPACE_YUV << COLOR_PIXEL_FORMAT_BITWIDTH) + COLOR_PIXEL_YUV420, ///< YUV420 + ISP_COLOR_RAW8 = COLOR_TYPE_ID(COLOR_SPACE_RAW, COLOR_PIXEL_RAW8), ///< RAW8 + ISP_COLOR_RAW10 = COLOR_TYPE_ID(COLOR_SPACE_RAW, COLOR_PIXEL_RAW10), ///< RAW10 + ISP_COLOR_RAW12 = COLOR_TYPE_ID(COLOR_SPACE_RAW, COLOR_PIXEL_RAW12), ///< RAW12 + ISP_COLOR_RGB888 = COLOR_TYPE_ID(COLOR_SPACE_RGB, COLOR_PIXEL_RGB888), ///< RGB888 + ISP_COLOR_RGB565 = COLOR_TYPE_ID(COLOR_SPACE_RGB, COLOR_PIXEL_RGB565), ///< RGB565 + ISP_COLOR_YUV422 = COLOR_TYPE_ID(COLOR_SPACE_YUV, COLOR_PIXEL_YUV422), ///< YUV422 + ISP_COLOR_YUV420 = COLOR_TYPE_ID(COLOR_SPACE_YUV, COLOR_PIXEL_YUV420), ///< YUV420 } isp_color_t; /*--------------------------------------------------------------- @@ -68,7 +68,6 @@ typedef struct { #endif } isp_af_result_t; - #ifdef __cplusplus } #endif diff --git a/components/hal/include/hal/lcd_types.h b/components/hal/include/hal/lcd_types.h index 019dd2852d..ebb112b803 100644 --- a/components/hal/include/hal/lcd_types.h +++ b/components/hal/include/hal/lcd_types.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -8,6 +8,7 @@ #include "soc/soc_caps.h" #include "soc/clk_tree_defs.h" +#include "hal/color_types.h" #ifdef __cplusplus extern "C" { @@ -20,19 +21,6 @@ extern "C" { typedef soc_periph_lcd_clk_src_t lcd_clock_source_t; #endif -/** - * @brief RGB color endian - */ -typedef enum { - LCD_RGB_ELEMENT_ORDER_RGB, /*!< RGB element order: RGB */ - LCD_RGB_ELEMENT_ORDER_BGR, /*!< RGB element order: BGR */ -} lcd_rgb_element_order_t; - -/// for backward compatible -typedef lcd_rgb_element_order_t lcd_color_rgb_endian_t; -#define LCD_RGB_ENDIAN_RGB LCD_RGB_ELEMENT_ORDER_RGB -#define LCD_RGB_ENDIAN_BGR LCD_RGB_ELEMENT_ORDER_BGR - /** * @brief RGB data endian */ @@ -45,33 +33,33 @@ typedef enum { * @brief LCD color space */ typedef enum { - LCD_COLOR_SPACE_RGB, /*!< Color space: RGB */ - LCD_COLOR_SPACE_YUV, /*!< Color space: YUV */ + LCD_COLOR_SPACE_RGB = COLOR_SPACE_RGB, /*!< Color space: RGB */ + LCD_COLOR_SPACE_YUV = COLOR_SPACE_YUV, /*!< Color space: YUV */ } lcd_color_space_t; /** * @brief LCD color range */ typedef enum { - LCD_COLOR_RANGE_LIMIT, /*!< Limited color range */ - LCD_COLOR_RANGE_FULL, /*!< Full color range */ + LCD_COLOR_RANGE_LIMIT = COLOR_RANGE_LIMIT, /*!< Limited color range */ + LCD_COLOR_RANGE_FULL = COLOR_RANGE_FULL, /*!< Full color range */ } lcd_color_range_t; /** * @brief YUV sampling method */ typedef enum { - LCD_YUV_SAMPLE_422, /*!< YUV 4:2:2 sampling */ - LCD_YUV_SAMPLE_420, /*!< YUV 4:2:0 sampling */ - LCD_YUV_SAMPLE_411, /*!< YUV 4:1:1 sampling */ + LCD_YUV_SAMPLE_422 = COLOR_PIXEL_YUV422, /*!< YUV 4:2:2 sampling */ + LCD_YUV_SAMPLE_420 = COLOR_PIXEL_YUV420, /*!< YUV 4:2:0 sampling */ + LCD_YUV_SAMPLE_411 = COLOR_PIXEL_YUV411, /*!< YUV 4:1:1 sampling */ } lcd_yuv_sample_t; /** * @brief The standard used for conversion between RGB and YUV */ typedef enum { - LCD_YUV_CONV_STD_BT601, /*!< YUV<->RGB conversion standard: BT.601 */ - LCD_YUV_CONV_STD_BT709, /*!< YUV<->RGB conversion standard: BT.709 */ + LCD_YUV_CONV_STD_BT601 = COLOR_CONV_STD_RGB_YUV_BT601, /*!< YUV<->RGB conversion standard: BT.601 */ + LCD_YUV_CONV_STD_BT709 = COLOR_CONV_STD_RGB_YUV_BT709, /*!< YUV<->RGB conversion standard: BT.709 */ } lcd_yuv_conv_std_t; #ifdef __cplusplus diff --git a/docs/doxygen/Doxyfile b/docs/doxygen/Doxyfile index 17c1707dbe..41f96611dc 100644 --- a/docs/doxygen/Doxyfile +++ b/docs/doxygen/Doxyfile @@ -174,6 +174,10 @@ INPUT = \ $(PROJECT_PATH)/components/esp_lcd/include/esp_lcd_panel_ops.h \ $(PROJECT_PATH)/components/esp_lcd/include/esp_lcd_panel_rgb.h \ $(PROJECT_PATH)/components/esp_lcd/include/esp_lcd_panel_vendor.h \ + $(PROJECT_PATH)/components/esp_lcd/include/esp_lcd_panel_dev.h \ + $(PROJECT_PATH)/components/esp_lcd/include/esp_lcd_panel_ssd1306.h \ + $(PROJECT_PATH)/components/esp_lcd/include/esp_lcd_panel_st7789.h \ + $(PROJECT_PATH)/components/esp_lcd/include/esp_lcd_panel_nt35510.h \ $(PROJECT_PATH)/components/esp_lcd/include/esp_lcd_types.h \ $(PROJECT_PATH)/components/esp_local_ctrl/include/esp_local_ctrl.h \ $(PROJECT_PATH)/components/esp_mm/include/esp_mmu_map.h \ @@ -229,6 +233,7 @@ INPUT = \ $(PROJECT_PATH)/components/freertos/FreeRTOS-Kernel/include/freertos/task.h \ $(PROJECT_PATH)/components/freertos/FreeRTOS-Kernel/include/freertos/timers.h \ $(PROJECT_PATH)/components/hal/include/hal/adc_types.h \ + $(PROJECT_PATH)/components/hal/include/hal/color_types.h \ $(PROJECT_PATH)/components/hal/include/hal/dac_types.h \ $(PROJECT_PATH)/components/hal/include/hal/esp_flash_err.h \ $(PROJECT_PATH)/components/hal/include/hal/gpio_types.h \ diff --git a/docs/en/api-reference/peripherals/lcd.rst b/docs/en/api-reference/peripherals/lcd.rst index 625f261e38..af9010639e 100644 --- a/docs/en/api-reference/peripherals/lcd.rst +++ b/docs/en/api-reference/peripherals/lcd.rst @@ -448,8 +448,8 @@ More LCD panel drivers and touch drivers are available in `ESP-IDF Component Reg .. _lcd_panel_operations: -LCD Panel IO Operations ------------------------ +LCD Panel Basic Operations +-------------------------- * :cpp:func:`esp_lcd_panel_reset` can reset the LCD panel. * :cpp:func:`esp_lcd_panel_init` performs a basic initialization of the panel. To perform more manufacture specific initialization, please go to :ref:`steps_add_manufacture_init`. @@ -463,7 +463,7 @@ LCD Panel IO Operations Steps to Add Manufacture Specific Initialization ------------------------------------------------- -The LCD controller drivers (e.g., st7789) in esp-idf only provide basic initialization in the :cpp:func:`esp_lcd_panel_init`, leaving the vast majority of settings to the default values. Some LCD modules needs to set a bunch of manufacture specific configurations before it can display normally. These configurations usually include gamma, power voltage and so on. If you want to add manufacture specific initialization, please follow the steps below: +The LCD controller drivers (e.g., st7789) in ESP-IDF only provide basic initialization in the :cpp:func:`esp_lcd_panel_init`, leaving the vast majority of settings to the default values. Some LCD modules needs to set a bunch of manufacture specific configurations before it can display normally. These configurations usually include gamma, power voltage and so on. If you want to add manufacture specific initialization, please follow the steps below: .. code:: c diff --git a/examples/peripherals/lcd/i2c_oled/main/Kconfig.projbuild b/examples/peripherals/lcd/i2c_oled/main/Kconfig.projbuild index 64101e6c43..f868a52184 100644 --- a/examples/peripherals/lcd/i2c_oled/main/Kconfig.projbuild +++ b/examples/peripherals/lcd/i2c_oled/main/Kconfig.projbuild @@ -13,4 +13,23 @@ menu "Example Configuration" bool "SH1107" endchoice + if EXAMPLE_LCD_CONTROLLER_SSD1306 + choice EXAMPLE_SSD1306_HEIGHT + prompt "SSD1306 Height in pixels" + default EXAMPLE_SSD1306_HEIGHT_64 + help + Height of the display in pixels. a.k.a vertical resolution + + config EXAMPLE_SSD1306_HEIGHT_64 + bool "64" + config EXAMPLE_SSD1306_HEIGHT_32 + bool "32" + endchoice + + config EXAMPLE_SSD1306_HEIGHT + int + default 64 if EXAMPLE_SSD1306_HEIGHT_64 + default 32 if EXAMPLE_SSD1306_HEIGHT_32 + endif + endmenu diff --git a/examples/peripherals/lcd/i2c_oled/main/i2c_oled_example_main.c b/examples/peripherals/lcd/i2c_oled/main/i2c_oled_example_main.c index b95a6f77b8..0ddc6e7a48 100644 --- a/examples/peripherals/lcd/i2c_oled/main/i2c_oled_example_main.c +++ b/examples/peripherals/lcd/i2c_oled/main/i2c_oled_example_main.c @@ -38,7 +38,7 @@ static const char *TAG = "example"; // The pixel number in horizontal and vertical #if CONFIG_EXAMPLE_LCD_CONTROLLER_SSD1306 #define EXAMPLE_LCD_H_RES 128 -#define EXAMPLE_LCD_V_RES 64 +#define EXAMPLE_LCD_V_RES CONFIG_EXAMPLE_SSD1306_HEIGHT #elif CONFIG_EXAMPLE_LCD_CONTROLLER_SH1107 #define EXAMPLE_LCD_H_RES 64 #define EXAMPLE_LCD_V_RES 128 @@ -49,16 +49,6 @@ static const char *TAG = "example"; extern void example_lvgl_demo_ui(lv_disp_t *disp); -/* The LVGL port component calls esp_lcd_panel_draw_bitmap API for send data to the screen. There must be called -lvgl_port_flush_ready(disp) after each transaction to display. The best way is to use on_color_trans_done -callback from esp_lcd IO config structure. In IDF 5.1 and higher, it is solved inside LVGL port component. */ -static bool notify_lvgl_flush_ready(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_io_event_data_t *edata, void *user_ctx) -{ - lv_disp_t * disp = (lv_disp_t *)user_ctx; - lvgl_port_flush_ready(disp); - return false; -} - void app_main(void) { ESP_LOGI(TAG, "Initialize I2C bus"); @@ -90,7 +80,7 @@ void app_main(void) } #endif }; - ESP_ERROR_CHECK(esp_lcd_new_panel_io_i2c((esp_lcd_i2c_bus_handle_t)I2C_HOST, &io_config, &io_handle)); + ESP_ERROR_CHECK(esp_lcd_new_panel_io_i2c(I2C_HOST, &io_config, &io_handle)); ESP_LOGI(TAG, "Install SSD1306 panel driver"); esp_lcd_panel_handle_t panel_handle = NULL; @@ -99,6 +89,10 @@ void app_main(void) .reset_gpio_num = EXAMPLE_PIN_NUM_RST, }; #if CONFIG_EXAMPLE_LCD_CONTROLLER_SSD1306 + esp_lcd_panel_ssd1306_config_t ssd1306_config = { + .height = EXAMPLE_LCD_V_RES, + }; + panel_config.vendor_config = &ssd1306_config; ESP_ERROR_CHECK(esp_lcd_new_panel_ssd1306(io_handle, &panel_config, &panel_handle)); #elif CONFIG_EXAMPLE_LCD_CONTROLLER_SH1107 ESP_ERROR_CHECK(esp_lcd_new_panel_sh1107(io_handle, &panel_config, &panel_handle)); @@ -131,11 +125,6 @@ void app_main(void) } }; lv_disp_t * disp = lvgl_port_add_disp(&disp_cfg); - /* Register done callback for IO */ - const esp_lcd_panel_io_callbacks_t cbs = { - .on_color_trans_done = notify_lvgl_flush_ready, - }; - esp_lcd_panel_io_register_event_callbacks(io_handle, &cbs, disp); /* Rotation of the screen */ lv_disp_set_rotation(disp, LV_DISP_ROT_NONE);