Use eager reporting when debouncing

If a key has been in a stable state and then changes, report that change
immediately and then wait for a cooldown period before reporting any
additional changes.  This reduces latency for registering initial
keypresses.

It would be unusual for this to introduce chatter, since mechanical
switches only tend to be noisy immediately after a key press or release.

This change does not introduce any additional persistent state, although
it does add an additional parameter to the debouncer to distinguish
between the last raw state and the last debounced state.

It also fixes a bug whereby all rows in the matrix would be rewritten
for every row that changed due to a mis-nesting of loops.  However,
it now writes to the matrix state unconditionally.

Signed-off-by: Dean Scarff <dos@scarff.id.au>
pull/1014/head
Dean Scarff 4 years ago
parent 4f9afcfdb9
commit 104697ec40

@ -105,15 +105,11 @@ class ATmega: public kaleidoscope::driver::keyscanner::Base<_KeyScannerProps> {
OUTPUT_TOGGLE(_KeyScannerProps::matrix_row_pins[current_row]); OUTPUT_TOGGLE(_KeyScannerProps::matrix_row_pins[current_row]);
any_debounced_changes |= debounce(hot_pins, &matrix_state_[current_row].debouncer); matrix_state_[current_row].current ^=
debounce(hot_pins, matrix_state_[current_row].current, &matrix_state_[current_row].debouncer);
if (any_debounced_changes) {
for (uint8_t current_row = 0; current_row < _KeyScannerProps::matrix_rows; current_row++) {
matrix_state_[current_row].current = matrix_state_[current_row].debouncer.debounced_state;
}
}
} }
} }
void scanMatrix() { void scanMatrix() {
if (do_scan_) { if (do_scan_) {
do_scan_ = false; do_scan_ = false;
@ -164,15 +160,14 @@ class ATmega: public kaleidoscope::driver::keyscanner::Base<_KeyScannerProps> {
protected: protected:
/* /*
each of these variables are storing the state for a row of keys Each of these variables is storing the state for a row of keys.
So for key 0, the last scan state is in raw[0], and the number of
so for key 0, the counter is represented by db0[0] and db1[0] consecutive scans with key 0 in that same state is (n1[0] << 1) | n0[0].
and the state in debounced_state[0].
*/ */
struct debounce_t { struct debounce_t {
typename _KeyScannerProps::RowState db0; // counter bit 0 typename _KeyScannerProps::RowState n0; // consecutive scans % 1
typename _KeyScannerProps::RowState db1; // counter bit 1 typename _KeyScannerProps::RowState n1; // consecutive scans % 2
typename _KeyScannerProps::RowState debounced_state; // debounced state typename _KeyScannerProps::RowState raw; // last key state
}; };
struct row_state_t { struct row_state_t {
@ -209,29 +204,44 @@ class ATmega: public kaleidoscope::driver::keyscanner::Base<_KeyScannerProps> {
return hot_pins; return hot_pins;
} }
/*
* Returns a row with bits set wherever a key's debounced state has changed.
*
* Changes are reported eagerly: if the state is stable and a new change is
* detected, immediately report that change. Whenever the raw state changes,
* the counter is reset.
*/
static inline typename _KeyScannerProps::RowState debounce( static inline typename _KeyScannerProps::RowState debounce(
typename _KeyScannerProps::RowState sample, debounce_t *debouncer typename _KeyScannerProps::RowState sample,
typename _KeyScannerProps::RowState current,
debounce_t *db
) { ) {
typename _KeyScannerProps::RowState delta, changes; // If the counter for a key is non-zero, it is still in a cooldown phase.
typename _KeyScannerProps::RowState unstable = db->n0 | db->n1;
// Use xor to detect changes from last reported state:
// if a key has changed, its bit will be 1, otherwise 0
typename _KeyScannerProps::RowState delta = sample ^ current;
// Use xor to detect changes from last stable state: // Ignore any keys in their cooldown phase.
// if a key has changed, it's bit will be 1, otherwise 0 delta &= ~unstable;
delta = sample ^ debouncer->debounced_state;
// Increment counters and reset any unchanged bits: // Reset cooldown counter on any changed (raw) keys to 0.
// increment bit 1 for all changed keys typename _KeyScannerProps::RowState changed = sample ^ db->raw;
debouncer->db1 = ((debouncer->db1) ^ (debouncer->db0)) & delta; unstable |= changed;
// increment bit 0 for all changed keys db->n1 &= ~changed;
debouncer->db0 = ~(debouncer->db0) & delta; db->n0 &= ~changed;
// Calculate returned change set: if delta is still true // Increment cooldown counters for keys that are unstable:
// and the counter has wrapped back to 0, the key is changed. // n1 = (n + 1) % 2
db->n1 = (db->n1 ^ db->n0) & unstable;
// n0 = (n + 1) % 1
db->n0 = ~db->n0 & unstable;
changes = ~(~delta | (debouncer->db0) | (debouncer->db1)); // Save the raw sample for the next scan.
// Update state: in this case use xor to flip any bit that is true in changes. db->raw = sample;
debouncer->debounced_state ^= changes;
return changes; return delta;
} }
}; };
#else // ifndef KALEIDOSCOPE_VIRTUAL_BUILD #else // ifndef KALEIDOSCOPE_VIRTUAL_BUILD

Loading…
Cancel
Save