diy: Add M5StickC Plus2 backlight brightness control
What changed, and why it matters
This commit adds a screen brightness control feature for the M5StickC Plus2 hardware variant of the Blockstream Jade device. It is a hardware-support and user-interface change, not a security fix or vulnerability. There is no indication of a security issue in the code changes.
No security action required. Treat as normal feature/hardware-enablement commit.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The commit introduces LED PWM (LEDC) backlight control for the M5StickC Plus2 board. It adds a brightness initialization routine, implements power_backlight_on/off using LEDC duty-cycle scaling, and adds the M5_STICKC_PLUS_2 board define to the existing brightness-control conditional compilation blocks. The commit also excludes this board from the generic GPIO backlight on/off path in display_hw.c because backlight is now managed via LEDC. No security-relevant code paths (e.g., cryptography, authentication, memory handling, USB/Bluetooth protocol parsing) are modified.
Changed components
main/display_hw.cmain/power/m5stickcplus2.incmain/process/dashboard.cmain/ui/dashboard.cInspect captured patch +71 / −8
diff --git a/main/display_hw.c b/main/display_hw.c
index 11c0727..79629af 100644
--- a/main/display_hw.c
+++ b/main/display_hw.c
@@ -87,7 +87,7 @@ static void esp_lcd_init(void* _ignored)
esp_lcd_panel_io_handle_t io_handle = NULL;
#if CONFIG_DISPLAY_PIN_BL != -1 && !defined(CONFIG_BOARD_TYPE_WS_TOUCH_LCD2) \
- && !defined(CONFIG_BOARD_TYPE_TTGO_TDISPLAY)
+ && !defined(CONFIG_BOARD_TYPE_TTGO_TDISPLAY) && !defined(CONFIG_BOARD_TYPE_M5_STICKC_PLUS_2)
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));
@@ -181,7 +181,8 @@ 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 && !defined(CONFIG_BOARD_TYPE_TTGO_TDISPLAY)
+#if CONFIG_DISPLAY_PIN_BL != -1 && !defined(CONFIG_BOARD_TYPE_TTGO_TDISPLAY) \
+ && !defined(CONFIG_BOARD_TYPE_M5_STICKC_PLUS_2)
ESP_ERROR_CHECK(gpio_set_level(CONFIG_DISPLAY_PIN_BL, 1));
#endif
diff --git a/main/power/m5stickcplus2.inc b/main/power/m5stickcplus2.inc
index 3903ad1..3720dd9 100644
--- a/main/power/m5stickcplus2.inc
+++ b/main/power/m5stickcplus2.inc
@@ -1,13 +1,45 @@
-// M5StickCPlus implementation - uses IP5303 Power PMU
+// M5StickC Plus 2 implementation - uses IP5303 Power PMU
//
#include <driver/gpio.h>
+#include <driver/ledc.h>
#include <esp_adc/adc_oneshot.h>
#define POWER_HOLD_GPIO 4
#define BATTERY_ADC_CHANNEL ADC_CHANNEL_2
+#define LCD_BL_LEDC_TIMER LEDC_TIMER_3
+#define LCD_BL_LEDC_MODE LEDC_HIGH_SPEED_MODE
+#define LCD_BL_LEDC_CHANNEL LEDC_CHANNEL_7
+#define LCD_BL_LEDC_DUTY_RES LEDC_TIMER_9_BIT
+#define LCD_BL_LEDC_DUTY_BITS 9
+#define LCD_BL_LEDC_FREQUENCY 256
+#define LCD_BL_LEDC_OFFSET 40
+
static adc_oneshot_unit_handle_t adc1_handle = NULL;
+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)
{
// Set the power hold pin to keep the device from powering down straight away
@@ -15,6 +47,8 @@ esp_err_t power_init(void)
gpio_set_direction(POWER_HOLD_GPIO, GPIO_MODE_OUTPUT);
gpio_set_level(POWER_HOLD_GPIO, 1);
+ ESP_ERROR_CHECK(brightness_init());
+
// Initialise the ADC to measure battery level
//-------------ADC1 Init---------------//
adc_oneshot_unit_init_cfg_t init_config1 = {
@@ -42,8 +76,34 @@ 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 scaled_brightness = 1 + ((brightness - BACKLIGHT_MIN) * 254) / (BACKLIGHT_MAX - BACKLIGHT_MIN);
+ uint_fast16_t offset = LCD_BL_LEDC_OFFSET;
+ if (offset) {
+ offset = offset * 259 >> 8;
+ }
+ uint32_t duty = scaled_brightness * (257 - offset);
+ duty += offset * 255;
+ duty += 1 << (15 - LCD_BL_LEDC_DUTY_BITS);
+ duty >>= 16 - LCD_BL_LEDC_DUTY_BITS;
+
+ 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 c2d2de8..56cba90 100644
--- a/main/process/dashboard.c
+++ b/main/process/dashboard.c
@@ -1703,7 +1703,8 @@ static void handle_view_otps(void)
// 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_TTGO_TDISPLAY)
+ || defined(CONFIG_BOARD_TYPE_WS_TOUCH_LCD2) || defined(CONFIG_BOARD_TYPE_TTGO_TDISPLAY) \
+ || defined(CONFIG_BOARD_TYPE_M5_STICKC_PLUS_2)
static void handle_screen_brightness(void)
{
static const char* LABELS[] = { "Min(1)", "Low(2)", "Medium(3)", "High(4)", "Max(5)" };
@@ -2290,7 +2291,8 @@ static void handle_settings(const bool startup_menu)
// 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_TTGO_TDISPLAY)
+ || defined(CONFIG_BOARD_TYPE_WS_TOUCH_LCD2) || defined(CONFIG_BOARD_TYPE_TTGO_TDISPLAY) \
+ || defined(CONFIG_BOARD_TYPE_M5_STICKC_PLUS_2)
case BTN_SETTINGS_DISPLAY_BRIGHTNESS:
handle_screen_brightness();
break;
diff --git a/main/ui/dashboard.c b/main/ui/dashboard.c
index 6c30fd1..2001468 100644
--- a/main/ui/dashboard.c
+++ b/main/ui/dashboard.c
@@ -395,7 +395,7 @@ gui_activity_t* make_display_settings_activity(void)
// 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) \
- || defined(CONFIG_BOARD_TYPE_TTGO_TDISPLAY)
+ || defined(CONFIG_BOARD_TYPE_TTGO_TDISPLAY) || defined(CONFIG_BOARD_TYPE_M5_STICKC_PLUS_2)
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.