2019-01-26 12:03:46 +06:00
|
|
|
/*
|
|
|
|
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"
|
2019-01-26 19:10:14 +06:00
|
|
|
#include "quantum.h"
|
2019-01-26 18:18:24 +06:00
|
|
|
#include <stdlib.h>
|
2019-01-26 12:03:46 +06:00
|
|
|
|
|
|
|
#ifndef DEBOUNCE
|
2019-08-31 00:19:03 +06:00
|
|
|
# define DEBOUNCE 5
|
2019-01-26 12:03:46 +06:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#if (MATRIX_COLS <= 8)
|
2019-08-31 00:19:03 +06:00
|
|
|
# define ROW_SHIFTER ((uint8_t)1)
|
2019-01-26 12:03:46 +06:00
|
|
|
#elif (MATRIX_COLS <= 16)
|
2019-08-31 00:19:03 +06:00
|
|
|
# define ROW_SHIFTER ((uint16_t)1)
|
2019-01-26 12:03:46 +06:00
|
|
|
#elif (MATRIX_COLS <= 32)
|
2019-08-31 00:19:03 +06:00
|
|
|
# define ROW_SHIFTER ((uint32_t)1)
|
2019-01-26 12:03:46 +06:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#define debounce_counter_t uint8_t
|
|
|
|
|
2019-01-26 18:18:24 +06:00
|
|
|
static debounce_counter_t *debounce_counters;
|
2019-04-16 01:58:03 +06:00
|
|
|
static bool counters_need_update;
|
2019-07-10 00:09:54 +06:00
|
|
|
static bool matrix_need_update;
|
2019-01-26 12:03:46 +06:00
|
|
|
|
|
|
|
#define DEBOUNCE_ELAPSED 251
|
|
|
|
#define MAX_DEBOUNCE (DEBOUNCE_ELAPSED - 1)
|
|
|
|
|
Various fixes to how timer differences are calculated (#8585)
* tmk_core/common: Fixing TIMER_DIFF macro to calculate difference correctly after the timer wraps.
Let's go through an example, using the following macro:
If the first timer read is 0xe4 and the second one is 0x32, the timer wrapped.
If the timer would have had more bits, it's new value would have been 0x132,
and the correct difference in time is 0x132 - 0xe4 = 0x4e
old code TIMER_DIFF_8(0x32, 0xe4) = 0xff - 0xe4 + 0x32 = 0x4d, which is wrong.
new code TIMER_DIFF_8(0x32, 0xe4) = 0xff + 1 - 0xe4 + 0x32 = 0x4e, which is correct.
This also gives a chance for a smart compiler to optimize the code using normal
integer overflow.
For example on AVR, the following C code:
uint8_t __attribute__ ((noinline)) test(uint8_t current_timer, uint8_t start_timer)
{
return TIMER_DIFF_8(current_timer, start_timer);
}
With the original code, it gets translated to the following list of instructions:
00004c6e <test>:
4c6e: 98 2f mov r25, r24
4c70: 86 1b sub r24, r22
4c72: 96 17 cp r25, r22
4c74: 08 f4 brcc .+2 ; 0x4c78 <test+0xa>
4c76: 81 50 subi r24, 0x01 ; 1
4c78: 08 95 ret
But with this commit, it gets translated to a single instruction:
00004c40 <test>:
4c40: 86 1b sub r24, r22
4c42: 08 95 ret
This unfortunately doesn't always work so nicely, for example the following C code:
int __attribute__ ((noinline)) test(uint8_t current_timer, uint8_t start_timer)
{
return TIMER_DIFF_8(current_timer, start_timer);
}
(Note: return type changed to int)
With the original code it gets translated to:
00004c6e <test>:
4c6e: 28 2f mov r18, r24
4c70: 30 e0 ldi r19, 0x00 ; 0
4c72: 46 2f mov r20, r22
4c74: 50 e0 ldi r21, 0x00 ; 0
4c76: 86 17 cp r24, r22
4c78: 20 f0 brcs .+8 ; 0x4c82 <test+0x14>
4c7a: c9 01 movw r24, r18
4c7c: 84 1b sub r24, r20
4c7e: 95 0b sbc r25, r21
4c80: 08 95 ret
4c82: c9 01 movw r24, r18
4c84: 84 1b sub r24, r20
4c86: 95 0b sbc r25, r21
4c88: 81 50 subi r24, 0x01 ; 1
4c8a: 9f 4f sbci r25, 0xFF ; 255
4c8c: 08 95 ret
Wth this commit it gets translated to:
00004c40 <test>:
4c40: 28 2f mov r18, r24
4c42: 30 e0 ldi r19, 0x00 ; 0
4c44: 46 2f mov r20, r22
4c46: 50 e0 ldi r21, 0x00 ; 0
4c48: 86 17 cp r24, r22
4c4a: 20 f0 brcs .+8 ; 0x4c54 <test+0x14>
4c4c: c9 01 movw r24, r18
4c4e: 84 1b sub r24, r20
4c50: 95 0b sbc r25, r21
4c52: 08 95 ret
4c54: c9 01 movw r24, r18
4c56: 84 1b sub r24, r20
4c58: 95 0b sbc r25, r21
4c5a: 93 95 inc r25
4c5c: 08 95 ret
There is not much performance improvement in this case, however at least with this
commit it functions correctly.
Note: The following commit will improve compiler output for the latter example.
* tmk_core/common: Improve code generation for TIMER_DIFF* macros
Because of integer promotion the compiler is having a hard time generating
efficient code to calculate TIMER_DIFF* macros in some situations.
In the below example, the return value is "int", and this is causing the
trouble.
Example C code:
int __attribute__ ((noinline)) test(uint8_t current_timer, uint8_t start_timer)
{
return TIMER_DIFF_8(current_timer, start_timer);
}
BEFORE: (with -Os)
00004c40 <test>:
4c40: 28 2f mov r18, r24
4c42: 30 e0 ldi r19, 0x00 ; 0
4c44: 46 2f mov r20, r22
4c46: 50 e0 ldi r21, 0x00 ; 0
4c48: 86 17 cp r24, r22
4c4a: 20 f0 brcs .+8 ; 0x4c54 <test+0x14>
4c4c: c9 01 movw r24, r18
4c4e: 84 1b sub r24, r20
4c50: 95 0b sbc r25, r21
4c52: 08 95 ret
4c54: c9 01 movw r24, r18
4c56: 84 1b sub r24, r20
4c58: 95 0b sbc r25, r21
4c5a: 93 95 inc r25
4c5c: 08 95 ret
AFTER: (with -Os)
00004c40 <test>:
4c40: 86 1b sub r24, r22
4c42: 90 e0 ldi r25, 0x00 ; 0
4c44: 08 95 ret
Note: the example is showing -Os but improvements can be seen at all optimization levels,
including -O0. We never use -O0, but I tested it to make sure that no extra code is
generated in that case.OA
* quantum/debounce: Fix custom wrapping timers in eager_pr and eager_pk debounce algorithms
Please see the below simulated sequence of events:
Column A is the 16-bit value returned by read_timer();
Column B is the value returned by custom_wrap_timer_read();
Column C is the original code: (timer_read() % MAX_DEBOUNCE)
A, B, C
65530, 19, 30
65531, 20, 31
65532, 21, 32
65533, 22, 33
65534, 23, 34
65535, 24, 35
0 25, 0
1, 26, 1
2, 27, 2
3, 28, 3
4, 29, 4
5, 30, 5
read_timer() wraps about every 1.09 seconds, and so debouncing might
fail at these times without this commit.
* quantum/debounce/eager_pr and eager_pk: modifications for code readability according to code review.
* quantum/debounce/eager_pr and eager_pk: modifications for code readability according to code review. (2)
2020-04-11 06:14:28 +06:00
|
|
|
static uint8_t wrapping_timer_read(void) {
|
|
|
|
static uint16_t time = 0;
|
|
|
|
static uint8_t last_result = 0;
|
|
|
|
uint16_t new_time = timer_read();
|
|
|
|
uint16_t diff = new_time - time;
|
|
|
|
time = new_time;
|
|
|
|
last_result = (last_result + diff) % (MAX_DEBOUNCE + 1);
|
|
|
|
return last_result;
|
|
|
|
}
|
|
|
|
|
2019-01-26 12:29:02 +06:00
|
|
|
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);
|
2019-01-26 12:03:46 +06:00
|
|
|
|
2019-04-16 01:58:03 +06:00
|
|
|
// we use num_rows rather than MATRIX_ROWS to support split keyboards
|
|
|
|
void debounce_init(uint8_t num_rows) {
|
2019-08-31 00:19:03 +06:00
|
|
|
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;
|
|
|
|
}
|
2019-01-26 12:03:46 +06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-16 01:58:03 +06:00
|
|
|
void debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) {
|
Various fixes to how timer differences are calculated (#8585)
* tmk_core/common: Fixing TIMER_DIFF macro to calculate difference correctly after the timer wraps.
Let's go through an example, using the following macro:
If the first timer read is 0xe4 and the second one is 0x32, the timer wrapped.
If the timer would have had more bits, it's new value would have been 0x132,
and the correct difference in time is 0x132 - 0xe4 = 0x4e
old code TIMER_DIFF_8(0x32, 0xe4) = 0xff - 0xe4 + 0x32 = 0x4d, which is wrong.
new code TIMER_DIFF_8(0x32, 0xe4) = 0xff + 1 - 0xe4 + 0x32 = 0x4e, which is correct.
This also gives a chance for a smart compiler to optimize the code using normal
integer overflow.
For example on AVR, the following C code:
uint8_t __attribute__ ((noinline)) test(uint8_t current_timer, uint8_t start_timer)
{
return TIMER_DIFF_8(current_timer, start_timer);
}
With the original code, it gets translated to the following list of instructions:
00004c6e <test>:
4c6e: 98 2f mov r25, r24
4c70: 86 1b sub r24, r22
4c72: 96 17 cp r25, r22
4c74: 08 f4 brcc .+2 ; 0x4c78 <test+0xa>
4c76: 81 50 subi r24, 0x01 ; 1
4c78: 08 95 ret
But with this commit, it gets translated to a single instruction:
00004c40 <test>:
4c40: 86 1b sub r24, r22
4c42: 08 95 ret
This unfortunately doesn't always work so nicely, for example the following C code:
int __attribute__ ((noinline)) test(uint8_t current_timer, uint8_t start_timer)
{
return TIMER_DIFF_8(current_timer, start_timer);
}
(Note: return type changed to int)
With the original code it gets translated to:
00004c6e <test>:
4c6e: 28 2f mov r18, r24
4c70: 30 e0 ldi r19, 0x00 ; 0
4c72: 46 2f mov r20, r22
4c74: 50 e0 ldi r21, 0x00 ; 0
4c76: 86 17 cp r24, r22
4c78: 20 f0 brcs .+8 ; 0x4c82 <test+0x14>
4c7a: c9 01 movw r24, r18
4c7c: 84 1b sub r24, r20
4c7e: 95 0b sbc r25, r21
4c80: 08 95 ret
4c82: c9 01 movw r24, r18
4c84: 84 1b sub r24, r20
4c86: 95 0b sbc r25, r21
4c88: 81 50 subi r24, 0x01 ; 1
4c8a: 9f 4f sbci r25, 0xFF ; 255
4c8c: 08 95 ret
Wth this commit it gets translated to:
00004c40 <test>:
4c40: 28 2f mov r18, r24
4c42: 30 e0 ldi r19, 0x00 ; 0
4c44: 46 2f mov r20, r22
4c46: 50 e0 ldi r21, 0x00 ; 0
4c48: 86 17 cp r24, r22
4c4a: 20 f0 brcs .+8 ; 0x4c54 <test+0x14>
4c4c: c9 01 movw r24, r18
4c4e: 84 1b sub r24, r20
4c50: 95 0b sbc r25, r21
4c52: 08 95 ret
4c54: c9 01 movw r24, r18
4c56: 84 1b sub r24, r20
4c58: 95 0b sbc r25, r21
4c5a: 93 95 inc r25
4c5c: 08 95 ret
There is not much performance improvement in this case, however at least with this
commit it functions correctly.
Note: The following commit will improve compiler output for the latter example.
* tmk_core/common: Improve code generation for TIMER_DIFF* macros
Because of integer promotion the compiler is having a hard time generating
efficient code to calculate TIMER_DIFF* macros in some situations.
In the below example, the return value is "int", and this is causing the
trouble.
Example C code:
int __attribute__ ((noinline)) test(uint8_t current_timer, uint8_t start_timer)
{
return TIMER_DIFF_8(current_timer, start_timer);
}
BEFORE: (with -Os)
00004c40 <test>:
4c40: 28 2f mov r18, r24
4c42: 30 e0 ldi r19, 0x00 ; 0
4c44: 46 2f mov r20, r22
4c46: 50 e0 ldi r21, 0x00 ; 0
4c48: 86 17 cp r24, r22
4c4a: 20 f0 brcs .+8 ; 0x4c54 <test+0x14>
4c4c: c9 01 movw r24, r18
4c4e: 84 1b sub r24, r20
4c50: 95 0b sbc r25, r21
4c52: 08 95 ret
4c54: c9 01 movw r24, r18
4c56: 84 1b sub r24, r20
4c58: 95 0b sbc r25, r21
4c5a: 93 95 inc r25
4c5c: 08 95 ret
AFTER: (with -Os)
00004c40 <test>:
4c40: 86 1b sub r24, r22
4c42: 90 e0 ldi r25, 0x00 ; 0
4c44: 08 95 ret
Note: the example is showing -Os but improvements can be seen at all optimization levels,
including -O0. We never use -O0, but I tested it to make sure that no extra code is
generated in that case.OA
* quantum/debounce: Fix custom wrapping timers in eager_pr and eager_pk debounce algorithms
Please see the below simulated sequence of events:
Column A is the 16-bit value returned by read_timer();
Column B is the value returned by custom_wrap_timer_read();
Column C is the original code: (timer_read() % MAX_DEBOUNCE)
A, B, C
65530, 19, 30
65531, 20, 31
65532, 21, 32
65533, 22, 33
65534, 23, 34
65535, 24, 35
0 25, 0
1, 26, 1
2, 27, 2
3, 28, 3
4, 29, 4
5, 30, 5
read_timer() wraps about every 1.09 seconds, and so debouncing might
fail at these times without this commit.
* quantum/debounce/eager_pr and eager_pk: modifications for code readability according to code review.
* quantum/debounce/eager_pr and eager_pk: modifications for code readability according to code review. (2)
2020-04-11 06:14:28 +06:00
|
|
|
uint8_t current_time = wrapping_timer_read();
|
2019-08-31 00:19:03 +06:00
|
|
|
if (counters_need_update) {
|
|
|
|
update_debounce_counters(num_rows, current_time);
|
|
|
|
}
|
2019-04-16 01:58:03 +06:00
|
|
|
|
2019-08-31 00:19:03 +06:00
|
|
|
if (changed || matrix_need_update) {
|
|
|
|
transfer_matrix_values(raw, cooked, num_rows, current_time);
|
|
|
|
}
|
2019-01-26 12:03:46 +06:00
|
|
|
}
|
|
|
|
|
2019-04-16 01:58:03 +06:00
|
|
|
// 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) {
|
2019-08-31 00:19:03 +06:00
|
|
|
counters_need_update = false;
|
|
|
|
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;
|
|
|
|
} else {
|
|
|
|
counters_need_update = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
debounce_pointer++;
|
2019-01-26 12:03:46 +06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// upload from raw_matrix to final matrix;
|
2019-04-16 01:58:03 +06:00
|
|
|
void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, uint8_t current_time) {
|
2019-08-31 00:19:03 +06:00
|
|
|
matrix_need_update = false;
|
|
|
|
debounce_counter_t *debounce_pointer = debounce_counters;
|
|
|
|
for (uint8_t row = 0; row < num_rows; row++) {
|
|
|
|
matrix_row_t delta = raw[row] ^ cooked[row];
|
|
|
|
matrix_row_t existing_row = cooked[row];
|
|
|
|
for (uint8_t col = 0; col < MATRIX_COLS; col++) {
|
|
|
|
matrix_row_t col_mask = (ROW_SHIFTER << col);
|
|
|
|
if (delta & col_mask) {
|
|
|
|
if (*debounce_pointer == DEBOUNCE_ELAPSED) {
|
|
|
|
*debounce_pointer = current_time;
|
|
|
|
counters_need_update = true;
|
|
|
|
existing_row ^= col_mask; // flip the bit.
|
|
|
|
} else {
|
|
|
|
matrix_need_update = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
debounce_pointer++;
|
2019-07-10 00:09:54 +06:00
|
|
|
}
|
2019-08-31 00:19:03 +06:00
|
|
|
cooked[row] = existing_row;
|
2019-01-26 12:03:46 +06:00
|
|
|
}
|
2019-01-26 12:29:02 +06:00
|
|
|
}
|
2019-01-26 12:03:46 +06:00
|
|
|
|
2019-04-16 01:58:03 +06:00
|
|
|
bool debounce_active(void) { return true; }
|