Change to per-key eager debouncing for ErgoDox EZ.

Empirically, waiting for N consecutive identical scans as a debouncing
strategy doesn't work very well for the ErgoDox EZ where scans are very
slow compared to most keyboards.  Instead, debounce the signals by
eagerly reporting a change as soon as one scan observes it, but then
ignoring further changes from that key for the next N scans.

This is implemented by keeping an extra matrix of uint8 countdowns, such
that only keys whose countdown is currently zero are eligible to change.
When we do observe a change, we bump that key's countdown to DEBOUNCE.
During each scan, every nonzero countdown is decremented.

With this approach to debouncing, much higher debounce constants are
tolerable, because latency does not increase with the constant, and
debounce countdowns on one key do not interfere with events on other
keys.  The only negative effect of increasing the constant is that the
minimum duration of a keypress increases.  Perhaps I'm just extremely
unlucky w.r.t. key switch quality, but I saw occasional bounces even
with DEBOUNCE=10; with 15, I've seen none so far.  That's around 47ms,
which seems like an absolutely insane amount of time for a key to be
bouncy, but at least it works.
master
Andrew Pritchard 2017-04-26 15:29:39 -07:00
parent 7bd4559b4b
commit cd30a60d0e
2 changed files with 38 additions and 26 deletions

View File

@ -58,7 +58,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define RGBW 1 #define RGBW 1
/* Set 0 if debouncing isn't needed */ /* Set 0 if debouncing isn't needed */
#define DEBOUNCE 5 #define DEBOUNCE 15
#define USB_MAX_POWER_CONSUMPTION 500 #define USB_MAX_POWER_CONSUMPTION 500

View File

@ -53,11 +53,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef DEBOUNCE #ifndef DEBOUNCE
# define DEBOUNCE 5 # define DEBOUNCE 5
#endif #endif
static uint8_t debouncing = DEBOUNCE;
/* matrix state(1:on, 0:off) */ /* matrix state(1:on, 0:off) */
static matrix_row_t matrix[MATRIX_ROWS]; static matrix_row_t matrix[MATRIX_ROWS];
static matrix_row_t matrix_debouncing[MATRIX_ROWS];
// Debouncing: store for each key the number of scans until it's eligible to
// change. When scanning the matrix, ignore any changes in keys that have
// already changed in the last DEBOUNCE scans.
static uint8_t debounce_matrix[MATRIX_ROWS * MATRIX_COLS];
static matrix_row_t read_cols(uint8_t row); static matrix_row_t read_cols(uint8_t row);
static void init_cols(void); static void init_cols(void);
@ -113,7 +116,9 @@ void matrix_init(void)
// initialize matrix state: all keys off // initialize matrix state: all keys off
for (uint8_t i=0; i < MATRIX_ROWS; i++) { for (uint8_t i=0; i < MATRIX_ROWS; i++) {
matrix[i] = 0; matrix[i] = 0;
matrix_debouncing[i] = 0; for (uint8_t j=0; j < MATRIX_COLS; ++j) {
debounce_matrix[i * MATRIX_COLS + j] = 0;
}
} }
#ifdef DEBUG_MATRIX_SCAN_RATE #ifdef DEBUG_MATRIX_SCAN_RATE
@ -134,14 +139,36 @@ void matrix_power_up(void) {
// initialize matrix state: all keys off // initialize matrix state: all keys off
for (uint8_t i=0; i < MATRIX_ROWS; i++) { for (uint8_t i=0; i < MATRIX_ROWS; i++) {
matrix[i] = 0; matrix[i] = 0;
matrix_debouncing[i] = 0;
} }
#ifdef DEBUG_MATRIX_SCAN_RATE #ifdef DEBUG_MATRIX_SCAN_RATE
matrix_timer = timer_read32(); matrix_timer = timer_read32();
matrix_scan_count = 0; matrix_scan_count = 0;
#endif #endif
}
// Returns a matrix_row_t whose bits are set if the corresponding key should be
// eligible to change in this scan.
matrix_row_t debounce_mask(uint8_t row) {
matrix_row_t result = 0;
for (uint8_t j=0; j < MATRIX_COLS; ++j) {
if (debounce_matrix[row * MATRIX_COLS + j]) {
--debounce_matrix[row * MATRIX_COLS + j];
} else {
result |= (1 << j);
}
}
return result;
}
// Report changed keys in the given row. Resets the debounce countdowns
// corresponding to each set bit in 'change' to DEBOUNCE.
void debounce_report(matrix_row_t change, uint8_t row) {
for (uint8_t i = 0; i < MATRIX_COLS; ++i) {
if (change & (1 << i)) {
debounce_matrix[row * MATRIX_COLS + i] = DEBOUNCE;
}
}
} }
uint8_t matrix_scan(void) uint8_t matrix_scan(void)
@ -178,26 +205,12 @@ uint8_t matrix_scan(void)
for (uint8_t i = 0; i < MATRIX_ROWS; i++) { for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
select_row(i); select_row(i);
wait_us(30); // without this wait read unstable value. wait_us(30); // without this wait read unstable value.
matrix_row_t cols = read_cols(i); matrix_row_t mask = debounce_mask(i);
if (matrix_debouncing[i] != cols) { matrix_row_t cols = (read_cols(i) & mask) | (matrix[i] & ~mask);
matrix_debouncing[i] = cols; debounce_report(cols ^ matrix[i], i);
if (debouncing) { matrix[i] = cols;
debug("bounce!: "); debug_hex(debouncing); debug("\n");
}
debouncing = DEBOUNCE;
}
unselect_rows();
}
if (debouncing) { unselect_rows();
if (--debouncing) {
wait_us(1);
// this should be wait_ms(1) but has been left as-is at EZ's request
} else {
for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
matrix[i] = matrix_debouncing[i];
}
}
} }
matrix_scan_quantum(); matrix_scan_quantum();
@ -205,9 +218,8 @@ uint8_t matrix_scan(void)
return 1; return 1;
} }
bool matrix_is_modified(void) bool matrix_is_modified(void) // deprecated and evidently not called.
{ {
if (debouncing) return false;
return true; return true;
} }