Skip to content

Feature: interrupt-driven touch input and a main loop that never blocks #292

Description

@Strycher

Owner, 2026-09-08: 'Touch needs to be interrupt-driven and read much sooner, with fewer gaps in reading touch. The heartbeat loop is too slow or too off.' This issue is the design for that, with the measurements that back it.

What the board measured (um_feather @ e3818d3, 2026-09-08 12:07 onward, boot log)

Design

  1. Event-driven touch. The FT6336U pulls CTP_INT (GPIO 6 on the UM board) low for every touch report. Keep the falling-edge ISR, but have it record a flag and a timestamp, and put the LVGL touch indev in LV_INDEV_MODE_EVENT (lvgl 9.5: lv_indev_set_mode / lv_indev_read) so the chip is read the moment loop() sees the flag, not on a 33 ms timer. Awake and asleep use the same path; the sleep case just calls wakeAllDisplays() first. Touch latency becomes one loop pass.
  2. A loop pass is bounded at ~10 ms. Every blocking call in loop() goes: the WiFi reconnect wait becomes a non-blocking state machine driven by WiFi events; SD flushes and weather/battery logging are time-boxed or moved to their own low-priority task; the trailing delay(5) goes (the WDT is fed by the loop itself). Instrument it: track the maximum pass time per status interval and print it in the status line, so a regression is visible in the log.
  3. A dead I2C device costs nothing per pass (Touch controller stops ACKing after ~100 s; firmware polls it at 30 Hz forever with no backoff, and boot never logs the reset reason #289): consecutive-failure counter, mark unavailable, re-probe on a slow timer, bus recovery before the re-probe. This alone returns the loop from 12-27 Hz to 44+ Hz on the current bench.
  4. Instrument the touch path: count ISR edges, reads, and read failures; print them with the loop stats. 'Touch wake sucked' becomes a number.
  5. Later, if 1-3 are not enough: a dedicated input task at higher priority than loopTask that owns the touch reads, with a mutex around every Wire user. Bigger change (every I2C unit touches the mutex); not the first step.

Order

3 (#289) and the WiFi state machine first: they are the measured gaps. Then 1 and 4 together. Then 2's remaining items. Acceptance for the whole feature: on the bench, max loop pass under 10 ms in every status interval, touch registered within 20 ms of the INT edge, a sleeping panel wakes on the first tap every time, all verified from the boot log.

Related: #289 (I2C backoff), #290 (wake path), #99 (credentials, the WiFi wait's trigger), #286 (OLED).

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    board:todoBoard sync: Todo columnpriority:P1Priority: P1 - Majortype:featureDeliverable capability grouping epics

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions