Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Debounce refactor / API #3720

Merged
merged 29 commits into from
Feb 15, 2019
Merged
Show file tree
Hide file tree
Changes from 28 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
2758158
Added xeal60 via clone of lets split
alex-ong Aug 12, 2018
c796944
Delete removed other keymaps
alex-ong Aug 12, 2018
714e0da
Basic keymap (no FN). Compiles.
alex-ong Aug 12, 2018
ac9b88e
Removed NP_STAR and NP_SLSH.
alex-ong Aug 12, 2018
3cf7f73
Removed "debounce_algo = manual" in all keyboards with CUSTOM_MATRIX …
alex-ong Aug 29, 2018
4db27a2
Changed order of rules in TMK. Documented feature.
alex-ong Aug 29, 2018
e8e6268
Fixed missing whitespace in debounce documentation
alex-ong Aug 29, 2018
a55c838
Added bold in a few areas.
alex-ong Aug 29, 2018
47c91fc
Merge branch 'master' of https://github.com/qmk/qmk_firmware
alex-ong Jan 4, 2019
2bb2977
Merge branch 'master' into debounce_refactor
alex-ong Jan 4, 2019
d977daa
Merge branch 'master' of https://github.com/qmk/qmk_firmware
alex-ong Jan 26, 2019
c9ba618
DO NOT USE Merge branch 'master' into debounce_refactor
alex-ong Jan 26, 2019
39ca330
DO NOT USE - Removed debounce from TMK.
alex-ong Jan 26, 2019
3949ab3
Remove accidental xeal60 commit
alex-ong Jan 26, 2019
d0b691d
DO NOT USE - debounce successfully compiled.
alex-ong Jan 26, 2019
123608f
DO NOT USE Revert back to original API to support split_keyboards.
alex-ong Jan 26, 2019
4d87335
Working eager_pk
alex-ong Jan 26, 2019
574fc64
Whitespace cleanup.
alex-ong Jan 26, 2019
5b7fc75
Restored debounce.h since there wasnt any real change.
alex-ong Jan 26, 2019
14ed96a
Moved debouncing_time variable to inside #if debounce
alex-ong Jan 26, 2019
cce8dfa
Removed check for custom_matrix. We can safely include the debounce f…
alex-ong Jan 26, 2019
b5b1195
Removed #include "matrix.h" from debounce.h
alex-ong Jan 26, 2019
7cb8d3c
Bug fix - was using MATRIX_ROWS instead of num_rows
alex-ong Jan 26, 2019
039dde3
Fixed compilation error with debounce_sym_g
alex-ong Jan 26, 2019
d30d5ee
Renamed DEBOUNCE_ALGO to DEBOUNCE_TYPE
alex-ong Jan 26, 2019
10cc423
Malloc array in debounce_eager_pk, since split keyboards only use MAT…
alex-ong Jan 26, 2019
503e02d
Merge branch 'debounce_refactor' of https://github.com/alex-ong/qmk_f…
alex-ong Jan 26, 2019
562c0d7
Fix compile error in debounce_eager_pk
alex-ong Jan 26, 2019
7d8c629
Stricter, leaner DEBOUNCE_TYPE section in common_features.mk. Cleanup…
alex-ong Jan 26, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 12 additions & 3 deletions common_features.mk
Original file line number Diff line number Diff line change
Expand Up @@ -263,11 +263,20 @@ ifneq ($(strip $(CUSTOM_MATRIX)), yes)
endif
endif

# Include the standard debounce code if needed
ifneq ($(strip $(CUSTOM_DEBOUNCE)), yes)
QUANTUM_SRC += $(QUANTUM_DIR)/debounce.c
DEBOUNCE_DIR:= $(QUANTUM_DIR)/debounce
# Debounce Modules. If implemented in matrix.c, don't use these.
ifeq ($(strip $(DEBOUNCE_TYPE)), custom)
alex-ong marked this conversation as resolved.
Show resolved Hide resolved
# Do nothing. do your debouncing in matrix.c
else 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
else # default algorithm. Won't be used if we have a custom_matrix that doesn't utilize it
QUANTUM_SRC += $(DEBOUNCE_DIR)/debounce_sym_g.c
endif



ifeq ($(strip $(SPLIT_KEYBOARD)), yes)
OPT_DEFS += -DSPLIT_KEYBOARD

Expand Down
44 changes: 44 additions & 0 deletions docs/feature_debounce_algo.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# 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

```
ifeq ($(strip $(DEBOUNCE_ALGO)), manual)
alex-ong marked this conversation as resolved.
Show resolved Hide resolved
# Do nothing. do your debouncing in matrix.c
else ifeq ($(strip $(DEBOUNCE_ALGO)), sym_g)
alex-ong marked this conversation as resolved.
Show resolved Hide resolved
QUANTUM_SRC += $(DEBOUNCE)/debounce_sym_g.c
else ifeq ($(strip $(DEBOUNCE_ALGO)), eager_pk)
alex-ong marked this conversation as resolved.
Show resolved Hide resolved
QUANTUM_SRC += $(DEBOUNCE)/debounce_eager_pk.c
else # default algorithm
QUANTUM_SRC += $(DEBOUNCE)/debounce_sym_g.c
endif
```

# Debounce selection

| DEBOUNCE_ALGO | Description | What to do |
alex-ong marked this conversation as resolved.
Show resolved Hide resolved
| ------------- | --------------------------------------------------- | ----------------------------- |
| Not defined | You are using the included matrix.c and debounce.c | Nothing. Debounce_sym_g will be compiled, and used if necessary |
| manual | 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_ALGO = manual```.
alex-ong marked this conversation as resolved.
Show resolved Hide resolved
* 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.

# 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.


2 changes: 1 addition & 1 deletion keyboards/handwired/xealous/rules.mk
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ SUBPROJECT_rev1 = yes
SLEEP_LED_ENABLE = no # Breathing sleep LED during USB suspend

CUSTOM_MATRIX = no
CUSTOM_DEBOUNCE = yes
DEBOUNCE_TYPE = custom

LAYOUTS = split60

Expand Down
52 changes: 0 additions & 52 deletions quantum/debounce.c

This file was deleted.

2 changes: 1 addition & 1 deletion quantum/debounce.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ void debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool

bool debounce_active(void);

void debounce_init(uint8_t num_rows);
void debounce_init(uint8_t num_rows);
121 changes: 121 additions & 0 deletions quantum/debounce/debounce_eager_pk.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
/*
Copyright 2017 Alex Ong<[email protected]>
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;
}

57 changes: 57 additions & 0 deletions quantum/debounce/debounce_sym_g.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
Copyright 2017 Alex Ong<[email protected]>
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;
}

28 changes: 28 additions & 0 deletions quantum/debounce/readme.md
Original file line number Diff line number Diff line change
@@ -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!
31 changes: 3 additions & 28 deletions quantum/matrix.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,8 @@ static const pin_t col_pins[MATRIX_COLS] = MATRIX_COL_PINS;
#endif

/* matrix state(1:on, 0:off) */
static matrix_row_t raw_matrix[MATRIX_ROWS];

static matrix_row_t matrix[MATRIX_ROWS];

static matrix_row_t raw_matrix[MATRIX_ROWS]; //raw values
static matrix_row_t matrix[MATRIX_ROWS]; //debounced values

#if (DIODE_DIRECTION == COL2ROW)
static void init_cols(void);
Expand Down Expand Up @@ -108,30 +106,6 @@ uint8_t matrix_cols(void) {
return MATRIX_COLS;
}

// void matrix_power_up(void) {
// #if (DIODE_DIRECTION == COL2ROW)
// for (int8_t r = MATRIX_ROWS - 1; r >= 0; --r) {
// /* DDRxn */
// _SFR_IO8((row_pins[r] >> 4) + 1) |= _BV(row_pins[r] & 0xF);
// toggle_row(r);
// }
// for (int8_t c = MATRIX_COLS - 1; c >= 0; --c) {
// /* PORTxn */
// _SFR_IO8((col_pins[c] >> 4) + 2) |= _BV(col_pins[c] & 0xF);
// }
// #elif (DIODE_DIRECTION == ROW2COL)
// for (int8_t c = MATRIX_COLS - 1; c >= 0; --c) {
// /* DDRxn */
// _SFR_IO8((col_pins[c] >> 4) + 1) |= _BV(col_pins[c] & 0xF);
// toggle_col(c);
// }
// for (int8_t r = MATRIX_ROWS - 1; r >= 0; --r) {
// /* PORTxn */
// _SFR_IO8((row_pins[r] >> 4) + 2) |= _BV(row_pins[r] & 0xF);
// }
// #endif
// }

void matrix_init(void) {

// initialize row and col
Expand Down Expand Up @@ -175,6 +149,7 @@ uint8_t matrix_scan(void)
return 1;
}

//Deprecated.
bool matrix_is_modified(void)
{
if (debounce_active()) return false;
Expand Down
Loading