Repository navigation
fix(#290, #291): a tap wakes a sleeping TFT; GPS parser survives a short RMC sentence - #293
Merged
Merged
Conversation
loop() parks lv_timer_handler() while the TFT sleeps, and the LVGL indev callback was the only reader of the touch chip, so once asleep only the wing buttons could wake the panel. While asleep the touch unit now polls the chip every 100 ms (touchPollForWake) and loop() calls wakeAllDisplays() on a touch, the same path the buttons use. The touch that woke the panel is swallowed until the finger lifts so it does not also click what is under it. Docs: CTP_RST goes to hole 14 with the panel's RESET (owner, 2026-09-08).
On the bench the 100 ms poll needed several taps: a short tap fell between two reads. The FT6336U pulls CTP_INT low for the whole touch, so the ISR that #260 left empty now sets a flag on the falling edge and the sleep path wakes on it; the poll stays as the fallback for a bench without CTP_INT wired. LVGL's read path clears the flag while awake, so a touch made before sleep cannot wake the panel the moment it sleeps.
… garbage nmeaParse fills only nFields slots of parseNMEA's uninitialised fields[]; the RMC branch is entered at nFields >= 3 and reads fields[3..7] unchecked. A sentence cut short by a UART hiccup with status 'A' therefore read stale stack pointers and, once every few hours, faulted at strlen(fields[7]) (LoadProhibited, twice on um_feather 2026-09-08). Every unfilled slot now points at an empty string, so a missing field reads as empty, which is what the existing checks already mean by it.
… manual; FPC order; VCC note Header J2 and FPC P2 carry the same 14 signals in the same order (manual schematics 4.6/4.7). A 14P 0.5 mm FFC-to-DIP adapter is therefore a valid latching-cable option. Manual recommends 5 V on VCC; the bench runs on 3V3.
…US via a diode, no boost on board
…EA fields (#291) From the Gemini gate on this branch: the wake ISR no longer reads the pin (FALLING edge, flag only); the swallow-until-release of a waking tap is capped at 2 s so a chip stuck reporting touch cannot disable input; the NMEA field array is const char* so the empty-string padding needs no cast and a write through it cannot compile. Two findings justified in the PR.
Owner
Author
|
Agent: EmberDelta (session f0e32f9f) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #290, closes #291.
Two firmware defects found on the UM FeatherS3D bench on 2026-09-08, both pre-existing on
mainand independent of the board, plus the display module's official pinout and the FeatherS3D power-path facts in the docs.#290 — a tap wakes a sleeping TFT
loop()parkslv_timer_handler()while the TFT sleeps, and LVGL's indev callback was the only reader of the FT6336U, so once asleep only the three wing buttons could wake the panel. Hidden until now because TFT sleep defaults to "always on"; the owner enabled it.touch.cpp/touch.h:touchPollForWake()— the CTP_INT falling-edge ISR sets a flag (no pin read, nothing outside IRAM), consumed on the next loop pass; a 100 msctp.touched()poll is the fallback for a bench without CTP_INT wired. The waking tap is swallowed until the finger lifts (touchWakeSwallow, called from the LVGL read callback), capped at 2 s so a chip stuck reporting "touched" cannot disable input.src.ino: whiletftSleeping,touchPollForWake()→wakeAllDisplays(), the same path the buttons use. Logs[SLEEP] Woken by touch.Hardware evidence (um_feather): cf3f8fd (poll only) woke after 90 s, ~4 min and an overnight idle, but needed several taps; ea4a99b/e3818d3 (edge-driven) woke on the running image, logged. The post-review edge-mode change (FALLING instead of CHANGE+read) is built but not yet flashed.
#291 — GPS parser crash on a short RMC sentence
parseNMEAdeclared an uninitialisedfields[],nmeaParsefilled onlynFieldsslots, and the RMC branch readfields[3..7]after anFields >= 3gate. A sentence cut short by a UART hiccup with statusAread stale stack pointers and faulted atstrlen(fields[7]):LoadProhibited,EXCVADDR 0, decoded with addr2line against a rebuild of the crashed commit (parseNMEAgps.cpp:138 ←readGPS←loop). Three identical panics in one night, 1.5–3.5 h apart.gps.cpp/gps.h: every unfilled slot points at an empty string;fields[]is nowconst char*so a write through it cannot compile.Hardware evidence: e3818d3 has run since 12:07 EDT with no GPS panic (the old image failed within 1.5–3.5 h every time).
Docs (#290 branch)
docs/um-bench-wiring.mdanddocs/HARDWARE.md: the display module's official 14-pin order from the LCDWIKI MSP3526 manual (header J2 and the 14P 0.5 mm FPC P2 carry the same signals in the same order, verified from the schematic), CTP_RST → hole 14, the manual's 5 V recommendation, and the FeatherS3D power paths from its schematic (5V pin = VBUS via a diode, no boost on board).Gemini adversarial review (gemini-2.5-pro,
docs/llm-consultations/2026-09-08-touch-wake-gps-parse-*.log)digitalRead()inside the IRAM ISR flagged as non-IRAM__digitalReadisARDUINO_ISR_ATTR), but it has alog_wpath, so the read is gone anyway: the interrupt is now FALLING and the ISR only sets the flag. Fixed.(char*)cast off the const empty string is a latent write hazardfields[]isconst char*end to end; no cast. Fixed.talker[2]read without a length checkisRMCis only true whenstrstr(talker, "RMC")found the substring, sotalkerhas at least three characters on that path. Justified.Builds
um_feathers3andfeather_s3both green on the tip; the Adafruit env is unchanged in behaviour.pytest scripts/untouched by this branch.For Ben
🤖 Generated with Claude Code