Skip to content

feat: Seeed Wio Tracker L2#335

Open
mverch67 wants to merge 5 commits into
masterfrom
wio-l2
Open

feat: Seeed Wio Tracker L2#335
mverch67 wants to merge 5 commits into
masterfrom
wio-l2

Conversation

@mverch67

@mverch67 mverch67 commented Jul 6, 2026

Copy link
Copy Markdown
Collaborator

QSPI display NV3031B

Summary by CodeRabbit

  • New Features

    • Added support for a new Wio Tracker L2 display profile, including built-in backlight and touch integration.
    • Added a public LP5814 LED driver interface for device setup, brightness control, and per-channel LED tuning.
    • Added configurable SPI mode and optional quad-SPI pin settings for display hardware.
    • Added ESP-style logging support for device UI messages.
  • Bug Fixes

    • Improved device initialization flow to better handle touch controller detection and backlight startup.

@coderabbitai

coderabbitai Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

This PR adds a complete LP5814 I2C LED driver (init/deinit, chip/current/LED control, DC/PWM programming, current calculation), a new LGFX_WIO_TRACKER_L2 display header integrating this driver as a backlight with GT911 touch, generic LGFX SPI/quad-SPI configuration macros, an ESP_LOG logging backend, and factory/config wiring for the new device.

Changes

LED driver and display device integration

Layer / File(s) Summary
LP5814 header contract
drivers/lp5814.h
Defines register addresses, bit masks, lp5814_max_current_t, lp5814_handle_t, and declares the full public API including lp5814_calculate_current.
LP5814 I2C helpers and lifecycle
drivers/lp5814.c
Adds internal register read/write/mask-modify helpers, LED-to-DC/PWM register mapping, and lp5814_init/lp5814_deinit implementations.
LP5814 configuration and LED control
drivers/lp5814.c
Implements chip enable, max-current selection, LED enable, dim/engine/update modes, per-LED DC/PWM writes, combined DC+PWM setter, and current calculation.
LGFX generic SPI configuration
include/graphics/LGFX/LGFX_GENERIC.h
Adds overridable LGFX_SPI_MODE and quad-SPI pin macros (LGFX_PIN_IO0IO3), applying them to the bus configuration.
Wio_Tracker_Light backlight driver
include/graphics/LGFX/LGFX_WIO_TRACKER_L2.h
Implements an ILight wrapper probing and configuring the LP5814, setting/getting brightness via PWM, and logging I2C failures.
LGFX_WIO_TRACKER_L2 device wiring
include/graphics/LGFX/LGFX_WIO_TRACKER_L2.h
Adds the device class wiring SPI panel, GT911 touch, LP5814 backlight, an I2C reset workaround in init_impl, and sleep/wakeup methods.
Device enum, logging, and factory selection
include/graphics/driver/DisplayDriverConfig.h, include/util/ILog.h, source/graphics/driver/DisplayDriverFactory.cpp
Adds WIO_TRACKER_L2 enum value, a USE_ESP_LOG-based logging macro branch, and factory case constructing the new LGFX driver.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant App
  participant LGFX_WIO_TRACKER_L2
  participant Wio_Tracker_Light
  participant LP5814Chip
  participant Wire

  App->>LGFX_WIO_TRACKER_L2: init_impl()
  LGFX_WIO_TRACKER_L2->>Wio_Tracker_Light: init(brightness)
  Wio_Tracker_Light->>LP5814Chip: probe, configure, set DC/PWM
  LGFX_WIO_TRACKER_L2->>LGFX_WIO_TRACKER_L2: base init_impl (GT911 probe)
  LGFX_WIO_TRACKER_L2->>Wire: end()
  LGFX_WIO_TRACKER_L2->>Wire: begin(sda, scl)
  App->>LGFX_WIO_TRACKER_L2: sleep()
  LGFX_WIO_TRACKER_L2->>Wio_Tracker_Light: setBrightness(0)
  App->>LGFX_WIO_TRACKER_L2: wakeup()
  LGFX_WIO_TRACKER_L2->>Wio_Tracker_Light: setBrightness(cached)
  Wio_Tracker_Light->>LP5814Chip: write PWM registers
Loading

Estimated code review effort: 4 (Complex) | ~60 minutes

Poem

A rabbit hops through I2C lanes,
Lighting LP5814's tiny veins,
Four channels glow, PWM in tune,
Tracker L2 wakes beneath the moon,
Hop, flash, sleep — repeat again! 🐇✨

🚥 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 and concisely describes the main change: adding Seeed Wio Tracker L2 support.
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: 3

🧹 Nitpick comments (6)
drivers/lp5814.h (1)

184-221: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Incomplete/incorrect Doxygen for the dim/engine/update setters.

The @brief bodies are empty and the copied @return lines reference led_mask is invalid, but none of these functions take a led_mask parameter. Please fill in the briefs and drop the irrelevant led_mask clause so the public API docs are accurate.

🤖 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 `@drivers/lp5814.h` around lines 184 - 221, Update the Doxygen comments for
lp5814_set_led_dim_mode, lp5814_set_led_engine_mode, and
lp5814_set_led_update_param so the `@brief` fields actually describe each setter’s
purpose, and remove the incorrect “led_mask is invalid” text from the `@return`
sections since these APIs do not take a led_mask parameter. Keep the return
descriptions aligned with the actual handle and I2C failure behavior for each
function.
drivers/lp5814.c (2)

197-202: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

lp5814_init ignores errors from the final configuration writes.

The first three writes are error-checked and unwind on failure, but these six calls discard their return values, and the function then returns ESP_OK unconditionally. If any of these I2C writes fail (e.g., NAK), init reports success while the device is left partially configured. Capture and propagate the results (and unwind consistently with the earlier failure path).

🤖 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 `@drivers/lp5814.c` around lines 197 - 202, lp5814_init is ignoring failures
from the final device-configuration writes, so update the
lp5814_set_led_dim_mode, lp5814_set_led_engine_mode, lp5814_set_led_dc,
lp5814_set_led_enable, lp5814_set_led_update_param, and lp5814_set_led_pwm calls
to capture and check their return values. If any call fails, propagate the error
from lp5814_init and unwind consistently with the earlier error path instead of
returning ESP_OK unconditionally.

93-146: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Remove the unused DC/PWM register helpers drivers/lp5814.c:93-146lp5814_get_dc_register() and lp5814_get_pwm_register() aren’t called anywhere, while lp5814_set_led_dc() / lp5814_set_led_pwm() already compute the same offsets inline. Either delete the dead helpers or switch the loops to use them; keeping both risks drift. The current fallback to LED0 for unknown masks also makes them a poor drop-in replacement.

🤖 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 `@drivers/lp5814.c` around lines 93 - 146, Remove the dead DC/PWM register
helpers in lp5814.c by either deleting lp5814_get_dc_register() and
lp5814_get_pwm_register() or updating lp5814_set_led_dc() and
lp5814_set_led_pwm() to call them consistently. If you keep the helpers, ensure
their LED mask handling matches the existing loops and does not silently fall
back to LED0 for invalid masks; otherwise remove the duplication to avoid drift.
include/util/ILog.h (1)

34-44: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

ILOG_TRACE maps to the same verbosity as ILOG_DEBUG.

ESP-IDF has ESP_LOGV (verbose), which is a level below ESP_LOGD and better matches "trace" semantics. Mapping ILOG_TRACE to ESP_LOGD makes it indistinguishable from ILOG_DEBUG output/filtering.

♻️ Suggested fix
-#define ILOG_TRACE(...) ESP_LOGD("DeviceUI", __VA_ARGS__)
+#define ILOG_TRACE(...) ESP_LOGV("DeviceUI", __VA_ARGS__)
🤖 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/util/ILog.h` around lines 34 - 44, `ILOG_TRACE` currently aliases
`ESP_LOGD`, so trace logs are treated the same as debug logs in the
`USE_ESP_LOG` branch of `ILog.h`. Update the `ILOG_TRACE` macro in that ESP log
mapping block to use the verbose ESP-IDF log level instead, while keeping the
other `ILOG_*` macros unchanged, so trace output is distinct from `ILOG_DEBUG`.
include/graphics/LGFX/LGFX_GENERIC.h (1)

67-82: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Quad-SPI pins applied unconditionally even if only partially defined.

The comment says quad pins are "only used if all 4 are defined," but each LGFX_PIN_IOx macro independently defaults to -1 and all four are applied unconditionally to cfg.pin_io0-cfg.pin_io3. If a board only defines a subset (e.g. LGFX_PIN_IO0/IO1 but not IO2/IO3), the bus gets a partially-valid quad-SPI pin configuration instead of falling back to standard SPI, which could misconfigure the bus for that board.

💡 Suggested guard to enforce all-or-nothing quad pin definition
+#if defined(LGFX_PIN_IO0) || defined(LGFX_PIN_IO1) || defined(LGFX_PIN_IO2) || defined(LGFX_PIN_IO3)
+#if !defined(LGFX_PIN_IO0) || !defined(LGFX_PIN_IO1) || !defined(LGFX_PIN_IO2) || !defined(LGFX_PIN_IO3)
+#error "All four LGFX_PIN_IO0..IO3 must be defined together for quad SPI"
+#endif
+#endif

Also applies to: 254-259

🤖 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_GENERIC.h` around lines 67 - 82, The quad-SPI pin
handling in LGFX_GENERIC.h is applied even when only some of the LGFX_PIN_IO0
through LGFX_PIN_IO3 macros are defined, so update the configuration logic
around the cfg.pin_io0–cfg.pin_io3 assignments to require all four pins before
enabling quad mode. Use the existing LGFX_PIN_IOx symbols in the generic display
config path to add an all-or-nothing guard, and otherwise leave the bus in
standard SPI mode when any of the quad pins are missing.
include/graphics/LGFX/LGFX_WIO_TRACKER_L2.h (1)

103-118: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Magic-number I2C pins duplicated across the class.

Pins 47/48 appear both in Wire.begin(47, 48) (line 115) and in the touch cfg.pin_sda/cfg.pin_scl (lines 187-188). If one is updated without the other, the LP5814 recovery reset would silently reconfigure the bus with mismatched pins.

♻️ Suggested consolidation
+    static constexpr int8_t kI2cSda = 47;
+    static constexpr int8_t kI2cScl = 48;
+
     bool init_impl(bool use_reset, bool use_clear) override
     {
         ...
-        Wire.end();
-        Wire.begin(47, 48);
+        Wire.end();
+        Wire.begin(kI2cSda, kI2cScl);

and use the same constants for cfg.pin_sda/cfg.pin_scl in the touch config block.

Also applies to: 185-190

🤖 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_WIO_TRACKER_L2.h` around lines 103 - 118, The I2C
pin values are duplicated in both the recovery logic inside init_impl and the
touch configuration block, which risks them drifting out of sync. Introduce
shared named constants or a single source of truth in LGFX_WIO_TRACKER_L2 and
use those symbols in both Wire.begin and the cfg.pin_sda/cfg.pin_scl assignments
so the LP5814 reset and GT911 setup always use the same pins.
🤖 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_WIO_TRACKER_L2.h`:
- Around line 45-60: The init() setup sequence in LGFX_WIO_TRACKER_L2 is
ignoring failed register writes and still reporting success. Update init() to
track the result of every writeReg call in the LP5814 configuration path,
including the loop over REG_LED0_DC and the final REG_UPDATE write, and return
the aggregated success state instead of unconditionally returning true. Keep the
existing setBrightness(brightness) call after the writes, but only report
initialization success when all register operations succeed.
- Around line 1-2: The include guard in LGFX_WIO_TRACKER_L2 is colliding with
another header because it still uses the LGFX_PICO_H symbol. Update the guard in
this header to a unique name tied to LGFX_WIO_TRACKER_L2, and make sure both the
define and matching endif protection use that new symbol so this header can be
included alongside LGFX_PICO_TFT_240x135 without being skipped.

---

Nitpick comments:
In `@drivers/lp5814.c`:
- Around line 197-202: lp5814_init is ignoring failures from the final
device-configuration writes, so update the lp5814_set_led_dim_mode,
lp5814_set_led_engine_mode, lp5814_set_led_dc, lp5814_set_led_enable,
lp5814_set_led_update_param, and lp5814_set_led_pwm calls to capture and check
their return values. If any call fails, propagate the error from lp5814_init and
unwind consistently with the earlier error path instead of returning ESP_OK
unconditionally.
- Around line 93-146: Remove the dead DC/PWM register helpers in lp5814.c by
either deleting lp5814_get_dc_register() and lp5814_get_pwm_register() or
updating lp5814_set_led_dc() and lp5814_set_led_pwm() to call them consistently.
If you keep the helpers, ensure their LED mask handling matches the existing
loops and does not silently fall back to LED0 for invalid masks; otherwise
remove the duplication to avoid drift.

In `@drivers/lp5814.h`:
- Around line 184-221: Update the Doxygen comments for lp5814_set_led_dim_mode,
lp5814_set_led_engine_mode, and lp5814_set_led_update_param so the `@brief` fields
actually describe each setter’s purpose, and remove the incorrect “led_mask is
invalid” text from the `@return` sections since these APIs do not take a led_mask
parameter. Keep the return descriptions aligned with the actual handle and I2C
failure behavior for each function.

In `@include/graphics/LGFX/LGFX_GENERIC.h`:
- Around line 67-82: The quad-SPI pin handling in LGFX_GENERIC.h is applied even
when only some of the LGFX_PIN_IO0 through LGFX_PIN_IO3 macros are defined, so
update the configuration logic around the cfg.pin_io0–cfg.pin_io3 assignments to
require all four pins before enabling quad mode. Use the existing LGFX_PIN_IOx
symbols in the generic display config path to add an all-or-nothing guard, and
otherwise leave the bus in standard SPI mode when any of the quad pins are
missing.

In `@include/graphics/LGFX/LGFX_WIO_TRACKER_L2.h`:
- Around line 103-118: The I2C pin values are duplicated in both the recovery
logic inside init_impl and the touch configuration block, which risks them
drifting out of sync. Introduce shared named constants or a single source of
truth in LGFX_WIO_TRACKER_L2 and use those symbols in both Wire.begin and the
cfg.pin_sda/cfg.pin_scl assignments so the LP5814 reset and GT911 setup always
use the same pins.

In `@include/util/ILog.h`:
- Around line 34-44: `ILOG_TRACE` currently aliases `ESP_LOGD`, so trace logs
are treated the same as debug logs in the `USE_ESP_LOG` branch of `ILog.h`.
Update the `ILOG_TRACE` macro in that ESP log mapping block to use the verbose
ESP-IDF log level instead, while keeping the other `ILOG_*` macros unchanged, so
trace output is distinct from `ILOG_DEBUG`.
🪄 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: a0b83900-6d57-4b76-8371-a8f70f7c3a87

📥 Commits

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

📒 Files selected for processing (7)
  • drivers/lp5814.c
  • drivers/lp5814.h
  • include/graphics/LGFX/LGFX_GENERIC.h
  • include/graphics/LGFX/LGFX_WIO_TRACKER_L2.h
  • include/graphics/driver/DisplayDriverConfig.h
  • include/util/ILog.h
  • source/graphics/driver/DisplayDriverFactory.cpp

Comment thread drivers/lp5814.c
Comment on lines +181 to +182
// Set default max current to 25.5mA
ret = lp5814_set_max_current(handle, LP5814_MAX_CURRENT_51MA);

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

Comment/value mismatch and macro used where enum is expected.

The comment says "default max current to 25.5mA", but the code programs LP5814_MAX_CURRENT_51MA. Also, LP5814_MAX_CURRENT_51MA is the raw register-bit macro (0x01); the setter expects the lp5814_max_current_t enum. It compiles because the values coincide, but pass the enum to keep intent clear and align the comment with the actual default.

🔧 Proposed fix
-    // Set default max current to 25.5mA
-    ret = lp5814_set_max_current(handle, LP5814_MAX_CURRENT_51MA);
+    // Set default max current to 51mA
+    ret = lp5814_set_max_current(handle, LP5814_MAX_CURRENT_51_MA);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Set default max current to 25.5mA
ret = lp5814_set_max_current(handle, LP5814_MAX_CURRENT_51MA);
// Set default max current to 51mA
ret = lp5814_set_max_current(handle, LP5814_MAX_CURRENT_51_MA);

Comment on lines +1 to +2
#ifndef LGFX_PICO_H
#define LGFX_PICO_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 | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check for guard-name collisions with LGFX_PICO_H across the repo
rg -n 'LGFX_PICO_H' --type=cpp -g '!**/build/**'

Repository: meshtastic/device-ui

Length of output: 158


🏁 Script executed:

#!/bin/bash
sed -n '1,20p' include/graphics/LGFX/LGFX_WIO_TRACKER_L2.h

Repository: meshtastic/device-ui

Length of output: 617


🏁 Script executed:

#!/bin/bash
rg -n --hidden --glob '!**/.git/**' 'LGFX_PICO_H' .

Repository: meshtastic/device-ui

Length of output: 434


Rename this include guard
LGFX_PICO_H is also used by include/graphics/LGFX/LGFX_PICO_TFT_240x135.h, so including both headers in one translation unit will suppress one of them. Use LGFX_WIO_TRACKER_L2_H here instead.

🐛 Suggested fix
-#ifndef LGFX_PICO_H
-#define LGFX_PICO_H
+#ifndef LGFX_WIO_TRACKER_L2_H
+#define LGFX_WIO_TRACKER_L2_H
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
#ifndef LGFX_PICO_H
#define LGFX_PICO_H
`#ifndef` LGFX_WIO_TRACKER_L2_H
`#define` LGFX_WIO_TRACKER_L2_H
🤖 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_WIO_TRACKER_L2.h` around lines 1 - 2, The include
guard in LGFX_WIO_TRACKER_L2 is colliding with another header because it still
uses the LGFX_PICO_H symbol. Update the guard in this header to a unique name
tied to LGFX_WIO_TRACKER_L2, and make sure both the define and matching endif
protection use that new symbol so this header can be included alongside
LGFX_PICO_TFT_240x135 without being skipped.

Comment on lines +45 to +60
writeReg(REG_DEVICE_CONFIG0, 0x01); // chip enable
writeReg(REG_MAX_CURRENT, 0x01); // 51 mA max current
writeReg(REG_ENABLE_CONTROL, 0x00); // disable outputs while configuring
writeReg(REG_DIM_MODE, 0x4E); // dim mode config
writeReg(REG_ENGINE_MODE, 0xF0); // engine mode config
// Set DC current for all 4 channels (registers 0x14..0x17)
for (uint8_t i = 0; i < 4; i++) {
writeReg(REG_LED0_DC + i, 200);
}
writeReg(REG_ENABLE_CONTROL, 0x0F); // enable all 4 channels
writeReg(REG_UPDATE, 0x55); // latch parameters (LP5814 requires 0x55)
delay(5); // LP5814 engine startup settling time

setBrightness(brightness);
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.

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

init() returns true even when individual register writes fail.

Each writeReg call in the setup sequence logs on failure but doesn't affect the final return true;. A partial/failed LP5814 configuration would still be reported as successful init.

♻️ Suggested fix to propagate write failures
-    void writeReg(uint8_t reg, uint8_t value)
+    bool writeReg(uint8_t reg, uint8_t value)
     {
         Wire.beginTransmission(LP5814_I2C_ADDR_DEFAULT);
         Wire.write(reg);
         Wire.write(value);
         uint8_t error = Wire.endTransmission();
-        if (error != 0)
+        if (error != 0) {
             ILOG_ERROR("LP5814 write reg 0x%02x failed: %d", reg, error);
+            return false;
+        }
+        return true;
     }

Then aggregate the boolean results in init() (e.g. bool ok = true; ok &= writeReg(...); ...; return ok;) instead of unconditionally returning true.

🤖 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_WIO_TRACKER_L2.h` around lines 45 - 60, The init()
setup sequence in LGFX_WIO_TRACKER_L2 is ignoring failed register writes and
still reporting success. Update init() to track the result of every writeReg
call in the LP5814 configuration path, including the loop over REG_LED0_DC and
the final REG_UPDATE write, and return the aggregated success state instead of
unconditionally returning true. Keep the existing setBrightness(brightness) call
after the writes, but only report initialization success when all register
operations succeed.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant