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