Hardware overview
The controller handles baseline calibration internally and reports which channels are active via the status register.
Touch initialization
At startup (zerokey-setup.cpp), the firmware:
- Probes the TS06 at
0x69with up to 5 retries (20 ms apart). - If detected, writes minimum sensitivity (
0x3F) to registers0x00–0x02. - Configures operation mode via registers
0x05–0x06. - Sets
ts06_ok = true— if the controller isn’t found, touch is disabled and the serial log shows"TS06 not found on I2C".
Polling cycle
ThehandleButtonChecker() method runs in the main loop:
- Reads
STATUS_REGISTER(0x25) viareadRegister()over I²C. - For each channel bit:
- Records
pressStartTimewhen a channel first becomes active. - Applies a 80 ms debounce (
DEBOUNCE_MS) — releases shorter than this are ignored. - Enforces a 150 ms channel lockout (
CHANNEL_LOCKOUT_MS) — touching a different pad while one is active is ignored.
- Records
- On release:
- If held >
LONG_PRESS_THRESHOLD(800 ms) → dispatches long-press handler. - Otherwise → dispatches short-press handler.
- If held >
Gesture mapping
Long-press visual feedback
When a long press is in progress,drawLongPressProgress() renders a filling progress bar on the OLED screen. This gives the user visual confirmation that they should keep holding. Releasing before 800 ms cancels the action.
PIN screen controls
On the PIN entry screen, the controls change:Error handling
- If the TS06 is not detected at boot,
ts06_okis set tofalseand the status register read returns0x00— effectively disabling touch input. - The firmware does not show a touch error screen; instead, the serial log reports the issue for debugging.
- Touch is silently disabled during lockout delays (
waitFromEeprom()) and during long-running operations like credential erasure.
The TS06 operates independently of EEPROM or ATECC608A operations. Since all share the same I²C bus at 100 kHz, touch polling is interleaved with other I²C traffic in the cooperative main loop.