Debounce refactor / API (#3720)
* Added xeal60 via clone of lets split * Delete removed other keymaps * Basic keymap (no FN). Compiles. * Removed NP_STAR and NP_SLSH. * Removed "debounce_algo = manual" in all keyboards with CUSTOM_MATRIX = yes. * Changed order of rules in TMK. Documented feature. * Fixed missing whitespace in debounce documentation Table wasn't working due to missing newline. * Added bold in a few areas. * DO NOT USE - Removed debounce from TMK. * Remove accidental xeal60 commit * DO NOT USE - debounce successfully compiled. * DO NOT USE Revert back to original API to support split_keyboards. * Working eager_pk * Whitespace cleanup. * Restored debounce.h since there wasnt any real change. * Moved debouncing_time variable to inside #if debounce * Removed check for custom_matrix. We can safely include the debounce file for compilation when custom_matrix is used. * Removed #include "matrix.h" from debounce.h * Bug fix - was using MATRIX_ROWS instead of num_rows * Fixed compilation error with debounce_sym_g * Renamed DEBOUNCE_ALGO to DEBOUNCE_TYPE * Malloc array in debounce_eager_pk, since split keyboards only use MATRIX_ROWS/2. * Fix compile error in debounce_eager_pk * Stricter, leaner DEBOUNCE_TYPE section in common_features.mk. Cleanup debounce_type.mkrgb7seg 0.6.280
commit
c22f3ba3a2
@ -0,0 +1,46 @@ |
|||||||
|
# Debounce algorithm |
||||||
|
|
||||||
|
QMK supports multiple debounce algorithms through its debounce API. |
||||||
|
|
||||||
|
The underlying debounce algorithm is determined by which matrix.c file you are using. |
||||||
|
|
||||||
|
The logic for which debounce method called is below. It checks various defines that you have set in rules.mk |
||||||
|
|
||||||
|
``` |
||||||
|
DEBOUNCE_TYPE?= sym_g |
||||||
|
VALID_DEBOUNCE_TYPES := sym_g eager_pk custom |
||||||
|
ifeq ($(filter $(DEBOUNCE_TYPE),$(VALID_DEBOUNCE_TYPES)),) |
||||||
|
$(error DEBOUNCE_TYPE="$(DEBOUNCE_TYPE)" is not a valid debounce algorithm) |
||||||
|
endif |
||||||
|
ifeq ($(strip $(DEBOUNCE_TYPE)), sym_g) |
||||||
|
QUANTUM_SRC += $(DEBOUNCE_DIR)/debounce_sym_g.c |
||||||
|
else ifeq ($(strip $(DEBOUNCE_TYPE)), eager_pk) |
||||||
|
QUANTUM_SRC += $(DEBOUNCE_DIR)/debounce_eager_pk.c |
||||||
|
endif |
||||||
|
``` |
||||||
|
|
||||||
|
# Debounce selection |
||||||
|
|
||||||
|
| DEBOUNCE_ALGO | Description | What to do | |
||||||
|
| ------------- | --------------------------------------------------- | ----------------------------- | |
||||||
|
| Not defined | You are using the included matrix.c and debounce.c | Nothing. Debounce_sym_g will be compiled, and used if necessary | |
||||||
|
| custom | Use your own debounce.c | ```SRC += debounce.c``` add your own debounce.c and implement necessary functions | |
||||||
|
| sym_g / eager_pk | You are using the included matrix.c and debounce.c | Use an alternative debounce algorithm | |
||||||
|
|
||||||
|
**Regarding split keyboards**: |
||||||
|
The debounce code is compatible with split keyboards. |
||||||
|
|
||||||
|
# Use your own debouncing code |
||||||
|
* Set ```DEBOUNCE_TYPE = custom ```. |
||||||
|
* Add ```SRC += debounce.c``` |
||||||
|
* Add your own ```debounce.c```. Look at included ```debounce_sym_g.c```s for sample implementations. |
||||||
|
* Debouncing occurs after every raw matrix scan. |
||||||
|
* Use num_rows rather than MATRIX_ROWS, so that split keyboards are supported correctly. |
||||||
|
|
||||||
|
# Changing between included debouncing methods |
||||||
|
You can either use your own code, by including your own debounce.c, or switch to another included one. |
||||||
|
Included debounce methods are: |
||||||
|
* debounce_eager_pk - debouncing per key. On any state change, response is immediate, followed by ```DEBOUNCE_DELAY``` millseconds of no further input for that key |
||||||
|
* debounce_sym_g - debouncing per keyboard. On any state change, a global timer is set. When ```DEBOUNCE_DELAY``` milliseconds of no changes has occured, all input changes are pushed. |
||||||
|
|
||||||
|
|
@ -1,52 +0,0 @@ |
|||||||
|
|
||||||
#include "matrix.h" |
|
||||||
#include "timer.h" |
|
||||||
#include "quantum.h" |
|
||||||
|
|
||||||
#ifndef DEBOUNCING_DELAY |
|
||||||
# define DEBOUNCING_DELAY 5 |
|
||||||
#endif |
|
||||||
|
|
||||||
void debounce_init(uint8_t num_rows) { |
|
||||||
} |
|
||||||
|
|
||||||
#if DEBOUNCING_DELAY > 0 |
|
||||||
|
|
||||||
static bool debouncing = false; |
|
||||||
|
|
||||||
void debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) { |
|
||||||
static uint16_t debouncing_time; |
|
||||||
|
|
||||||
if (changed) { |
|
||||||
debouncing = true; |
|
||||||
debouncing_time = timer_read(); |
|
||||||
} |
|
||||||
|
|
||||||
if (debouncing && (timer_elapsed(debouncing_time) > DEBOUNCING_DELAY)) { |
|
||||||
for (uint8_t i = 0; i < num_rows; i++) { |
|
||||||
cooked[i] = raw[i]; |
|
||||||
} |
|
||||||
debouncing = false; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
bool debounce_active(void) { |
|
||||||
return debouncing; |
|
||||||
} |
|
||||||
|
|
||||||
#else |
|
||||||
|
|
||||||
// no debounce
|
|
||||||
void debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) { |
|
||||||
if (changed) |
|
||||||
{ |
|
||||||
for (uint8_t i = 0; i < num_rows; i++) { |
|
||||||
cooked[i] = raw[i]; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
bool debounce_active(void) { |
|
||||||
return false; |
|
||||||
} |
|
||||||
#endif |
|
@ -0,0 +1,121 @@ |
|||||||
|
/*
|
||||||
|
Copyright 2017 Alex Ong<the.onga@gmail.com> |
||||||
|
This program is free software: you can redistribute it and/or modify |
||||||
|
it under the terms of the GNU General Public License as published by |
||||||
|
the Free Software Foundation, either version 2 of the License, or |
||||||
|
(at your option) any later version. |
||||||
|
This program is distributed in the hope that it will be useful, |
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
GNU General Public License for more details. |
||||||
|
You should have received a copy of the GNU General Public License |
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/ |
||||||
|
|
||||||
|
/*
|
||||||
|
Basic per-key algorithm. Uses an 8-bit counter per key. |
||||||
|
After pressing a key, it immediately changes state, and sets a counter. |
||||||
|
No further inputs are accepted until DEBOUNCE milliseconds have occurred. |
||||||
|
*/ |
||||||
|
|
||||||
|
#include "matrix.h" |
||||||
|
#include "timer.h" |
||||||
|
#include "quantum.h" |
||||||
|
#include <stdlib.h> |
||||||
|
|
||||||
|
#ifndef DEBOUNCE |
||||||
|
#define DEBOUNCE 5 |
||||||
|
#endif |
||||||
|
|
||||||
|
|
||||||
|
#if (MATRIX_COLS <= 8) |
||||||
|
# define ROW_SHIFTER ((uint8_t)1) |
||||||
|
#elif (MATRIX_COLS <= 16) |
||||||
|
# define ROW_SHIFTER ((uint16_t)1) |
||||||
|
#elif (MATRIX_COLS <= 32) |
||||||
|
# define ROW_SHIFTER ((uint32_t)1) |
||||||
|
#endif |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define debounce_counter_t uint8_t |
||||||
|
|
||||||
|
static debounce_counter_t *debounce_counters; |
||||||
|
|
||||||
|
#define DEBOUNCE_ELAPSED 251 |
||||||
|
#define MAX_DEBOUNCE (DEBOUNCE_ELAPSED - 1) |
||||||
|
|
||||||
|
void update_debounce_counters(uint8_t num_rows, uint8_t current_time); |
||||||
|
void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, uint8_t current_time); |
||||||
|
|
||||||
|
//we use num_rows rather than MATRIX_ROWS to support split keyboards
|
||||||
|
void debounce_init(uint8_t num_rows) |
||||||
|
{ |
||||||
|
debounce_counters = (debounce_counter_t*)malloc(num_rows*MATRIX_COLS * sizeof(debounce_counter_t)); |
||||||
|
int i = 0; |
||||||
|
for (uint8_t r = 0; r < num_rows; r++) |
||||||
|
{ |
||||||
|
for (uint8_t c = 0; c < MATRIX_COLS; c++) |
||||||
|
{ |
||||||
|
debounce_counters[i++] = DEBOUNCE_ELAPSED; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) |
||||||
|
{ |
||||||
|
uint8_t current_time = timer_read() % MAX_DEBOUNCE; |
||||||
|
update_debounce_counters(num_rows, current_time); |
||||||
|
transfer_matrix_values(raw, cooked, num_rows, current_time); |
||||||
|
} |
||||||
|
|
||||||
|
//If the current time is > debounce counter, set the counter to enable input.
|
||||||
|
void update_debounce_counters(uint8_t num_rows, uint8_t current_time) |
||||||
|
{ |
||||||
|
debounce_counter_t *debounce_pointer = debounce_counters; |
||||||
|
for (uint8_t row = 0; row < num_rows; row++) |
||||||
|
{ |
||||||
|
for (uint8_t col = 0; col < MATRIX_COLS; col++) |
||||||
|
{ |
||||||
|
if (*debounce_pointer != DEBOUNCE_ELAPSED) |
||||||
|
{ |
||||||
|
if (TIMER_DIFF(current_time, *debounce_pointer, MAX_DEBOUNCE) >= DEBOUNCE) { |
||||||
|
*debounce_pointer = DEBOUNCE_ELAPSED; |
||||||
|
} |
||||||
|
} |
||||||
|
debounce_pointer++; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// upload from raw_matrix to final matrix;
|
||||||
|
void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, uint8_t current_time) |
||||||
|
{ |
||||||
|
debounce_counter_t *debounce_pointer = debounce_counters; |
||||||
|
for (uint8_t row = 0; row < num_rows; row++) |
||||||
|
{ |
||||||
|
matrix_row_t existing_row = cooked[row];
|
||||||
|
matrix_row_t raw_row = raw[row]; |
||||||
|
|
||||||
|
for (uint8_t col = 0; col < MATRIX_COLS; col++) |
||||||
|
{ |
||||||
|
matrix_row_t col_mask = (ROW_SHIFTER << col); |
||||||
|
bool final_value = raw_row & col_mask; |
||||||
|
bool existing_value = existing_row & col_mask; |
||||||
|
if (*debounce_pointer == DEBOUNCE_ELAPSED && |
||||||
|
(existing_value != final_value)) |
||||||
|
{ |
||||||
|
*debounce_pointer = current_time; |
||||||
|
existing_row ^= col_mask; //flip the bit.
|
||||||
|
} |
||||||
|
debounce_pointer++; |
||||||
|
} |
||||||
|
cooked[row] = existing_row; |
||||||
|
}
|
||||||
|
} |
||||||
|
|
||||||
|
bool debounce_active(void) |
||||||
|
{ |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
@ -0,0 +1,57 @@ |
|||||||
|
/*
|
||||||
|
Copyright 2017 Alex Ong<the.onga@gmail.com> |
||||||
|
This program is free software: you can redistribute it and/or modify |
||||||
|
it under the terms of the GNU General Public License as published by |
||||||
|
the Free Software Foundation, either version 2 of the License, or |
||||||
|
(at your option) any later version. |
||||||
|
This program is distributed in the hope that it will be useful, |
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
GNU General Public License for more details. |
||||||
|
You should have received a copy of the GNU General Public License |
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/ |
||||||
|
|
||||||
|
/*
|
||||||
|
Basic global debounce algorithm. Used in 99% of keyboards at time of implementation |
||||||
|
When no state changes have occured for DEBOUNCE milliseconds, we push the state. |
||||||
|
*/ |
||||||
|
#include "matrix.h" |
||||||
|
#include "timer.h" |
||||||
|
#include "quantum.h" |
||||||
|
#ifndef DEBOUNCE |
||||||
|
#define DEBOUNCE 5 |
||||||
|
#endif |
||||||
|
|
||||||
|
void debounce_init(uint8_t num_rows) {} |
||||||
|
static bool debouncing = false; |
||||||
|
|
||||||
|
#if DEBOUNCE > 0 |
||||||
|
static uint16_t debouncing_time; |
||||||
|
void debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) |
||||||
|
{ |
||||||
|
if (changed) { |
||||||
|
debouncing = true; |
||||||
|
debouncing_time = timer_read(); |
||||||
|
} |
||||||
|
|
||||||
|
if (debouncing && timer_elapsed(debouncing_time) > DEBOUNCE) { |
||||||
|
for (int i = 0; i < num_rows; i++) { |
||||||
|
cooked[i] = raw[i]; |
||||||
|
} |
||||||
|
debouncing = false; |
||||||
|
} |
||||||
|
} |
||||||
|
#else //no debouncing.
|
||||||
|
void debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) |
||||||
|
{ |
||||||
|
for (int i = 0; i < num_rows; i++) { |
||||||
|
cooked[i] = raw[i]; |
||||||
|
} |
||||||
|
} |
||||||
|
#endif |
||||||
|
|
||||||
|
bool debounce_active(void) { |
||||||
|
return debouncing; |
||||||
|
} |
||||||
|
|
@ -0,0 +1,28 @@ |
|||||||
|
Debounce algorithms belong in this folder. |
||||||
|
Here are a few ideas |
||||||
|
|
||||||
|
1) Global vs Per-Key vs Per-Row |
||||||
|
* Global - one timer for all keys. Any key change state affects global timer |
||||||
|
* Per key - one timer per key |
||||||
|
* Per row - one timer per row |
||||||
|
|
||||||
|
2) Eager vs symmetric vs assymetric |
||||||
|
* Eager - any key change is reported immediately. All further inputs for DEBOUNCE ms are ignored. |
||||||
|
* Symmetric - wait for no changes for DEBOUNCE ms before reporting change |
||||||
|
* Assymetric - wait for different times depending on key-down/key-up. E.g. Eager key-down, DEBOUNCE ms key up. |
||||||
|
|
||||||
|
3) Timestamp vs cycles |
||||||
|
* old old old code waits n cycles, decreasing count by one each matrix_scan |
||||||
|
* newer code stores the millisecond the change occurred, and does subraction to figure out time elapsed. |
||||||
|
* Timestamps are superior, i don't think cycles will ever be used again once upgraded. |
||||||
|
|
||||||
|
The default algorithm is symmetric and global. |
||||||
|
Here are a few that could be implemented: |
||||||
|
|
||||||
|
debounce_sym_g.c |
||||||
|
debounce_sym_pk.c |
||||||
|
debounce_sym_pr.c |
||||||
|
debounce_sym_pr_cycles.c //currently used in ergo-dox |
||||||
|
debounce_eager_g.c |
||||||
|
debounce_eager_pk.c |
||||||
|
debounce_eager_pr.c //could be used in ergo-dox! |
Loading…
Reference in new issue