From fa042b0ecd1b555829d903aa734b957ce435dc09 Mon Sep 17 00:00:00 2001 From: Tomas Rezucha Date: Tue, 3 Aug 2021 08:59:59 +0200 Subject: [PATCH] Carve out backlight control to separate component --- CMakeLists.txt | 8 +-- lvgl_tft/Kconfig | 116 +++++++++++++++++++-------------- lvgl_tft/disp_driver.c | 32 +++++++++- lvgl_tft/disp_driver.h | 2 +- lvgl_tft/esp_lcd_backlight.c | 120 ++++++++++++++++++++++++----------- lvgl_tft/esp_lcd_backlight.h | 57 +++++++++++++---- 6 files changed, 227 insertions(+), 108 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2dbc2f7..78870dd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,8 +3,7 @@ if(ESP_PLATFORM) file(GLOB SOURCES *.c) set(LVGL_INCLUDE_DIRS . lvgl_tft) list(APPEND SOURCES "lvgl_tft/disp_driver.c") - -#@todo add SimleInclude macro here +list(APPEND SOURCES "lvgl_tft/esp_lcd_backlight.c") # Include only the source file of the selected # display controller. @@ -79,11 +78,6 @@ if(CONFIG_LV_TOUCH_CONTROLLER) endif() endif() -# Add backlight control to compilation only if it is selected in menuconfig -if(CONFIG_LV_ENABLE_BACKLIGHT_CONTROL) - list(APPEND SOURCES "lvgl_tft/esp_lcd_backlight.c") -endif() - if(CONFIG_LV_I2C) list(APPEND SOURCES "lvgl_i2c/i2c_manager.c") endif() diff --git a/lvgl_tft/Kconfig b/lvgl_tft/Kconfig index 593b948..7b94d46 100644 --- a/lvgl_tft/Kconfig +++ b/lvgl_tft/Kconfig @@ -910,51 +910,6 @@ menu "LVGL TFT Display controller" help Configure the display Busy pin here. - config LV_ENABLE_BACKLIGHT_CONTROL - bool "Enable control of the display backlight by using an GPIO." if \ - ( LV_PREDEFINED_DISPLAY_NONE && ! ( LV_TFT_DISPLAY_CONTROLLER_SH1107 || LV_TFT_DISPLAY_CONTROLLER_SSD1306 ) ) \ - || LV_PREDEFINED_DISPLAY_RPI_MPI3501 - default y if LV_PREDEFINED_DISPLAY_M5STACK - default n if LV_PREDEFINED_DISPLAY_M5CORE2 - default y if LV_PREDEFINED_DISPLAY_WROVER4 - default y if LV_PREDEFINED_DISPLAY_ERTFT0356 - default y if LV_PREDEFINED_DISPLAY_TTGO - default y if LV_PREDEFINED_DISPLAY_TTGO_CAMERA_PLUS - default y if LV_PREDEFINED_DISPLAY_WT32_SC01 - help - Enable controlling the display backlight using an GPIO - - config LV_BACKLIGHT_ACTIVE_LVL - bool "Is backlight turn on with a HIGH (1) logic level?" - depends on LV_ENABLE_BACKLIGHT_CONTROL - default y if LV_PREDEFINED_DISPLAY_M5STACK - default y if LV_PREDEFINED_DISPLAY_ERTFT0356 - default y if LV_PREDEFINED_DISPLAY_TTGO - default y if LV_PREDEFINED_DISPLAY_TTGO_CAMERA_PLUS - default y if LV_PREDEFINED_DISPLAY_WT32_SC01 - help - Some backlights are turned on with a high signal, others held low. - If enabled, a value of 1 will be sent to the display to enable the backlight, - otherwise a 0 will be expected to enable it. - - config LV_DISP_PIN_BCKL - int "GPIO for Backlight Control" - depends on LV_ENABLE_BACKLIGHT_CONTROL - default 23 if LV_PREDEFINED_PINS_38V1 - default 26 if LV_PREDEFINED_PINS_38V4 - default 32 if LV_PREDEFINED_DISPLAY_M5STACK - default 5 if LV_PREDEFINED_DISPLAY_WROVER4 - default 2 if LV_PREDEFINED_DISPLAY_ADA_FEATHERWING - default 27 if LV_PREDEFINED_DISPLAY_ERTFT0356 - default 0 if LV_PREDEFINED_PINS_TKOALA - default 4 if LV_PREDEFINED_DISPLAY_TTGO - default 2 if LV_PREDEFINED_DISPLAY_TTGO_CAMERA_PLUS - default 23 if LV_PREDEFINED_DISPLAY_WT32_SC01 - default 27 - - help - Configure the display BCLK (LED) pin here. - endmenu choice @@ -965,19 +920,86 @@ menu "LVGL TFT Display controller" config LV_I2C_DISPLAY_PORT_0 bool prompt "I2C port 0" - help + help I2C is shared peripheral managed by I2C Manager. In order to configure I2C Manager (pinout, etc.) see menu Component config->I2C Port Settings. config LV_I2C_DISPLAY_PORT_1 bool prompt "I2C port 1" - help + help I2C is shared peripheral managed by I2C Manager. In order to configure I2C Manager (pinout, etc.) see menu Component config->I2C Port Settings. endchoice + choice + prompt "Backlight Control" if \ + (! ( LV_TFT_DISPLAY_CONTROLLER_SH1107 || LV_TFT_DISPLAY_CONTROLLER_SSD1306 ) ) + default LV_DISP_BACKLIGHT_SWITCH if LV_PREDEFINED_DISPLAY_M5STACK + default LV_DISP_BACKLIGHT_OFF if LV_PREDEFINED_DISPLAY_M5CORE2 + default LV_DISP_BACKLIGHT_SWITCH if LV_PREDEFINED_DISPLAY_WROVER4 + default LV_DISP_BACKLIGHT_SWITCH if LV_PREDEFINED_DISPLAY_ERTFT0356 + default LV_DISP_BACKLIGHT_SWITCH if LV_PREDEFINED_DISPLAY_TTGO + default LV_DISP_BACKLIGHT_SWITCH if LV_PREDEFINED_DISPLAY_TTGO_CAMERA_PLUS + default LV_DISP_BACKLIGHT_SWITCH if LV_PREDEFINED_DISPLAY_WT32_SC01 + default LV_DISP_BACKLIGHT_OFF + + config LV_DISP_BACKLIGHT_OFF + bool + prompt "Not Used" + help + Display backlight is not controlled by this driver, must be hardwired in hardware. + + config LV_DISP_BACKLIGHT_SWITCH + bool + prompt "Switch control" + help + Display backlight can be switched on or off. + + config LV_DISP_BACKLIGHT_PWM + bool + prompt "PWM control" + help + Display backlight is controlled by pulse-width modulation, allowing brightness settings. + + endchoice + + config LV_BACKLIGHT_ACTIVE_LVL + bool "Is backlight turn on with a HIGH (1) logic level?" if \ + ( LV_PREDEFINED_DISPLAY_NONE && ! ( LV_TFT_DISPLAY_CONTROLLER_SH1107 || LV_TFT_DISPLAY_CONTROLLER_SSD1306 ) ) \ + || LV_PREDEFINED_DISPLAY_RPI_MPI3501 + depends on !LV_DISP_BACKLIGHT_OFF + default y if LV_PREDEFINED_DISPLAY_M5STACK + default y if LV_PREDEFINED_DISPLAY_ERTFT0356 + default y if LV_PREDEFINED_DISPLAY_TTGO + default y if LV_PREDEFINED_DISPLAY_TTGO_CAMERA_PLUS + default y if LV_PREDEFINED_DISPLAY_WT32_SC01 + help + Some backlights are turned on with a high signal, others held low. + If enabled, a value of 1 will be sent to the display to enable the backlight, + otherwise a 0 will be expected to enable it. + + config LV_DISP_PIN_BCKL + int "GPIO for Backlight Control" if \ + ( LV_PREDEFINED_DISPLAY_NONE && ! ( LV_TFT_DISPLAY_CONTROLLER_SH1107 || LV_TFT_DISPLAY_CONTROLLER_SSD1306 ) ) \ + || LV_PREDEFINED_DISPLAY_RPI_MPI3501 + depends on !LV_DISP_BACKLIGHT_OFF + default 23 if LV_PREDEFINED_PINS_38V1 + default 26 if LV_PREDEFINED_PINS_38V4 + default 32 if LV_PREDEFINED_DISPLAY_M5STACK + default 5 if LV_PREDEFINED_DISPLAY_WROVER4 + default 2 if LV_PREDEFINED_DISPLAY_ADA_FEATHERWING + default 27 if LV_PREDEFINED_DISPLAY_ERTFT0356 + default 0 if LV_PREDEFINED_PINS_TKOALA + default 4 if LV_PREDEFINED_DISPLAY_TTGO + default 2 if LV_PREDEFINED_DISPLAY_TTGO_CAMERA_PLUS + default 23 if LV_PREDEFINED_DISPLAY_WT32_SC01 + default 27 + + help + Configure the display BCLK (LED) pin here. + config LV_I2C bool default y if LV_I2C_DISPLAY diff --git a/lvgl_tft/disp_driver.c b/lvgl_tft/disp_driver.c index adae2ad..0d77155 100644 --- a/lvgl_tft/disp_driver.c +++ b/lvgl_tft/disp_driver.c @@ -4,8 +4,10 @@ #include "disp_driver.h" #include "disp_spi.h" +#include "esp_lcd_backlight.h" +#include "sdkconfig.h" -void disp_driver_init(void) +void *disp_driver_init(void) { #if defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_ILI9341 ili9341_init(); @@ -42,6 +44,34 @@ void disp_driver_init(void) #elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_ILI9163C ili9163c_init(); #endif + + // We still use menuconfig for these settings + // It will be set up during runtime in the future +#ifndef CONFIG_LV_DISP_BACKLIGHT_OFF + const disp_backlight_config_t bckl_config = { + .gpio_num = CONFIG_LV_DISP_PIN_BCKL, +#if defined CONFIG_LV_DISP_BACKLIGHT_PWM + .pwm_control = true, +#else + .pwm_control = false, +#endif +#if defined CONFIG_LV_BACKLIGHT_ACTIVE_LVL + .output_invert = false, // Backlight on high +#else + .output_invert = true, // Backlight on low +#endif + .timer_idx = 0, + .channel_idx = 0 // @todo this prevents us from having two PWM controlled displays + }; + const disp_backlight_config_t *bckl_config_p = &bckl_config; +#else + const disp_backlight_config_t *bckl_config_p = NULL; +#endif + + disp_backlight_h bckl_handle = disp_backlight_new(bckl_config_p); + disp_backlight_set(bckl_handle, 100); + + return bckl_handle; } void disp_driver_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * color_map) diff --git a/lvgl_tft/disp_driver.h b/lvgl_tft/disp_driver.h index 2e369cc..8c70fda 100644 --- a/lvgl_tft/disp_driver.h +++ b/lvgl_tft/disp_driver.h @@ -67,7 +67,7 @@ extern "C" { **********************/ /* Initialize display */ -void disp_driver_init(void); +void *disp_driver_init(void); /* Display flush callback */ void disp_driver_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * color_map); diff --git a/lvgl_tft/esp_lcd_backlight.c b/lvgl_tft/esp_lcd_backlight.c index e4bf930..d8724e6 100644 --- a/lvgl_tft/esp_lcd_backlight.c +++ b/lvgl_tft/esp_lcd_backlight.c @@ -8,51 +8,95 @@ *********************/ #include "esp_lcd_backlight.h" #include "driver/ledc.h" +#include "driver/gpio.h" #include "esp_log.h" +#include "esp_rom_gpio.h" // for output signal inversion -static const char *TAG = "disp_brightness"; +typedef struct { + bool pwm_control; // true: LEDC is used, false: GPIO is used + int index; // Either GPIO or LEDC channel +} disp_backlight_t; -void disp_brightness_control_enable(void) +static const char *TAG = "disp_backlight"; + +disp_backlight_h disp_backlight_new(const disp_backlight_config_t *config) { - /* - Configure LED (Backlight) pin as PWM for Brightness control. - */ - ledc_channel_config_t LCD_backlight_channel = { - .gpio_num = DISP_PIN_BCKL, - .speed_mode = LEDC_LOW_SPEED_MODE, - .channel = LEDC_CHANNEL_0, - .intr_type = LEDC_INTR_DISABLE, - .timer_sel = LEDC_TIMER_0, - .duty = 0, - .hpoint = 0, - .flags.output_invert = 0 - }; - ledc_timer_config_t LCD_backlight_timer = { - .speed_mode = LEDC_LOW_SPEED_MODE, - .bit_num = LEDC_TIMER_10_BIT, - .timer_num = LEDC_TIMER_0, - .freq_hz = 5000, - .clk_cfg = LEDC_AUTO_CLK - }; + if (config == NULL) + return NULL; + disp_backlight_t *bckl_dev = calloc(1, sizeof(disp_backlight_t)); + if (bckl_dev == NULL){ + ESP_LOGW(TAG, "Could not create new LCD backlight instance"); + return NULL; + } - ESP_ERROR_CHECK( ledc_timer_config(&LCD_backlight_timer) ); - ESP_ERROR_CHECK( ledc_channel_config(&LCD_backlight_channel) ); + if (config->pwm_control){ + // Configure LED (Backlight) pin as PWM for Brightness control. + bckl_dev->pwm_control = true; + bckl_dev->index = config->channel_idx; + const ledc_channel_config_t LCD_backlight_channel = { + .gpio_num = config->gpio_num, + .speed_mode = LEDC_LOW_SPEED_MODE, + .channel = config->channel_idx, + .intr_type = LEDC_INTR_DISABLE, + .timer_sel = config->timer_idx, + .duty = 0, + .hpoint = 0, + .flags.output_invert = config->output_invert //@todo added only in recent IDF versions + }; + const ledc_timer_config_t LCD_backlight_timer = { + .speed_mode = LEDC_LOW_SPEED_MODE, + .bit_num = LEDC_TIMER_10_BIT, + .timer_num = config->timer_idx, + .freq_hz = 5000, + .clk_cfg = LEDC_AUTO_CLK}; + ESP_ERROR_CHECK(ledc_timer_config(&LCD_backlight_timer)); + ESP_ERROR_CHECK(ledc_channel_config(&LCD_backlight_channel)); + } + else + { + // Configure GPIO for output + bckl_dev->index = config->gpio_num; + gpio_pad_select_gpio(config->gpio_num); + ESP_ERROR_CHECK(gpio_set_direction(config->gpio_num, GPIO_MODE_OUTPUT)); + esp_rom_gpio_connect_out_signal(config->gpio_num, SIG_GPIO_OUT_IDX, config->output_invert, false); + } + + return (disp_backlight_h)bckl_dev; } -void disp_set_brightness(uint16_t brightness) +void disp_backlight_set(disp_backlight_h bckl, int brightness_percent) { - /* - Set brightness. - 0 -> Display off - 100 -> Full brightness - NOTE: brightness value must be between 0 - 100 - */ - if(brightness > 100) - { - ESP_LOGE(TAG, "Brightness value must be between 0 - 100"); - return; - } - ESP_ERROR_CHECK( ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, brightness*10) ); - ESP_ERROR_CHECK( ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0) ); + // Check input paramters + if (bckl == NULL) + return; + if (brightness_percent > 100) + brightness_percent = 100; + if (brightness_percent < 0) + brightness_percent = 0; + + disp_backlight_t *bckl_dev = (disp_backlight_t *) bckl; + ESP_LOGI(TAG, "Setting LCD backlight: %d%%", brightness_percent); + + if (bckl_dev->pwm_control) { + uint32_t duty_cycle = (1023 * brightness_percent) / 100; // LEDC resolution set to 10bits, thus: 100% = 1023 + ESP_ERROR_CHECK(ledc_set_duty(LEDC_LOW_SPEED_MODE, bckl_dev->index, duty_cycle)); + ESP_ERROR_CHECK(ledc_update_duty(LEDC_LOW_SPEED_MODE, bckl_dev->index)); + } else { + ESP_ERROR_CHECK(gpio_set_level(bckl_dev->index, brightness_percent)); + } +} + +void disp_backlight_delete(disp_backlight_h bckl) +{ + if (bckl == NULL) + return; + + disp_backlight_t *bckl_dev = (disp_backlight_t *) bckl; + if (bckl_dev->pwm_control) { + ledc_stop(LEDC_LOW_SPEED_MODE, bckl_dev->index, 0); + } else { + gpio_reset_pin(bckl_dev->index); + } + free (bckl); } diff --git a/lvgl_tft/esp_lcd_backlight.h b/lvgl_tft/esp_lcd_backlight.h index b22bf9d..a04817b 100644 --- a/lvgl_tft/esp_lcd_backlight.h +++ b/lvgl_tft/esp_lcd_backlight.h @@ -9,29 +9,58 @@ * INCLUDES *********************/ #include -#ifdef LV_LVGL_H_INCLUDE_SIMPLE -#include "lvgl.h" -#else -#include "lvgl/lvgl.h" -#endif - -/********************* - * DEFINES - *********************/ -#if CONFIG_LV_ENABLE_BACKLIGHT_CONTROL -#define DISP_PIN_BCKL CONFIG_LV_DISP_PIN_BCKL +#ifdef __cplusplus +extern "C" { /* extern "C" */ #endif /********************** * GLOBAL PROTOTYPES **********************/ -void disp_brightness_control_enable(void); -void disp_set_brightness(uint16_t brightness); +/** + * @brief Display backlight controller handle + * + */ +typedef void * disp_backlight_h; + +/** + * @brief Configuration structure of backlight controller + * + */ +typedef struct { + bool pwm_control; + bool output_invert; + int gpio_num; // see gpio_num_t + + // Relevant only for PWM controlled backlight + // Ignored for switch (ON/OFF) backlight control + int timer_idx; // ledc_timer_t + int channel_idx; // ledc_channel_t +} disp_backlight_config_t; + +/** + * @brief Create new backlight controller + * + * @param[in] config Configuration structure of backlight controller + * @return Display backlight controller handle + */ +disp_backlight_h disp_backlight_new(const disp_backlight_config_t *config); + +/** + * @brief Set backlight + * + * Brightness parameter can be 0-100 for PWM controlled backlight. + * GPIO controlled backlight (ON/OFF) is turned off witch value 0 and turned on with any positive value. + * + * @param bckl Backlight controller handle + * @param[in] brightness_percent Brightness in [%] + */ +void disp_backlight_set(disp_backlight_h bckl, int brightness_percent); +void disp_backlight_delete(disp_backlight_h bckl); #ifdef __cplusplus } /* extern "C" */ #endif -#endif /*ESP_LCD_BACKLIGHT_H*/ \ No newline at end of file +#endif /*ESP_LCD_BACKLIGHT_H*/