feat(platform): add PWM backlight brightness control
This commit is contained in:
@@ -36,6 +36,7 @@ set(platform_priv_requires
|
||||
esp_driver_gpio
|
||||
esp_driver_i2c
|
||||
esp_driver_i2s
|
||||
esp_driver_ledc
|
||||
esp_driver_rmt
|
||||
esp_driver_spi
|
||||
esp_event
|
||||
|
||||
@@ -452,6 +452,15 @@ esp_err_t platform_multimodal_audio_register_downstream_playback_callbacks(
|
||||
|
||||
esp_err_t platform_init_lcd_device(void);
|
||||
|
||||
/**
|
||||
* @brief Set LCD backlight brightness using PWM.
|
||||
*
|
||||
* @param brightness_percent Brightness from 0 (off) to 100 (full).
|
||||
* @return ESP_OK on success, ESP_ERR_INVALID_ARG outside the supported range,
|
||||
* or ESP_ERR_INVALID_STATE before LCD initialization.
|
||||
*/
|
||||
esp_err_t platform_lcd_set_backlight_brightness(uint8_t brightness_percent);
|
||||
|
||||
/**
|
||||
* @brief Start LCD render loop.
|
||||
*
|
||||
|
||||
@@ -10,6 +10,7 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
esp_err_t lcd_direct_init_device(void);
|
||||
esp_err_t lcd_direct_set_backlight_brightness(uint8_t brightness_percent);
|
||||
void lcd_direct_start_render_loop(void);
|
||||
esp_err_t lcd_direct_stop_render_loop(int timeout_ms);
|
||||
esp_err_t lcd_direct_set_status_overlay(const platform_lcd_status_overlay_t *overlay);
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <unistd.h>
|
||||
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/ledc.h"
|
||||
#include "driver/spi_master.h"
|
||||
#include "esp_attr.h"
|
||||
#include "esp_check.h"
|
||||
@@ -58,6 +59,12 @@
|
||||
#define LCD_DIRECT_LAST_FRAME_EXTRA_HOLD_MS 200U
|
||||
#define LCD_DIRECT_BASIC_FACE_FRAME_HOLD_MS 100U
|
||||
#define LCD_DIRECT_BASIC_FACE_LAST_FRAME_HOLD_MS 100U
|
||||
#define LCD_DIRECT_BACKLIGHT_PWM_FREQUENCY_HZ 20000U
|
||||
#define LCD_DIRECT_BACKLIGHT_PWM_DUTY_RESOLUTION LEDC_TIMER_10_BIT
|
||||
#define LCD_DIRECT_BACKLIGHT_PWM_DUTY_MAX ((1U << 10U) - 1U)
|
||||
#define LCD_DIRECT_BACKLIGHT_PWM_TIMER LEDC_TIMER_0
|
||||
#define LCD_DIRECT_BACKLIGHT_PWM_CHANNEL LEDC_CHANNEL_0
|
||||
#define LCD_DIRECT_BACKLIGHT_LOCK_TIMEOUT_MS 100U
|
||||
|
||||
#define LCD_CMD_MADCTL 0x36
|
||||
#define LCD_CMD_RAMCTRL 0xB0
|
||||
@@ -133,6 +140,7 @@ static const lcd_direct_init_cmd_t s_st7789_init_cmds[] = {
|
||||
static esp_lcd_panel_io_handle_t s_panel_io;
|
||||
static esp_lcd_panel_handle_t s_panel;
|
||||
static SemaphoreHandle_t s_lock;
|
||||
static SemaphoreHandle_t s_backlight_lock;
|
||||
static SemaphoreHandle_t s_completion_sem;
|
||||
static SemaphoreHandle_t s_preheat_done_sem;
|
||||
static SemaphoreHandle_t s_transfer_done_sem;
|
||||
@@ -465,10 +473,49 @@ static esp_err_t lcd_direct_get_png_image(const char *path,
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static uint32_t lcd_direct_backlight_duty(uint8_t brightness_percent)
|
||||
{
|
||||
uint32_t duty = ((uint32_t)brightness_percent * LCD_DIRECT_BACKLIGHT_PWM_DUTY_MAX + 50U) / 100U;
|
||||
#if !CONFIG_TQ_SCREEN_BACKLIGHT_ACTIVE_HIGH
|
||||
duty = LCD_DIRECT_BACKLIGHT_PWM_DUTY_MAX - duty;
|
||||
#endif
|
||||
return duty;
|
||||
}
|
||||
|
||||
static esp_err_t lcd_direct_backlight_init(void)
|
||||
{
|
||||
const ledc_timer_config_t timer_config = {
|
||||
.speed_mode = LEDC_LOW_SPEED_MODE,
|
||||
.duty_resolution = LCD_DIRECT_BACKLIGHT_PWM_DUTY_RESOLUTION,
|
||||
.timer_num = LCD_DIRECT_BACKLIGHT_PWM_TIMER,
|
||||
.freq_hz = LCD_DIRECT_BACKLIGHT_PWM_FREQUENCY_HZ,
|
||||
.clk_cfg = LEDC_AUTO_CLK,
|
||||
};
|
||||
ESP_RETURN_ON_ERROR(ledc_timer_config(&timer_config), TAG, "backlight PWM timer config failed");
|
||||
|
||||
const ledc_channel_config_t channel_config = {
|
||||
.gpio_num = CONFIG_TQ_SCREEN_BACKLIGHT_GPIO,
|
||||
.speed_mode = LEDC_LOW_SPEED_MODE,
|
||||
.channel = LCD_DIRECT_BACKLIGHT_PWM_CHANNEL,
|
||||
.intr_type = LEDC_INTR_DISABLE,
|
||||
.timer_sel = LCD_DIRECT_BACKLIGHT_PWM_TIMER,
|
||||
.duty = lcd_direct_backlight_duty(CONFIG_TQ_SCREEN_BACKLIGHT_BRIGHTNESS_PERCENT),
|
||||
.hpoint = 0,
|
||||
};
|
||||
ESP_RETURN_ON_ERROR(ledc_channel_config(&channel_config), TAG, "backlight PWM channel config failed");
|
||||
|
||||
ESP_LOGI(TAG,
|
||||
"Backlight PWM initialized gpio=%d frequency=%uHz brightness=%d%% active_high=%d",
|
||||
CONFIG_TQ_SCREEN_BACKLIGHT_GPIO,
|
||||
(unsigned)LCD_DIRECT_BACKLIGHT_PWM_FREQUENCY_HZ,
|
||||
CONFIG_TQ_SCREEN_BACKLIGHT_BRIGHTNESS_PERCENT,
|
||||
CONFIG_TQ_SCREEN_BACKLIGHT_ACTIVE_HIGH ? 1 : 0);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t lcd_direct_gpio_init(void)
|
||||
{
|
||||
uint64_t pin_mask = (1ULL << CONFIG_TQ_SCREEN_BACKLIGHT_GPIO) |
|
||||
(1ULL << CONFIG_TQ_SCREEN_DC_GPIO);
|
||||
uint64_t pin_mask = (1ULL << CONFIG_TQ_SCREEN_DC_GPIO);
|
||||
if (CONFIG_TQ_SCREEN_RESET_PIN >= 0) {
|
||||
pin_mask |= (1ULL << CONFIG_TQ_SCREEN_RESET_PIN);
|
||||
}
|
||||
@@ -482,13 +529,11 @@ static esp_err_t lcd_direct_gpio_init(void)
|
||||
};
|
||||
ESP_RETURN_ON_ERROR(gpio_config(&gpio_config_data), TAG, "gpio config failed");
|
||||
|
||||
gpio_set_level(CONFIG_TQ_SCREEN_BACKLIGHT_GPIO,
|
||||
CONFIG_TQ_SCREEN_BACKLIGHT_ACTIVE_HIGH ? 1 : 0);
|
||||
gpio_set_level(CONFIG_TQ_SCREEN_DC_GPIO, 0);
|
||||
if (CONFIG_TQ_SCREEN_RESET_PIN >= 0) {
|
||||
gpio_set_level(CONFIG_TQ_SCREEN_RESET_PIN, 1);
|
||||
}
|
||||
return ESP_OK;
|
||||
return lcd_direct_backlight_init();
|
||||
}
|
||||
|
||||
static esp_err_t lcd_direct_panel_init(void)
|
||||
@@ -1301,6 +1346,11 @@ esp_err_t lcd_direct_init_device(void)
|
||||
|
||||
s_lock = xSemaphoreCreateMutex();
|
||||
ESP_RETURN_ON_FALSE(s_lock != NULL, ESP_ERR_NO_MEM, TAG, "lock create failed");
|
||||
s_backlight_lock = xSemaphoreCreateMutex();
|
||||
ESP_RETURN_ON_FALSE(s_backlight_lock != NULL,
|
||||
ESP_ERR_NO_MEM,
|
||||
TAG,
|
||||
"backlight lock create failed");
|
||||
s_completion_sem = xSemaphoreCreateBinary();
|
||||
ESP_RETURN_ON_FALSE(s_completion_sem != NULL, ESP_ERR_NO_MEM, TAG, "completion sem create failed");
|
||||
s_preheat_done_sem = xSemaphoreCreateBinary();
|
||||
@@ -1331,6 +1381,38 @@ esp_err_t lcd_direct_init_device(void)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t lcd_direct_set_backlight_brightness(uint8_t brightness_percent)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(brightness_percent <= 100U,
|
||||
ESP_ERR_INVALID_ARG,
|
||||
TAG,
|
||||
"backlight brightness must be between 0 and 100 percent");
|
||||
ESP_RETURN_ON_FALSE(s_initialized && s_backlight_lock != NULL,
|
||||
ESP_ERR_INVALID_STATE,
|
||||
TAG,
|
||||
"LCD backlight is not initialized");
|
||||
ESP_RETURN_ON_FALSE(xSemaphoreTake(s_backlight_lock,
|
||||
pdMS_TO_TICKS(LCD_DIRECT_BACKLIGHT_LOCK_TIMEOUT_MS)) == pdTRUE,
|
||||
ESP_ERR_TIMEOUT,
|
||||
TAG,
|
||||
"backlight lock timed out");
|
||||
|
||||
esp_err_t err = ledc_set_duty(LEDC_LOW_SPEED_MODE,
|
||||
LCD_DIRECT_BACKLIGHT_PWM_CHANNEL,
|
||||
lcd_direct_backlight_duty(brightness_percent));
|
||||
if (err == ESP_OK) {
|
||||
err = ledc_update_duty(LEDC_LOW_SPEED_MODE, LCD_DIRECT_BACKLIGHT_PWM_CHANNEL);
|
||||
}
|
||||
xSemaphoreGive(s_backlight_lock);
|
||||
|
||||
if (err == ESP_OK) {
|
||||
ESP_LOGI(TAG, "Backlight brightness set to %u%%", (unsigned)brightness_percent);
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Backlight brightness update failed: %s", esp_err_to_name(err));
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
void lcd_direct_start_render_loop(void)
|
||||
{
|
||||
if (!s_initialized) {
|
||||
|
||||
@@ -12,6 +12,11 @@ esp_err_t platform_init_lcd_device(void)
|
||||
return lcd_direct_init_device();
|
||||
}
|
||||
|
||||
esp_err_t platform_lcd_set_backlight_brightness(uint8_t brightness_percent)
|
||||
{
|
||||
return lcd_direct_set_backlight_brightness(brightness_percent);
|
||||
}
|
||||
|
||||
void platform_start_lcd_render_loop(void)
|
||||
{
|
||||
lcd_direct_start_render_loop();
|
||||
|
||||
@@ -578,6 +578,15 @@ menu "Example Configuration"
|
||||
bool "Backlight active high"
|
||||
default y
|
||||
|
||||
config TQ_SCREEN_BACKLIGHT_BRIGHTNESS_PERCENT
|
||||
int "Default backlight brightness (percent)"
|
||||
default 100
|
||||
range 0 100
|
||||
depends on TQ_SCREEN_ENABLE
|
||||
help
|
||||
Initial LCD backlight PWM duty after screen initialization.
|
||||
Set 0 to turn the backlight off or 100 for full brightness.
|
||||
|
||||
config TQ_SCREEN_MIRROR_X
|
||||
bool "Mirror panel in X direction"
|
||||
default y
|
||||
|
||||
@@ -277,6 +277,7 @@ CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_FULL=y
|
||||
CONFIG_TQ_SCREEN_INVERT_COLOR=y
|
||||
CONFIG_TQ_SCREEN_SWAP_COLOR_BYTES=y
|
||||
CONFIG_TQ_SCREEN_BACKLIGHT_ACTIVE_HIGH=y
|
||||
CONFIG_TQ_SCREEN_BACKLIGHT_BRIGHTNESS_PERCENT=100
|
||||
CONFIG_TQ_SCREEN_MIRROR_X=y
|
||||
CONFIG_TQ_SCREEN_SWAP_XY=y
|
||||
CONFIG_TQ_SCREEN_X_GAP=0
|
||||
|
||||
Reference in New Issue
Block a user