f946dc6893
Switched the GPIO matrix driver to debouncing using a simple integrator algorithm. Whenever a key is pressed, we now scan at a rate controlled by debounce-scan-period-ms (default 1 ms) until all keys are released, then return to either waiting for an interrupt or polling more slowly. The timers for key press and release can now be controlled separately, so debounce-period is deprecated in favor of debounce-press-ms and debounce-release-ms. Global Kconfig options ZMK_KSCAN_DEBOUNCE_PRESS_MS and ZMK_KSCAN_DEBOUNCE_RELEASE_MS are also added to make these easier to set. Added documentation for debouncing options.
62 lines
No EOL
1.9 KiB
C
62 lines
No EOL
1.9 KiB
C
/*
|
|
* Copyright (c) 2021 The ZMK Contributors
|
|
*
|
|
* SPDX-License-Identifier: MIT
|
|
*/
|
|
|
|
#include "debounce.h"
|
|
|
|
static uint32_t get_threshold(const struct debounce_state *state,
|
|
const struct debounce_config *config) {
|
|
return state->pressed ? config->debounce_release_ms : config->debounce_press_ms;
|
|
}
|
|
|
|
static void increment_counter(struct debounce_state *state, const int elapsed_ms) {
|
|
if (state->counter + elapsed_ms > DEBOUNCE_COUNTER_MAX) {
|
|
state->counter = DEBOUNCE_COUNTER_MAX;
|
|
} else {
|
|
state->counter += elapsed_ms;
|
|
}
|
|
}
|
|
|
|
static void decrement_counter(struct debounce_state *state, const int elapsed_ms) {
|
|
if (state->counter < elapsed_ms) {
|
|
state->counter = 0;
|
|
} else {
|
|
state->counter -= elapsed_ms;
|
|
}
|
|
}
|
|
|
|
void debounce_update(struct debounce_state *state, const bool active, const int elapsed_ms,
|
|
const struct debounce_config *config) {
|
|
// This uses a variation of the integrator debouncing described at
|
|
// https://www.kennethkuhn.com/electronics/debounce.c
|
|
// Every update where "active" does not match the current state, we increment
|
|
// a counter, otherwise we decrement it. When the counter reaches a
|
|
// threshold, the state flips and we reset the counter.
|
|
state->changed = false;
|
|
|
|
if (active == state->pressed) {
|
|
decrement_counter(state, elapsed_ms);
|
|
return;
|
|
}
|
|
|
|
const uint32_t flip_threshold = get_threshold(state, config);
|
|
|
|
if (state->counter < flip_threshold) {
|
|
increment_counter(state, elapsed_ms);
|
|
return;
|
|
}
|
|
|
|
state->pressed = !state->pressed;
|
|
state->counter = 0;
|
|
state->changed = true;
|
|
}
|
|
|
|
bool debounce_is_active(const struct debounce_state *state) {
|
|
return state->pressed || state->counter > 0;
|
|
}
|
|
|
|
bool debounce_is_pressed(const struct debounce_state *state) { return state->pressed; }
|
|
|
|
bool debounce_get_changed(const struct debounce_state *state) { return state->changed; } |