Root cause found and fixed: GT9271 touch controller ships with debounce disabled
The hardware EMI path was a dead end. The actual cause is a single configuration byte that ships with the wrong value on every unit.
TL;DR: All reTerminal DM units in our deployment shipped with shake_count = 1 in the GT9271 capacitive touch controller. shake_count is the number of consecutive scan frames a contact must persist before the controller reports a touch event. At value 1 (one frame, ~10ms), any brief capacitive coupling through the operator’s body registers as a real touch. Raising it to 4 eliminated ghost touches on all 19 units. No hardware changes needed.
What we ruled out
- Earthing topology changes (star topology, direct PE bond): no effect
- Bonding 24V supply negative terminal to PE: no effect
- SAKO SAKURA EMI filter on power input: appeared to help, but units on battery UPS still showed the same behaviour, ruling out conducted power-line noise as the primary path
- DSI flex cable shielding: not needed
- Steel enclosure: not needed
The hands-off test was the key diagnostic. Nine minutes of capture across three units with machines running and no human contact produced zero phantom touch events. This confirms the mechanism is touch-triggered capacitive coupling through the operator’s body, not free-running EMI.
Root cause
The Goodix GT9271 stores its configuration in a 186-byte register block starting at address 0x8047. Byte offset 8 (register 0x804F) is shake_count: how many consecutive scan cycles a contact must be detected before the controller reports BTN_TOUCH. Factory value on every unit tested: 1.
At the GT9271 default 100 Hz scan rate, shake_count = 1 means a 10ms contact is sufficient to register a touch. When an operator touches the screen in front of an injection moulding machine, their body couples common-mode disturbance from heaters, hydraulic pump motors, and VFD drives into the panel for roughly 10-30ms. The controller cannot tell this from a real tap.
This is not a floating DC reference problem. It is a debounce problem. The chip ships with debounce effectively disabled.
Measurements at factory settings (shake_count = 1)
| Scenario |
Expected |
Measured |
| Office bench, 50 deliberate taps |
50 |
72 (+44%) |
| Machine 16 (heavy EMI), 120s tap test |
~120 |
354 |
| Machine 16, 9 min hands-off capture, machines running |
0 |
0 |
| Machine 16, same 120s tap test at shake_count = 4 |
~120 |
37 |
The fix
The Linux mainline goodix_ts driver (used in Ubuntu Frame images on reTerminal DM) reads /lib/firmware/goodix_9271_cfg.bin at every probe and programs the chip if the file is present. The file does not exist on factory images, so the chip runs its own NVM config at shake_count = 1. Writing a modified blob to that path is all that is required.
Each unit’s config carries panel-specific calibration values. Build the modified config from that unit’s own live chip, never copy a blob between units.
Step 1: read the chip config
sudo modprobe i2c-dev
sudo python3 gt9271.py read
Reads 186 bytes live over I2C bus 10, address 0x5d. Validates checksum. Saves the factory config as a backup.
Step 2: build a modified config
sudo python3 gt9271.py make shake_count=4
Patches byte 8 in the live config, recalculates checksum using (~sum(cfg[0:184]) + 1) & 0xFF, sets config_fresh = 1, writes to /lib/firmware/goodix_9271_cfg.bin.
Step 3: reload the driver
sudo python3 gt9271.py apply
Unbinds then rebinds the Goodix-TS driver on 10-005d. Driver re-probes, reads the new file, programs the chip.
Step 4: verify
sudo python3 gt9271.py read
# expect: shake_count off 8 reg 0x804F = 4 (0x04)
Or directly without the tool:
sudo modprobe i2c-dev
i2cget -y 10 0x5d 0x4f
# factory: 0x01 after fix: 0x04
Driver note: This targets the mainline goodix_ts driver, not Seeed’s out-of-tree gt9xx. Confirm: ls /sys/bus/i2c/drivers/Goodix-TS/ should show 10-005d.
Persistence
/lib/firmware/goodix_9271_cfg.bin survives reboots. The driver reads it at every probe.
Warning: Re-imaging the OS wipes /lib/firmware/ and silently returns the unit to factory shake_count = 1. Bake the file into your standard image, or add a commissioning step to verify it after any reflash.
Results on fleet of 19 units
All 19 reTerminal DM units are now on shake_count = 4. Ghost touches eliminated across the entire fleet, confirmed by plant manager. Typing in login screens works correctly. No missed keystrokes in one week of monitoring. Changes survive reboots.
shake_count = 3 gave ~90% improvement with slightly slower touch feel reported. shake_count = 4 was required to fully eliminate ghost touches on machines with the heaviest inductive loads.
Note to Seeed
Every unit in this deployment (19 units, production ~2025-2026) shipped with shake_count = 1, the minimum possible value. The GT9271 datasheet describes shake_count as a noise rejection parameter specifically for industrial environments. A default of 3-4 would be appropriate for an industrial HMI product.
Reproducible on any quiet bench: our office unit registered 72 contacts for 50 deliberate taps at factory settings.
Quick check on any reTerminal DM:
sudo modprobe i2c-dev && i2cget -y 10 0x5d 0x4f
# 0x01 = factory default (affected)
# 0x04 = after fix
Thanks @PJ_Glasso for your continued support 