Add TTGO T-Display backlight brightness control
What changed, and why it matters
This commit adds a screen brightness control feature for the TTGO T-Display development board used with Blockstream Jade. It is a hardware-support change, not a security fix or vulnerability. There are no security signals in the code or commit message.
No security action required. Treat as normal feature/hardware-enablement review.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The patch introduces PWM-based backlight control for the CONFIG_BOARD_TYPE_TTGO_TDISPLAY board via the ESP32 LEDC peripheral. It excludes TTGO from the generic GPIO backlight path in display_hw.c, initializes a LEDC timer/channel in tdisplay.inc, clamps brightness between BACKLIGHT_MIN and BACKLIGHT_MAX, maps it to a 10-bit duty cycle, and adds the brightness menu item to the dashboard UI for this board. It also swaps wheel-event directions for TTGO to match its numeric-entry UI convention.
Changed components
main/display_hw.cmain/power/tdisplay.incmain/process/dashboard.cmain/ui/dashboard.cInspect captured patch +71 / −10
diff --git a/main/display_hw.c b/main/display_hw.c
index dec0c68..11c0727 100644
--- a/main/display_hw.c
+++ b/main/display_hw.c
@@ -86,7 +86,8 @@ static void esp_lcd_init(void* _ignored)
#ifdef ESP_PLATFORM
esp_lcd_panel_io_handle_t io_handle = NULL;
-#if CONFIG_DISPLAY_PIN_BL != -1 && !defined(CONFIG_BOARD_TYPE_WS_TOUCH_LCD2)
+#if CONFIG_DISPLAY_PIN_BL != -1 && !defined(CONFIG_BOARD_TYPE_WS_TOUCH_LCD2) \
+ && !defined(CONFIG_BOARD_TYPE_TTGO_TDISPLAY)
gpio_config_t bk_gpio_config = { .mode = GPIO_MODE_OUTPUT, .pin_bit_mask = 1ULL << CONFIG_DISPLAY_PIN_BL };
ESP_ERROR_CHECK(gpio_config(&bk_gpio_config));
ESP_ERROR_CHECK(gpio_set_level(CONFIG_DISPLAY_PIN_BL, 0));
@@ -180,7 +181,7 @@ static void esp_lcd_init(void* _ignored)
ESP_ERROR_CHECK(esp_lcd_new_panel_st7789(io_handle, &panel_config, &ph));
-#if CONFIG_DISPLAY_PIN_BL != -1
+#if CONFIG_DISPLAY_PIN_BL != -1 && !defined(CONFIG_BOARD_TYPE_TTGO_TDISPLAY)
ESP_ERROR_CHECK(gpio_set_level(CONFIG_DISPLAY_PIN_BL, 1));
#endif
diff --git a/main/power/tdisplay.inc b/main/power/tdisplay.inc
index 848ec6f..ed8c926 100644
--- a/main/power/tdisplay.inc
+++ b/main/power/tdisplay.inc
@@ -2,6 +2,7 @@
//
#include <driver/gpio.h>
+#include <driver/ledc.h>
#include <esp_adc/adc_cali.h>
#include <esp_adc/adc_cali_scheme.h>
#include <esp_adc/adc_oneshot.h>
@@ -11,13 +12,45 @@
#define BATTERY_ADC_ATTEN ADC_ATTEN_DB_12
#define BATTERY_EMA_ALPHA 0.3f // estimated moving average smoothing factor
+#define LCD_BL_LEDC_TIMER LEDC_TIMER_0
+#define LCD_BL_LEDC_MODE LEDC_LOW_SPEED_MODE
+#define LCD_BL_LEDC_CHANNEL LEDC_CHANNEL_0
+#define LCD_BL_LEDC_DUTY_RES LEDC_TIMER_10_BIT
+#define LCD_BL_LEDC_DUTY_MAX ((1 << 10) - 1)
+#define LCD_BL_LEDC_FREQUENCY 10000
+
static adc_oneshot_unit_handle_t adc1_handle = NULL;
static adc_cali_handle_t adc1_cali_chan0_handle = NULL;
static float ema_voltage = 0.0f;
+static esp_err_t brightness_init(void)
+{
+ gpio_reset_pin(CONFIG_DISPLAY_PIN_BL);
+ gpio_set_direction(CONFIG_DISPLAY_PIN_BL, GPIO_MODE_OUTPUT);
+
+ ledc_timer_config_t ledc_timer = { .speed_mode = LCD_BL_LEDC_MODE,
+ .timer_num = LCD_BL_LEDC_TIMER,
+ .duty_resolution = LCD_BL_LEDC_DUTY_RES,
+ .freq_hz = LCD_BL_LEDC_FREQUENCY,
+ .clk_cfg = LEDC_AUTO_CLK };
+ ESP_ERROR_CHECK(ledc_timer_config(&ledc_timer));
+
+ ledc_channel_config_t ledc_channel = { .speed_mode = LCD_BL_LEDC_MODE,
+ .channel = LCD_BL_LEDC_CHANNEL,
+ .timer_sel = LCD_BL_LEDC_TIMER,
+ .intr_type = LEDC_INTR_DISABLE,
+ .gpio_num = CONFIG_DISPLAY_PIN_BL,
+ .duty = 0,
+ .hpoint = 0 };
+ ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel));
+ return ESP_OK;
+}
+
esp_err_t power_init(void)
{
+ ESP_ERROR_CHECK(brightness_init());
+
// Initialise the ADC to measure battery level
adc_oneshot_unit_init_cfg_t init_config1 = {
.unit_id = ADC_UNIT_1,
@@ -50,8 +83,25 @@ esp_err_t power_shutdown(void)
}
esp_err_t power_screen_on(void) { return ESP_OK; }
esp_err_t power_screen_off(void) { return ESP_OK; }
-esp_err_t power_backlight_on(const uint8_t brightness) { return ESP_OK; }
-esp_err_t power_backlight_off(void) { return ESP_OK; }
+esp_err_t power_backlight_on(uint8_t brightness)
+{
+ if (brightness < BACKLIGHT_MIN) {
+ brightness = BACKLIGHT_MIN;
+ } else if (brightness > BACKLIGHT_MAX) {
+ brightness = BACKLIGHT_MAX;
+ }
+
+ const uint32_t duty = (brightness * LCD_BL_LEDC_DUTY_MAX) / BACKLIGHT_MAX;
+ ESP_ERROR_CHECK(ledc_set_duty(LCD_BL_LEDC_MODE, LCD_BL_LEDC_CHANNEL, duty));
+ ESP_ERROR_CHECK(ledc_update_duty(LCD_BL_LEDC_MODE, LCD_BL_LEDC_CHANNEL));
+ return ESP_OK;
+}
+esp_err_t power_backlight_off(void)
+{
+ ESP_ERROR_CHECK(ledc_set_duty(LCD_BL_LEDC_MODE, LCD_BL_LEDC_CHANNEL, 0));
+ ESP_ERROR_CHECK(ledc_update_duty(LCD_BL_LEDC_MODE, LCD_BL_LEDC_CHANNEL));
+ return ESP_OK;
+}
esp_err_t power_camera_on(void) { return ESP_OK; }
esp_err_t power_camera_off(void) { return ESP_OK; }
diff --git a/main/process/dashboard.c b/main/process/dashboard.c
index 67d191d..c2d2de8 100644
--- a/main/process/dashboard.c
+++ b/main/process/dashboard.c
@@ -1701,9 +1701,9 @@ static void handle_view_otps(void)
SENSITIVE_POP(otp_uri);
}
-// NOTE: Only Jade v1.1's and v2's have brightness controls
+// NOTE: Only boards listed here have brightness controls
#if defined(CONFIG_BOARD_TYPE_JADE_V1_1) || defined(CONFIG_BOARD_TYPE_JADE_V2_ANY) \
- || defined(CONFIG_BOARD_TYPE_WS_TOUCH_LCD2)
+ || defined(CONFIG_BOARD_TYPE_WS_TOUCH_LCD2) || defined(CONFIG_BOARD_TYPE_TTGO_TDISPLAY)
static void handle_screen_brightness(void)
{
static const char* LABELS[] = { "Min(1)", "Low(2)", "Medium(3)", "High(4)", "Max(5)" };
@@ -1729,6 +1729,15 @@ static void handle_screen_brightness(void)
// wait for a GUI event
gui_activity_wait_event(act, GUI_EVENT, ESP_EVENT_ANY_ID, NULL, &ev_id, NULL, 0);
+#if defined(CONFIG_BOARD_TYPE_TTGO_TDISPLAY)
+ // Match TTGO value-selection direction to the rest of its numeric entry UI.
+ if (ev_id == GUI_WHEEL_LEFT_EVENT) {
+ ev_id = GUI_WHEEL_RIGHT_EVENT;
+ } else if (ev_id == GUI_WHEEL_RIGHT_EVENT) {
+ ev_id = GUI_WHEEL_LEFT_EVENT;
+ }
+#endif
+
switch (ev_id) {
case GUI_WHEEL_LEFT_EVENT:
if (new_brightness > BACKLIGHT_MIN) {
@@ -2279,9 +2288,9 @@ static void handle_settings(const bool startup_menu)
break;
#endif
-// NOTE: Only Jade v1.1's and v2's have brightness controls
+// NOTE: Only boards listed here have brightness controls
#if defined(CONFIG_BOARD_TYPE_JADE_V1_1) || defined(CONFIG_BOARD_TYPE_JADE_V2_ANY) \
- || defined(CONFIG_BOARD_TYPE_WS_TOUCH_LCD2)
+ || defined(CONFIG_BOARD_TYPE_WS_TOUCH_LCD2) || defined(CONFIG_BOARD_TYPE_TTGO_TDISPLAY)
case BTN_SETTINGS_DISPLAY_BRIGHTNESS:
handle_screen_brightness();
break;
diff --git a/main/ui/dashboard.c b/main/ui/dashboard.c
index b637cfb..6c30fd1 100644
--- a/main/ui/dashboard.c
+++ b/main/ui/dashboard.c
@@ -392,9 +392,10 @@ gui_activity_t* make_display_settings_activity(void)
btn_data_t hdrbtns[] = { { .txt = "=", .font = JADE_SYMBOLS_16x16_FONT, .ev_id = BTN_SETTINGS_DISPLAY_EXIT },
{ .txt = NULL, .font = GUI_DEFAULT_FONT, .ev_id = GUI_BUTTON_EVENT_NONE } };
- // NOTE: Only Jade v1.1's and v2's have brightness controls
+ // NOTE: Only boards listed here have brightness controls
// NOTE: Jade v1.1's do not support Flip Orientation because of issues with screen offsets
-#if defined(CONFIG_BOARD_TYPE_JADE_V2_ANY) || defined(CONFIG_BOARD_TYPE_WS_TOUCH_LCD2)
+#if defined(CONFIG_BOARD_TYPE_JADE_V2_ANY) || defined(CONFIG_BOARD_TYPE_WS_TOUCH_LCD2) \
+ || defined(CONFIG_BOARD_TYPE_TTGO_TDISPLAY)
btn_data_t menubtns[]
= { { .txt = "Display Brightness", .font = GUI_DEFAULT_FONT, .ev_id = BTN_SETTINGS_DISPLAY_BRIGHTNESS },
{ .txt = "Flip Orientation", .font = GUI_DEFAULT_FONT, .ev_id = BTN_SETTINGS_DISPLAY_ORIENTATION },
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.