Skip to content

Fix touch navbar and touch input on display orientation flip - #1

Merged
oroderico merged 5 commits into
oroderico:fix-ws-touch-navbar-flip-cleanfrom
CaTeIM:touch-flip-orientation
Jul 12, 2026
Merged

Fix touch navbar and touch input on display orientation flip#1
oroderico merged 5 commits into
oroderico:fix-ws-touch-navbar-flip-cleanfrom
CaTeIM:touch-flip-orientation

Conversation

@CaTeIM

@CaTeIM CaTeIM commented Jul 11, 2026

Copy link
Copy Markdown

Description

On touchscreen boards the Display -> Flip Orientation feature left the virtual navbar unusable: the buttons were not redrawn at the new panel edge, and touch input kept using physical coordinates, so the y band was stale and prev/next acted swapped. This PR redraws the navbar on flip and mirrors the touch coordinates to follow the display, fixing the feature on all boards with a virtual navbar. Based on top of Blockstream#307 (touch i2c deinit fix); to be rebased once it lands.

Root Cause / Context

  • The navbar is drawn once inside display_init() (main/display.c) and never again; esp_lcd_panel_mirror() remaps the panel on flip (main/display_hw.c:229), leaving the navbar stale at the wrong edge.
  • Touch coordinates are never adjusted on flip: the old FIXME in main/input/touchscreen.inc described the problem (y band plus prev/next inversion).
  • The esp_lcd_touch component applies mirror flags in software (x_max - x, y_max - y) inside esp_lcd_touch_get_coordinates() when the driver has no hardware support, which is the case for both the CST816S and the FT5X06, so esp_lcd_touch_set_mirror_x/_y works uniformly here.
  • tp_cfg.y_max was set to the display height only, but the touch panel extends TOUCH_BUTTON_AREA (40 px) below the display; the software mirror needs the real panel span or coordinates underflow.
  • The navbar band check was hardcoded to touch_y > 200: correct for 200 px displays (CoreS3, TWatchS3), wrong for the 280 px Waveshare, where taps on the bottom 80 px of the GUI area triggered navigation.

Changes

main/display.c

  • Fix: extract the navbar drawing from display_init() into display_touch_navbar_redraw(); init behavior unchanged (settle delays stay in init).

main/display.h

  • Action: declare display_touch_navbar_redraw() with an inline no-op stub for boards without a navbar; promote TOUCH_BUTTON_AREA here so input code can share the constant.

main/gui.c

  • Fix: gui_set_flipped_orientation() redraws the navbar when the orientation actually changes.

main/input/touchscreen.inc

  • Fix: mirror touch coordinates via esp_lcd_touch_set_mirror_x/_y whenever the gui orientation changes. Applied from the touch task itself (no locking needed) and reapplied automatically after the camera touch restart, since the tracking state is task-local.
  • Fix: y_max now spans the full touch panel including the navbar area.
  • Fix: navbar band uses CONFIG_DISPLAY_HEIGHT + CONFIG_DISPLAY_OFFSET_Y instead of the hardcoded 200.
  • Note: the M5 Core2 is excluded from mirroring; its capacitive button strip is physically fixed below the display.

Testing

  • Waveshare S3 Touch LCD 2 (ESP-IDF 5.5.4): flip toggled both ways; prev/OK/next buttons verified in both orientations; QR scanner entry and exit with flip active (exercises the touchscreen restart path).
  • Pending: confirmation on your hardware, which is the goal of this PR.

Motivation

Makes Display -> Flip Orientation fully functional on the touchscreen boards instead of a per-board workaround, with no orientation logic in the button handler.

Since ESP-IDF v5.5 (espressif/esp-idf@e73d78ba) i2c_del_master_bus()
refuses to delete a bus that still has devices attached and returns
ESP_ERR_INVALID_STATE. The touchscreen task registers a panel IO
device on the bus but never releases it, so under IDF 5.5.4 the first
touchscreen_deinit() fails and aborts via ESP_ERROR_CHECK.

On boards that panic with PRINT_HALT, such as the Waveshare S3 Touch
LCD 2, this freezes the device on the boot splash screen while
gathering camera entropy, and also hangs the QR scanner and the
camera exit path, since the touchscreen is restarted around every
camera start/stop (see Blockstream#306).

Releasing the touch handle and the panel IO device (which removes it
from the bus) before deleting the bus restores the deinit/init cycle,
and also fixes a heap leak present under IDF 5.4 where both handles
leaked on every cycle.

Co-authored-by: oroderico <oroderico@users.noreply.github.com>
@oroderico
oroderico changed the base branch from master to touch-flip-orientation-base July 11, 2026 15:57
@oroderico

Copy link
Copy Markdown
Owner

I updated the PR base to a clean branch on my fork:

base: oroderico/Jade:touch-flip-orientation-base
head: CaTeIM:touch-flip-orientation

Now the PR diff is clean again: 4 files changed, based on the current upstream/master.

I also tested the Waveshare behavior again. The navbar redraw works, and entering/exiting the QR scanner with flip enabled also worked fine.

The remaining issue is mirror_x: with esp_lcd_touch_set_mirror_x(ret_touch, flipped), enabling flip makes the side buttons behave swapped. Tapping the visual right button triggers prev, and tapping the visual left button triggers next.

I did a minimal test on top of your branch keeping mirror_y = flipped, but setting mirror_x = false. With that change, prev/OK/next worked correctly in both orientations, including after entering and exiting the QR scanner.

So it looks like, at least on the Waveshare, we need to mirror Y to follow the navbar band, but not mirror X. Could you update your branch with that adjustment so I can test it again?

CaTeIM and others added 2 commits July 12, 2026 04:16
Since ESP-IDF v5.5 i2c_del_master_bus() refuses to delete a bus that
still has devices attached and returns ESP_ERR_INVALID_STATE. On the
M5CoreS3, power_init() attaches the axp2101 and aw9523 devices and
then deletes the bus without releasing them, so under IDF 5.5.4 the
deinit fails, power_init() propagates the error and the JADE_ASSERT
in main.c aborts the boot. Same root cause as the touchscreen fix in
the previous commit (Blockstream#306).

Remove both devices from the bus before deleting it.

Not tested on hardware (none available); the change mirrors the
touchscreen fix validated on the Waveshare S3 Touch LCD 2.
@CaTeIM
CaTeIM changed the base branch from touch-flip-orientation-base to fix-ws-touch-navbar-flip-clean July 11, 2026 17:30
@oroderico
oroderico force-pushed the fix-ws-touch-navbar-flip-clean branch from 394dc37 to 5c22b7d Compare July 11, 2026 17:44
oroderico and others added 2 commits July 11, 2026 14:50
On boards with a virtual touch navbar (TTGO TWatchS3, M5 CoreS3,
Waveshare S3 Touch LCD 2) the prev/OK/next buttons are drawn only once
at startup, inside display_init(). Flipping the display orientation
remaps the panel scan direction, so the navbar was left stale and
upside down at the wrong edge of the panel.

Extract the drawing code into display_touch_navbar_redraw() and call
it from gui_set_flipped_orientation() whenever the orientation
actually changes. Boards without a navbar get an inline no-op stub.
The TOUCH_BUTTON_AREA constant moves to display.h so the touch input
code can share it. The two 50 ms settle delays stay in display_init(),
as flipping does not need them.

Co-authored-by: Gustavo Cateim <cateim@gmail.com>
The touch controllers keep reporting physical panel coordinates after
the display orientation is flipped, so the virtual navbar buttons stop
lining up: taps land on the stale y band and prev/next act swapped
left/right (the FIXME removed here described exactly this).

Instead of teaching the button handler about orientation, apply
esp_lcd_touch_set_mirror_x/_y from the touchscreen task whenever the
gui orientation changes. The esp_lcd_touch component mirrors the
coordinates in software (x_max - x, y_max - y) for drivers without
hardware mirror support, which covers both the CST816S and the FT5X06,
so touch input always matches the display coordinate space on every
board with a navbar. The M5 Core2 is excluded: its buttons are
silk-screened on a fixed capacitive strip below the display and must
not follow the flip.

For the software mirror to be correct y_max must span the full touch
panel, including the navbar area below the main display, so it gains
TOUCH_BUTTON_AREA. The navbar band check also replaces the hardcoded
touch_y > 200 with the board display height: on displays taller than
200 pixels, such as the Waveshare S3 Touch LCD 2 (280 pixels), the old
value made taps on the bottom of the GUI area trigger navigation.

Co-authored-by: oroderico <oroderico@users.noreply.github.com>
@CaTeIM
CaTeIM force-pushed the touch-flip-orientation branch from bc87c1a to 0ed220f Compare July 11, 2026 18:50
@oroderico
oroderico merged commit 0ed220f into oroderico:fix-ws-touch-navbar-flip-clean Jul 12, 2026
@CaTeIM
CaTeIM deleted the touch-flip-orientation branch July 12, 2026 12:00
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.

3 participants