feat(platform): add PWM backlight brightness control

This commit is contained in:
chenjintao
2026-08-20 18:21:06 +08:00
parent 0542aadaa4
commit 988dc924b9
7 changed files with 113 additions and 5 deletions
+1
View File
@@ -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
+9
View File
@@ -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);
+87 -5
View File
@@ -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();