From a152e8f6d503fde06394e564169b5fd49cbacba6 Mon Sep 17 00:00:00 2001 From: Seebs Date: Tue, 3 Apr 2018 20:35:11 -0500 Subject: [PATCH 1/2] Change debouncing algorithm back This changes back to something closer to the old debouncing algorithm, which will ignore brief spikes and record only sustained states; you have to have the same columns for a given row for DEBOUNCE+1 scans before those changes are committed. Any additional changes in the row reset the counter. Doing this per row reduces the cost of rapid typists, as "rows" on the Ergodox are actually vertical columns, with one finger on each; you don't usually move very rapidly within a row, but adjacent keys can be struck rapidly without triggering this. This should probably be fine with significantly lower debounce numbers. It also relies on the other changes that sped up scan rates. This also cleans up the scan logic a bit, and shuffles things to scan the right hand side first; this appears to improve stability, I think. Signed-off-by: Seebs --- keyboards/ergodox_ez/matrix.c | 67 ++++++++++++++--------------------- 1 file changed, 26 insertions(+), 41 deletions(-) diff --git a/keyboards/ergodox_ez/matrix.c b/keyboards/ergodox_ez/matrix.c index e1017113343f..48a7b90accce 100644 --- a/keyboards/ergodox_ez/matrix.c +++ b/keyboards/ergodox_ez/matrix.c @@ -59,10 +59,10 @@ along with this program. If not, see . /* matrix state(1:on, 0:off) */ static matrix_row_t matrix[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]; +// for debouncing: wait until columns settle before +// using them. +static matrix_row_t matrix_last_read[MATRIX_ROWS]; +static uint8_t matrix_debouncing[MATRIX_ROWS]; static matrix_row_t read_cols(uint8_t row); static void init_cols(void); @@ -117,10 +117,9 @@ void matrix_init(void) // initialize matrix state: all keys off for (uint8_t i=0; i < MATRIX_ROWS; i++) { + matrix_debouncing[i] = 0; + matrix_last_read[i] = 0; matrix[i] = 0; - for (uint8_t j=0; j < MATRIX_COLS; ++j) { - debounce_matrix[i * MATRIX_COLS + j] = 0; - } } #ifdef DEBUG_MATRIX_SCAN_RATE @@ -149,28 +148,17 @@ void matrix_power_up(void) { #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; - } - } +static void matrix_read_row(int row) { + matrix_row_t cols = read_cols(row); + if (matrix_last_read[row] != cols) { + matrix_debouncing[row] = DEBOUNCE; + matrix_last_read[row] = cols; + } + if (matrix_debouncing[row] == 0) { + matrix[row] = cols; + } else { + --matrix_debouncing[row]; + } } uint8_t matrix_scan(void) @@ -208,20 +196,17 @@ uint8_t matrix_scan(void) mcp23018_status = ergodox_left_leds_update(); #endif // LEFT_LEDS for (uint8_t i = 0; i < MATRIX_ROWS_PER_SIDE; i++) { - select_row(i); - // and select on left hand - select_row(i + MATRIX_ROWS_PER_SIDE); + uint8_t right = i + MATRIX_ROWS_PER_SIDE; + uint8_t left = i; + // select on right hand first, then left hand + select_row(right); + select_row(left); + // we don't need a 30us delay anymore, because selecting a // left-hand row requires more than 30us for i2c. - matrix_row_t mask = debounce_mask(i); - matrix_row_t cols = (read_cols(i) & mask) | (matrix[i] & ~mask); - debounce_report(cols ^ matrix[i], i); - matrix[i] = cols; - // grab cols from right hand - mask = debounce_mask(i + MATRIX_ROWS_PER_SIDE); - cols = (read_cols(i + MATRIX_ROWS_PER_SIDE) & mask) | (matrix[i + MATRIX_ROWS_PER_SIDE] & ~mask); - debounce_report(cols ^ matrix[i + MATRIX_ROWS_PER_SIDE], i + MATRIX_ROWS_PER_SIDE); - matrix[i + MATRIX_ROWS_PER_SIDE] = cols; + matrix_read_row(right); + matrix_read_row(left); + unselect_rows(); } From 4c42a8392e81cc4ca355d7ab90140e2f427c35be Mon Sep 17 00:00:00 2001 From: Seebs Date: Wed, 4 Apr 2018 11:51:40 -0500 Subject: [PATCH 2/2] Use quasi-eager debouncing So, I looked at some scope traces of bouncing keys, and I noticed: There's only ever bouncing at the start and end of keypresses. This means that eager reporting of key *presses* is safe, as long as you're conservative about key *releases*. So I modify the debounce code slightly further. When this read doesn't match the previous read, we set the debounce timer, but instead of always setting it to the same thing, we set it to DEBOUNCE if at least one bit is set in the matrix but not in this scan (thus, "a key has been released"), and to 1 if it's the other way. So, if you have a very spiky initial state on press, you still get a key press as soon as two consecutive reads reported it, but you don't get a key release until you have at least DEBOUNCE+1 consecutive reads without that key. Testing: Typing with it right now. Less stuttery than the previous ergodox EZ debounce code, but responds faster than the previous debounce code. (Probably not *observably* faster.) Signed-off-by: Seebs --- keyboards/ergodox_ez/matrix.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/keyboards/ergodox_ez/matrix.c b/keyboards/ergodox_ez/matrix.c index 48a7b90accce..ec52c371d299 100644 --- a/keyboards/ergodox_ez/matrix.c +++ b/keyboards/ergodox_ez/matrix.c @@ -151,7 +151,17 @@ void matrix_power_up(void) { static void matrix_read_row(int row) { matrix_row_t cols = read_cols(row); if (matrix_last_read[row] != cols) { - matrix_debouncing[row] = DEBOUNCE; + matrix_row_t released = matrix[row] & ~cols; + if (released) { + /* slow down there! don't report a + * release until it's been stable for at + * least DEBOUNCE scans. (Really, + * DEBOUNCE+1.) + */ + matrix_debouncing[row] = DEBOUNCE; + } else { + matrix_debouncing[row] = 1; + } matrix_last_read[row] = cols; } if (matrix_debouncing[row] == 0) {