diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index feef098..0427b1b 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -1,3 +1,3 @@ idf_component_register(SRCS main.c lcd/lcd.c sd/sd.c lcd/ui.c lcd/ui_log.c lcd/ui_image_browser.c - PRIV_REQUIRES spi_flash esp_psram esp_lcd esp_driver_gpio esp_driver_i2c esp_driver_sdspi esp_driver_spi esp_lvgl_port esp_lcd_touch_gt911 fatfs sdmmc + PRIV_REQUIRES spi_flash esp_psram esp_lcd esp_driver_gpio esp_driver_i2c esp_driver_ledc esp_driver_sdspi esp_driver_spi esp_lvgl_port esp_lcd_touch_gt911 fatfs sdmmc INCLUDE_DIRS "." "include") diff --git a/main/include/lcd/lcd.h b/main/include/lcd/lcd.h index f25debd..f55863f 100644 --- a/main/include/lcd/lcd.h +++ b/main/include/lcd/lcd.h @@ -12,6 +12,7 @@ extern "C" { esp_err_t lcd_init(void); lv_display_t *lcd_get_display(void); +void lcd_backlight_set(uint8_t level); #ifdef __cplusplus } diff --git a/main/lcd/lcd.c b/main/lcd/lcd.c index 4705cc2..e1bff37 100644 --- a/main/lcd/lcd.c +++ b/main/lcd/lcd.c @@ -2,6 +2,7 @@ #include "driver/gpio.h" #include "driver/i2c_master.h" +#include "driver/ledc.h" #include "esp_check.h" #include "esp_idf_version.h" #include "esp_lcd_panel_io.h" @@ -27,6 +28,13 @@ #define LCD_GPIO_DISP (GPIO_NUM_NC) #define LCD_GPIO_BACKLIGHT (GPIO_NUM_2) #define LCD_BACKLIGHT_ON_LEVEL (1) +#define LCD_BACKLIGHT_LEDC_MODE (LEDC_LOW_SPEED_MODE) +#define LCD_BACKLIGHT_LEDC_TIMER (LEDC_TIMER_0) +#define LCD_BACKLIGHT_LEDC_CHANNEL (LEDC_CHANNEL_0) +#define LCD_BACKLIGHT_LEDC_RESOLUTION (LEDC_TIMER_8_BIT) +#define LCD_BACKLIGHT_LEDC_DUTY_MAX ((1 << 8) - 1) +#define LCD_BACKLIGHT_LEDC_FREQ_HZ (5000) +#define LCD_BACKLIGHT_FADE_MS (150) #define LCD_GPIO_DATA0 (GPIO_NUM_8) #define LCD_GPIO_DATA1 (GPIO_NUM_3) #define LCD_GPIO_DATA2 (GPIO_NUM_46) @@ -72,14 +80,28 @@ static lv_display_t *lvgl_display; static lv_indev_t *lvgl_touch_indev; static esp_err_t init_backlight(void){ - const gpio_config_t backlight_config = { - .mode = GPIO_MODE_OUTPUT, - .pin_bit_mask = 1ULL << LCD_GPIO_BACKLIGHT, + const ledc_timer_config_t timer_config = { + .speed_mode = LCD_BACKLIGHT_LEDC_MODE, + .timer_num = LCD_BACKLIGHT_LEDC_TIMER, + .duty_resolution = LCD_BACKLIGHT_LEDC_RESOLUTION, + .freq_hz = LCD_BACKLIGHT_LEDC_FREQ_HZ, + .clk_cfg = LEDC_AUTO_CLK, }; - ESP_RETURN_ON_ERROR(gpio_config(&backlight_config), TAG, "Backlight GPIO config failed"); - ESP_RETURN_ON_ERROR(gpio_set_level(LCD_GPIO_BACKLIGHT, LCD_BACKLIGHT_ON_LEVEL), TAG, "Backlight GPIO set failed"); - ESP_LOGI(TAG, "Backlight enabled on GPIO%d", LCD_GPIO_BACKLIGHT); - return ESP_OK; + ESP_RETURN_ON_ERROR(ledc_timer_config(&timer_config), TAG, "Backlight LEDC timer config failed"); + + const ledc_channel_config_t channel_config = { + .gpio_num = LCD_GPIO_BACKLIGHT, + .speed_mode = LCD_BACKLIGHT_LEDC_MODE, + .channel = LCD_BACKLIGHT_LEDC_CHANNEL, + .timer_sel = LCD_BACKLIGHT_LEDC_TIMER, + .intr_type = LEDC_INTR_DISABLE, + .duty = (LCD_BACKLIGHT_ON_LEVEL != 0) ? LCD_BACKLIGHT_LEDC_DUTY_MAX : 0, + .hpoint = 0, + }; + ESP_RETURN_ON_ERROR(ledc_channel_config(&channel_config), TAG, "Backlight LEDC channel config failed"); + ESP_RETURN_ON_ERROR(ledc_fade_func_install(0), TAG, "Backlight LEDC fade install failed"); + ESP_LOGI(TAG, "Backlight PWM enabled on GPIO%d", LCD_GPIO_BACKLIGHT); + return ESP_OK; } static esp_err_t probe_gt911_address(i2c_master_bus_handle_t i2c_handle, uint32_t *dev_addr){ @@ -272,6 +294,15 @@ static esp_err_t init_lvgl(void){ return ESP_OK; } +void lcd_backlight_set(uint8_t level){ + const uint32_t duty = (LCD_BACKLIGHT_ON_LEVEL != 0) ? level : (LCD_BACKLIGHT_LEDC_DUTY_MAX - level); + esp_err_t err = ledc_set_fade_with_time(LCD_BACKLIGHT_LEDC_MODE, LCD_BACKLIGHT_LEDC_CHANNEL, duty, LCD_BACKLIGHT_FADE_MS); + if(err == ESP_OK){ + err = ledc_fade_start(LCD_BACKLIGHT_LEDC_MODE, LCD_BACKLIGHT_LEDC_CHANNEL, LEDC_FADE_WAIT_DONE); + } + if(err != ESP_OK) ESP_LOGW(TAG, "Backlight set failed: %s", esp_err_to_name(err)); +} + esp_err_t lcd_init(void){ ESP_RETURN_ON_ERROR(init_rgb_panel(), TAG, "LCD panel init failed"); const esp_err_t touch_ret = init_touch(); diff --git a/main/lcd/ui_image_browser.c b/main/lcd/ui_image_browser.c index 69a470e..a993282 100644 --- a/main/lcd/ui_image_browser.c +++ b/main/lcd/ui_image_browser.c @@ -15,6 +15,7 @@ #include "lcd/ui_internal.h" #include "lcd/ui_log.h" #include "sd/sd.h" +#include "lcd/lcd.h" #define UI_IMAGE_PATH_PREFIX "A:/sdcard/" #define UI_IMAGE_PATH_MAX_LENGTH 160 @@ -349,6 +350,7 @@ static bool ui_image_browser_display_prefetched(void){ /* Warm up the next image so the following switch is instant too. */ ui_prefetch_next(index, slot); + return true; } @@ -395,11 +397,22 @@ static void ui_image_browser_load_via_path(void){ static void ui_image_browser_display_current(void){ if(image_widget == NULL || image_browser_names == NULL || image_browser_image_count == 0) return; - if(ui_image_browser_display_prefetched()) return; + ESP_LOGI(TAG, "Backlight sweep: turning off backlight"); + ui_log_append("Backlight sweep: turning off backlight"); + lcd_backlight_set(0); + + if(ui_image_browser_display_prefetched()) goto done; + ESP_LOGW(TAG, "Prefetched image unavailable: falling back to on-demand decoding"); + ui_log_append("Prefetched image unavailable: falling back to on-demand decoding"); /* Prefetch unavailable or render failed: fall back to on-demand decoding. */ visible_slot = -1; ui_image_browser_load_via_path(); + + done: + ESP_LOGI(TAG, "Backlight sweep: turning on backlight"); + ui_log_append("Backlight sweep: turning on backlight"); + lcd_backlight_set(255); } void ui_image_browser_build_view(lv_obj_t *screen){ diff --git a/sdkconfig b/sdkconfig index e12f6fb..b068acc 100644 --- a/sdkconfig +++ b/sdkconfig @@ -1165,6 +1165,13 @@ CONFIG_I2C_MASTER_ISR_HANDLER_IN_IRAM=y # CONFIG_I2S_ENABLE_DEBUG_LOG is not set # end of ESP-Driver:I2S Configurations +# +# ESP-Driver:LEDC Configurations +# +# default: +# CONFIG_LEDC_CTRL_FUNC_IN_IRAM is not set +# end of ESP-Driver:LEDC Configurations + # # ESP-Driver:SD Host SDMMC Controller Configurations #