Add LilyGO T-Deck Max (e-paper) base board support#552
Conversation
Base board bring-up for the LilyGO T-Deck Max (ESP32-S3, 16 MB flash, 8 MB PSRAM), per the plan discussed in TactilityProject#539: display, touch, and keyboard only — power, LoRa radio, GPS, and haptics follow as separate PRs. New reusable drivers: - Drivers/GDEQ031T10: UC8253-based 240x320 1bpp e-paper panel with windowed partial refresh + full-refresh ghost gate, refresh runs on a background task. - Drivers/xl9555-module: XL9555 I2C IO expander as a kernel module with gpio_controller bindings (the board routes touch/keyboard resets and several power rails through it). Board specifics: - CST66xx touch (Hynitron 4-byte register protocol) implemented device-locally; vendor docs mislabel the part as CST328. - TCA8418 keyboard matrix (existing upstream driver) with backlight. - SD card as an espressif,esp32-sdspi devicetree node on the shared SPI2 bus; unused chip-selects (LoRa, SD) are deasserted before the EPD touches the bus. - incubating=true until SD storage is verified on this board. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
✅ Files skipped from review due to trivial changes (1)
📝 WalkthroughWalkthroughThis PR adds an 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 8
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: f99c293d-2954-42e0-b773-bd1e5c7308dc
📒 Files selected for processing (26)
Devices/lilygo-tdeck-max/CMakeLists.txtDevices/lilygo-tdeck-max/Source/Configuration.cppDevices/lilygo-tdeck-max/Source/devices/Cst66xxTouch.cppDevices/lilygo-tdeck-max/Source/devices/Cst66xxTouch.hDevices/lilygo-tdeck-max/Source/devices/Display.cppDevices/lilygo-tdeck-max/Source/devices/Display.hDevices/lilygo-tdeck-max/Source/devices/TdeckmaxKeyboard.cppDevices/lilygo-tdeck-max/Source/devices/TdeckmaxKeyboard.hDevices/lilygo-tdeck-max/Source/module.cppDevices/lilygo-tdeck-max/device.propertiesDevices/lilygo-tdeck-max/devicetree.yamlDevices/lilygo-tdeck-max/lilygo,tdeck-max.dtsDrivers/GDEQ031T10/CMakeLists.txtDrivers/GDEQ031T10/README.mdDrivers/GDEQ031T10/Source/Gdeq031t10Display.cppDrivers/GDEQ031T10/Source/Gdeq031t10Display.hDrivers/xl9555-module/CMakeLists.txtDrivers/xl9555-module/LICENSE-Apache-2.0.mdDrivers/xl9555-module/README.mdDrivers/xl9555-module/bindings/xlsemi,xl9555.yamlDrivers/xl9555-module/devicetree.yamlDrivers/xl9555-module/include/bindings/xl9555.hDrivers/xl9555-module/include/drivers/xl9555.hDrivers/xl9555-module/include/xl9555_module.hDrivers/xl9555-module/source/module.cppDrivers/xl9555-module/source/xl9555.cpp
|
Thanks, that looks good! I left some comments on a few things, but I didn't find anything major. I am quite busy in the coming 24 hours, so my responses will be a bit slower. |
…ject#552 GDEQ031T10: - waitWhileBusy() now times out (5s) instead of spinning forever on a stuck BUSY pin, which previously could hang the refresh task and make stop() un-recoverable. - writeCommand()/writeData() and all callers now check the SPI transfer result instead of advancing panel/shadow state as if it always succeeds. - start() no longer marks the display powered/initialized before the refresh task is confirmed created; on task-creation failure it now unwinds the SPI device and allocated buffers instead of leaking them. - `powered` and `currentRefreshMode` are now atomic (read on the refresh task, written from arbitrary caller threads). - Corrected a stale doc comment on setRefreshMode() (not one-shot). - README updated to describe the actual windowed partial-refresh pipeline instead of the old full-refresh-every-flush description. TdeckmaxKeyboard: - Modifier state (shift/sym/caps) moved from function-local statics to instance members. - Keyboard queue send is now non-blocking (drops+logs on a full queue) instead of blocking inside the periodic input timer callback. - initBacklight() now returns false when channel config fails, instead of reporting success. xl9555: - set_flags() rejects GPIO_FLAG_ACTIVE_LOW combined with GPIO_FLAG_DIRECTION_OUTPUT: the polarity register only affects input reads, so it silently did nothing for outputs. - set_level()/set_flags() now serialize their read-modify-write register updates with device_lock()/device_unlock(), since the shared i2c_controller_register8_{set,reset}_bits() helpers do a separate read then write. - start() uses check() instead of a soft parent-type check, and drops a log line the parent already emits. Configuration.cpp: i2c0 is unconditionally declared in this board's devicetree, so createDevices() now uses check(i2c) instead of an if, matching the "trust internal guarantees" convention. Cst66xxTouch: unbind the Home/Recents bezel keys. Both called tt::app::start(), which pushes a new app-stack instance on every press; repeated presses would leak Launcher/AppList instances indefinitely. Left unbound until the app stack has a way to resume an existing instance instead of pushing a new one. device.properties / dts: corrected the product name to "T-Deck Max" (was "T-Deck Pro Max") to match the rest of the PR, the vendor repo, and LilyGO's actual naming. Verified with a full idf.py build for lilygo-tdeck-max (IDF 5.5.2). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…-max Follow-up to TactilityProject#552 (base board). Battery metrics come from the BQ27220 fuel gauge (I2C 0x55); charging status, charge control, and power-off (ship mode via SY6970 REG09 BATFET_DIS) use the SY6970 charger (0x6A — newer T-Deck Max revisions use this instead of the older BQ25896 at 0x6B, confirmed by I2C scan; the two are register-compatible for everything used here). Enables the launcher's power-off button. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Thanks for all the fixes we're nearly there! 👍 Regarding Don't forget to update |
…cs() Implements the TactilityProject#552 review suggestion. The manual gpio_config/ gpio_set_level block re-drove, with raw IDF calls, pins spi0 already owns via kernel GPIO descriptors (GPIO_OWNER_SPI): kernel_init() starts every status-okay devicetree device before hal::init runs, so spi0's start() has already initialized SPI2_HOST and driven all three cs-gpios (EPD, SD, LoRa) high by the time initBoot executes. The helper call re-asserts that state as a cheap guard before the EPD driver first transacts, mirroring the esp32_sdspi mount path. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Requested in TactilityProject#552 review so CI builds the board. The entry becomes redundant once TactilityProject#556 (generated device matrix) lands — the generator picks the board up from device.properties' hardware.target automatically. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Thank you for the contribution! This might help me with my pending T-Deck Pro implementation as I was struggling with the display driver. |
…-max Follow-up to TactilityProject#552 (base board). Battery metrics come from the BQ27220 fuel gauge (I2C 0x55); charging status, charge control, and power-off (ship mode via SY6970 REG09 BATFET_DIS) use the SY6970 charger (0x6A — newer T-Deck Max revisions use this instead of the older BQ25896 at 0x6B, confirmed by I2C scan; the two are register-compatible for everything used here). Enables the launcher's power-off button. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Follow-up to #539. This is PR 1 of the incremental plan discussed there: base board (display + touch + keyboard) first, with power, LoRa radio, GPS, and haptics to follow as separate PRs once this lands.
What this adds
Board:
Devices/lilygo-tdeck-max— LilyGO T-Deck Max (ESP32-S3, 16 MB flash, 8 MB PSRAM), the e-paper T-Deck variant (vendor repoXinyuan-LilyGO/T-Deck-MAX).incubating=trueper your suggestion in #539, pending fuller SD-card verification (see below).New reusable drivers:
Drivers/GDEQ031T10— generic UC8253-based e-paper panel driver (240x320, 1bpp), with windowed partial refresh and a full-refresh ghost-clear gate (ported from the vendor's GxEPD2 waveforms). Refresh runs on a background task so the ~0.5-3s panel update never blocks LVGL/input.Drivers/xl9555-module— XL9555 I2C IO expander as a kernel module withgpio_controllerbindings. This supersedes Add XL9555 I/O expander kernel module #537, which I'd closed before it was hardware-tested; it's now verified as part of this board (it gates the touch/keyboard reset lines).Board-local:
espressif,esp32-sdspidevicetree node on the shared SPI2 bus (per yourdevelop-branch SD rework). Unused chip-selects (LoRa, SD) are deasserted before the EPD touches the bus so a floating CS can't latch stray command bytes.Radio (SX1262), power (SY6970/BQ27220), GPS, and haptics (DRV2605) are all deliberately left out of this PR — they're built and working on my fork already, just being split into separate PRs per the plan in #539.
Verification
TactilityFreeRtosTests,TactilityKernelTests,TactilityTests,CryptModuleTests) pass.Known caveat (not from this PR)
During hardware testing I hit a case where touch stopped responding to new taps a few minutes into a session (confirmed via the live trace: the touch controller returned the exact same I2C frame on every subsequent poll — i.e. latched/frozen). This matches a quirk from earlier bring-up: a warm reset or reflash does not fully power-cycle the CST66xx, so it can occasionally need a full power-off to clear. Not something this PR's code can fix from the host side; documenting here for visibility. Happy to discuss defensive options (e.g. a periodic touch-health check with auto re-init) as a follow-up if useful.
🤖 Generated with Claude Code
Summary by CodeRabbit