Skip to content

Commit 7820c1e

Browse files
committed
qtouch: subtract min sensor value per slider
This improves touch position accuracy in noisy environments and may reduce touch issues reported in the wild. Touch position is calculated with a weighted average of the sensor readings. If properly calibrated, sensors on the opposite end of a finger touch would be zero and thus make no contribution to the weighted average. If the baseline sensor readings are elevated, the sensors on the opposite edge DO contribute to the weighted average making a positional artifact (i.e. the position is more central than it should be in reality). This artifact is higher when the finger is a bit distant while approaching and lower/negligible when the finger is fully touching the device. This can cause the position to move enough to enter "slide" mode and disable "tap" events being emitted. In addition, defines unnamed constant DEF_SENSOR_CEILING.
1 parent 7ebb845 commit 7820c1e

File tree

3 files changed

+29
-9
lines changed

3 files changed

+29
-9
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ customers cannot upgrade their bootloader, its changes are recorded separately.
1010
- Increased performance when signing Bitcoin transactions
1111
- Warn if the transaction fee is higher than 10% of the coins sent
1212
- ETH Testnets: add Goerli and remove deprecated Rinkeby and Ropsten
13+
- Improved touch button positional accuracy in noisy environments
1314

1415
### 9.13.1
1516
- Fix bug introduced in 9.13.0: remove double cancel confirmation in the 'Restore from recovery words' workflow

src/qtouch/qtouch.c

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
/*============================================================================
32
Filename : touch.c
43
Project : QTouch Modular Library
@@ -570,7 +569,7 @@ uint16_t qtouch_get_sensor_node_signal_filtered(uint16_t sensor_node)
570569
{
571570
// Filter the sensor signal.
572571
//
573-
// Smooth it out and saturate it so that values never go beyond 50.
572+
// Smooth it out and saturate it so that values never go beyond DEF_SENSOR_CEILING.
574573
// This helps to mitigate 'jumpy' channels that exist at higher sensor readings when
575574
// in noisy environments.
576575
//
@@ -592,7 +591,7 @@ uint16_t qtouch_get_sensor_node_signal_filtered(uint16_t sensor_node)
592591
X = (uint16_t)((double)X * (1 + DEF_SENSOR_EDGE_WEIGHT));
593592
}
594593
// Saturate out-of-range readings.
595-
X = (X > 50) ? 50 : X;
594+
X = (X > DEF_SENSOR_CEILING) ? DEF_SENSOR_CEILING : X;
596595

597596
// Calculate sensor readout using a moving average
598597
// The moving average wieghts previous N readings twice current reading
@@ -630,21 +629,38 @@ void qtouch_process_scroller_positions(void)
630629
uint8_t i, j;
631630
uint16_t sum = 0;
632631
uint16_t max_sensor_reading = 0;
632+
uint16_t min_sensor_reading = DEF_SENSOR_CEILING;
633633
uint16_t weighted_sum = 0;
634+
uint16_t filtered_readings[DEF_SCROLLER_NUM_CHANNELS] = {0};
634635
uint16_t sensor_location[DEF_SCROLLER_NUM_CHANNELS] = {
635636
1, // Offset by `1` because a `0` location cannot be weight-averaged
636637
DEF_SCROLLER_RESOLUTION / 3,
637638
DEF_SCROLLER_RESOLUTION / 3 * 2,
638639
DEF_SCROLLER_RESOLUTION};
639640

640-
// Read filterd data and weight by sensor physical location
641641
for (i = 0; i < DEF_SCROLLER_NUM_CHANNELS; i++) {
642-
uint16_t value;
643-
value = qtouch_get_sensor_node_signal_filtered(
642+
filtered_readings[i] = qtouch_get_sensor_node_signal_filtered(
644643
i + (scroller ? DEF_SCROLLER_OFFSET_1 : DEF_SCROLLER_OFFSET_0));
645-
sum += value;
646-
weighted_sum += value * sensor_location[i];
647-
max_sensor_reading = (value > max_sensor_reading) ? value : max_sensor_reading;
644+
min_sensor_reading = (filtered_readings[i] < min_sensor_reading) ? filtered_readings[i]
645+
: min_sensor_reading;
646+
max_sensor_reading = (filtered_readings[i] > max_sensor_reading) ? filtered_readings[i]
647+
: max_sensor_reading;
648+
}
649+
650+
// Read filterd data and weight by sensor physical location
651+
// Reduce the value by the min_sensor_reading to improve positional accuracy.
652+
// Touch position is calculated with a weighted average of the sensor readings.
653+
// If properly calibrated, sensors on the opposite end of a finger touch would
654+
// be zero and thus make no contribution to the weighted average. If the baseline
655+
// sensor readings are elevated, the sensors on the opposite edge DO contribute
656+
// to the weighted average making a positional artifact (i.e. the position is more
657+
// central than it should be in reality). This artifact is higher when the finger
658+
// is a bit distant while approaching and lower/negligible when the finger is
659+
// fully touching the device. This can cause the position to move enough to enter
660+
// "slide" mode and disable "tap" events being emitted.
661+
for (i = 0; i < DEF_SCROLLER_NUM_CHANNELS; i++) {
662+
sum += filtered_readings[i] - min_sensor_reading;
663+
weighted_sum += (filtered_readings[i] - min_sensor_reading) * sensor_location[i];
648664
}
649665

650666
// Compensate for deadband (i.e. when only a single edge button gives a reading and

src/qtouch/qtouch.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,9 @@ extern "C" {
262262
0.15 // Percent added weight to edge sensors, which are physically smaller
263263
#define DEF_SENSOR_NUM_PREV_POS \
264264
4 // Number of previous sensor positions to remember; used in a simple filter
265+
#define DEF_SENSOR_CEILING \
266+
50 // Maximum sensor reading. Mitigates 'jumpy' channels that exist at higher
267+
// sensor readings when in noisy environments.
265268

266269
#ifdef __cplusplus
267270
}

0 commit comments

Comments
 (0)