Skip to content

feat: Crowpanel V2 brightness control#203

Open
mverch67 wants to merge 21 commits into
masterfrom
crowpanelV2
Open

feat: Crowpanel V2 brightness control#203
mverch67 wants to merge 21 commits into
masterfrom
crowpanelV2

Conversation

@mverch67

@mverch67 mverch67 commented Sep 13, 2025

Copy link
Copy Markdown
Collaborator

see meshtastic/firmware#7126

Summary by CodeRabbit

  • New Features

    • Added support for multiple Elecrow backlight controller variants, with automatic detection at startup.
    • Backlight brightness is now handled more accurately across supported hardware versions.
  • Bug Fixes

    • Improved sleep and wake behavior so backlight control no longer toggles incorrectly on newer controller versions.
    • Better device probing helps the display initialize more reliably on supported boards.

@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds a new Elecrow_V2_Light class implementing ILight that detects V2/V3 ELECROW light controllers over I2C and maps brightness to controller commands. Integrates this into LGFX_ELECROW70's init_impl, light() accessor, and sleep()/wakeup() to conditionally control backlight via I2C versus TCA9534 IO expander.

Changes

ELECROW V2 Light Integration

Layer / File(s) Summary
Elecrow_V2_Light class and constants
include/graphics/LGFX/LGFX_ELECROW70.h
Adds ELECROW_V1_ADDR/ELECROW_V2_ADDR constants, changes FREQ_WRITE from 14000000 to 15800000, and defines Elecrow_V2_Light with config_t (isV2, isV3, brightness), init(), setBrightness(), and getBrightness().
Init probing and light exposure wiring
include/graphics/LGFX/LGFX_ELECROW70.h
init_impl probes the ELECROW V1 I2C address before configuring TCA9534, then delegates to base init_impl; light() returns _light_instance pointer only when configured as V2 or V3.
Sleep/wakeup backlight behavior
include/graphics/LGFX/LGFX_ELECROW70.h
sleep()/wakeup() only toggle TCA9534 output when the light instance is not V2/V3, while panel sleep enable/disable remains unconditional.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant InitImpl as LGFX_ELECROW70::init_impl
  participant I2C
  participant LightInstance as Elecrow_V2_Light
  participant TCA9534

  InitImpl->>I2C: probe ELECROW_V1_ADDR
  I2C-->>InitImpl: ACK/NACK result
  InitImpl->>TCA9534: attach, configure pins/levels
  InitImpl->>LightInstance: init(brightness)
  LightInstance->>I2C: detect device type via ACK
  LightInstance-->>InitImpl: isV2/isV3 status
  InitImpl->>InitImpl: delegate to LGFX_Device::init_impl
Loading

Poem

A rabbit hops through wires so bright,
Detecting V2 lights with delight,
No more TCA9534 fuss,
When I2C controls the buss,
Hop hop hooray, brightness just right! 🐇💡

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: adding brightness control support for the Crowpanel V2.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@include/graphics/LGFX/LGFX_ELECROW70.h`:
- Around line 222-236: The sleep/wakeup handling in LGFX_ELECROW70 currently
only toggles panel sleep and the IO expander for non-V2/V3 boards, so V2/V3
backlight remains on. Update the sleep() and wakeup() methods to explicitly turn
the backlight off by sending brightness 0 during sleep and restore the
previously saved brightness during wakeup, while keeping the existing
_panel->setSleep(true/false) and TCA9534 output logic intact. Use the existing
config checks on _light_instance and the current backlight control path in
LGFX_ELECROW70 to place the fix.
- Around line 28-36: Update ELECROW70::init(uint8_t brightness) so it detects
the V3 device and sets _cfg.isV3 when the V3 address/handshake is found, keeping
the existing V2 detection intact. Also stop hardcoding the startup command: use
the brightness argument when sending the initial backlight command so init()
matches getBrightness() and the later setBrightness()/light()/sleep()/wakeup()
paths stay consistent.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 4b01aafd-0848-4872-9ccd-c4a62daa0547

📥 Commits

Reviewing files that changed from the base of the PR and between 1c45ebc and 0ef43f7.

📒 Files selected for processing (1)
  • include/graphics/LGFX/LGFX_ELECROW70.h

Comment on lines +28 to +36
bool init(uint8_t brightness) override
{
Wire.beginTransmission(ELECROW_V2_ADDR);
if (Wire.endTransmission() == 0) {
sendI2CCommand(0x10);
_cfg.isV2 = true;
}
return true;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
rg -nP 'isV3' --type=cpp --type-add 'header:*.h' --type=header
rg -nP '\.init\s*\(' -C2 include/graphics/LGFX/LGFX_ELECROW70.h

Repository: meshtastic/device-ui

Length of output: 158


🌐 Web query:

LovyanGFX ILight init setBrightness interface contract

💡 Result:

In the LovyanGFX library, ILight is an abstract base class (interface) defined in the lgfx::v1 namespace, responsible for abstracting backlight control [1][2]. The ILight interface contract consists of two primary pure virtual functions [1][2]: 1. bool init(uint8_t brightness) = 0; This method is responsible for initializing the backlight hardware, such as configuring PWM pins or I2C communication for a PMIC [2][3][4]. The brightness parameter typically defines the initial light intensity level (range 0–255) [1][5][2]. 2. void setBrightness(uint8_t brightness) = 0; This method updates the backlight intensity to the specified value in the range of 0–255 [1][5][2]. Concrete implementations, such as Light_PWM or those for I2C-controlled backlights, override these methods to provide platform-specific hardware control [1][3][4]. Within the broader architecture, a Panel_Device instance composes an ILight object [6][7]. When a user calls the high-level lcd.setBrightness(b) method on their LGFX device, the library internally delegates the call to the registered ILight implementation's setBrightness method [4][7]. The init process for the light component is triggered automatically when the main LGFX_Device::init function is called during the application startup [4][7].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== file outline ==\n'
ast-grep outline include/graphics/LGFX/LGFX_ELECROW70.h --view expanded || true

printf '\n== relevant file slice ==\n'
sed -n '1,220p' include/graphics/LGFX/LGFX_ELECROW70.h | cat -n

printf '\n== search for ELECROW variants and V3 ==\n'
rg -n "ELECROW|isV3|setBrightness\\(|init\\(uint8_t brightness\\)" include/graphics/LGFX -S

Repository: meshtastic/device-ui

Length of output: 10896


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '220,250p' include/graphics/LGFX/LGFX_ELECROW70.h | cat -n

Repository: meshtastic/device-ui

Length of output: 752


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '220,240p' include/graphics/LGFX/LGFX_ELECROW70.h | cat -n

Repository: meshtastic/device-ui

Length of output: 752


Detect V3 and apply the requested brightness in init(). _cfg.isV3 is never set anywhere, so the V3 path in setBrightness()/light()/sleep()/wakeup() is dead and V3 backlight control never activates. init(uint8_t brightness) also ignores the caller’s value and always sends 0x10, so startup brightness and getBrightness() are out of sync.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@include/graphics/LGFX/LGFX_ELECROW70.h` around lines 28 - 36, Update
ELECROW70::init(uint8_t brightness) so it detects the V3 device and sets
_cfg.isV3 when the V3 address/handshake is found, keeping the existing V2
detection intact. Also stop hardcoding the startup command: use the brightness
argument when sending the initial backlight command so init() matches
getBrightness() and the later setBrightness()/light()/sleep()/wakeup() paths
stay consistent.

Comment on lines 222 to 236
void sleep(void)
{
ioex.output(1, TCA9534::Level::L);
if (!_light_instance.config().isV2 && !_light_instance.config().isV3) {
ioex.output(1, TCA9534::Level::L);
}
_panel->setSleep(true);
}

void wakeup(void)
{
ioex.output(1, TCA9534::Level::H);
_panel->setSleep(false);
if (!_light_instance.config().isV2 && !_light_instance.config().isV3) {
ioex.output(1, TCA9534::Level::H);
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Show the relevant section with line numbers.
sed -n '180,280p' include/graphics/LGFX/LGFX_ELECROW70.h

# Find references to the light instance and sleep/wakeup behavior.
rg -n "_light_instance|setSleep\\(|isV2|isV3|brightness|0x05|backlight" include/graphics/LGFX -S

# List nearby files that may define panel/light behavior.
fd -a "LGFX_ELECROW70.h|LGFX_.*\\.h|*Light*" include/graphics

Repository: meshtastic/device-ui

Length of output: 17831


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the Elecrow light implementation in context.
sed -n '1,120p' include/graphics/LGFX/LGFX_ELECROW70.h

# Inspect the LGFX configuration wrapper for light/panel interactions.
sed -n '1,260p' include/graphics/LGFX/LGFXConfig.h

# Search for setSleep implementations and backlight behavior in the LGFX subtree.
rg -n "setSleep\\(|setLight\\(|ILight|setBrightness\\(|brightness\\s*=|sleep\\(" include/graphics/LGFX -S

Repository: meshtastic/device-ui

Length of output: 17233


🌐 Web query:

LovyanGFX Panel_Device setSleep attached light backlight sleep behavior ILight setBrightness 0

💡 Result:

In the LovyanGFX library, the setSleep(bool) function typically commands the display controller IC itself to enter a low-power mode (e.g., sending MIPI DCS commands like CMD_SLPIN) [1][2]. It does not inherently control the physical backlight GPIO pin [3][2]. Key points regarding your query: 1. Backlight Management: LovyanGFX does not automatically manage the physical backlight GPIO during sleep [3]. Because the library does not explicitly handle the backlight state during sleep transitions, you must manually control the backlight (e.g., set the GPIO pin to LOW) when preparing for system sleep [3]. 2. ILight and Brightness: The ILight interface provides the setBrightness(uint8_t brightness) method [4]. While setting brightness to 0 is intended to turn off or dim the backlight, its effectiveness depends entirely on the underlying hardware implementation of the light controller associated with your panel [5][6]. If the backlight hardware does not support dimming via the ILight interface, calling setBrightness(0) will have no effect [5]. 3. Recommendations: To ensure the backlight is off during sleep, you should explicitly set the backlight pin to an "off" state in your code before calling the system's sleep function [3]. Do not rely on Panel_Device::setSleep or ILight::setBrightness(0) to perform this hardware-specific power-down task [3][5]. For reference, the Panel_Device class acts as a base for hardware abstraction [7], but because backlight circuits vary significantly across different boards, the library leaves the physical GPIO management to the user to avoid unintended side effects or hardware damage [3].

Citations:


V2/V3 backlight still needs an explicit off/on command
_panel->setSleep(true) only puts the panel IC to sleep; it does not power down the backlight. For V2/V3, send brightness 0 in sleep() and restore the saved brightness in wakeup(), otherwise the backlight can stay lit while the panel is asleep.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@include/graphics/LGFX/LGFX_ELECROW70.h` around lines 222 - 236, The
sleep/wakeup handling in LGFX_ELECROW70 currently only toggles panel sleep and
the IO expander for non-V2/V3 boards, so V2/V3 backlight remains on. Update the
sleep() and wakeup() methods to explicitly turn the backlight off by sending
brightness 0 during sleep and restore the previously saved brightness during
wakeup, while keeping the existing _panel->setSleep(true/false) and TCA9534
output logic intact. Use the existing config checks on _light_instance and the
current backlight control path in LGFX_ELECROW70 to place the fix.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant