aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTakeshi ISHII <2170248+mtei@users.noreply.github.com>2021-01-13 10:46:22 +0900
committerGitHub <noreply@github.com>2021-01-13 12:46:22 +1100
commit302b35c2a0ac90208e523944e8cc4b44a793d8d5 (patch)
tree473bf6d47b42125027fde59c409971b0b1c925c6
parent017aa5988af308ae6d585b4afea6f28c28e2d238 (diff)
downloadqmk_firmware-302b35c2a0ac90208e523944e8cc4b44a793d8d5.tar.gz
qmk_firmware-302b35c2a0ac90208e523944e8cc4b44a793d8d5.zip
fix matrix_io_delay() timing in quantum/matrix.c (#9603)
* fix matrix_io_delay() timing in quantum/matrix.c * Updated comments explaining the need for matrix_io_delay() in quantum/matrix.c * fix matrix_io_delay() timing in quantum/split_common/matrix.c * Update quantum/matrix.c Co-authored-by: Ryan <fauxpark@gmail.com> * Update quantum/split_common/matrix.c Co-authored-by: Ryan <fauxpark@gmail.com> * Update quantum/matrix.c Co-authored-by: Ryan <fauxpark@gmail.com> * Update quantum/split_common/matrix.c Co-authored-by: Ryan <fauxpark@gmail.com> * add waitOutputPinValid() and wait_cpuclock() into quantum/quantum.h and tmk_core/common/wait.h * add matrix_output_select_delay() and matrix_output_unselect_delay() * fix quantum/matrix_common.c, tmk_core/common/matrix.h * fix tmk_core/common/wait.h * fix quantum/quantum.h, tmk_core/common/wait.h * waitOutputPinValid() rename to waitInputPinDelay() in quantum/quantum.h. * waitOutputPinValid() rename to waitInputPinDelay() in quantum/matrix_common.c * update tmk_core/common/wait.h * update comment in quantum/matrix.c, quantum/split_common/matrix.c * update quantum/quantum.h: Make more margin in the GPIO_INPUT_PIN_DELAY default value. Co-authored-by: Ryan <fauxpark@gmail.com>
-rw-r--r--quantum/matrix.c14
-rw-r--r--quantum/matrix_common.c5
-rw-r--r--quantum/quantum.h29
-rw-r--r--quantum/split_common/matrix.c14
-rw-r--r--tmk_core/common/matrix.h3
-rw-r--r--tmk_core/common/wait.h52
6 files changed, 109 insertions, 8 deletions
diff --git a/quantum/matrix.c b/quantum/matrix.c
index 9083ff386..c027b7bf2 100644
--- a/quantum/matrix.c
+++ b/quantum/matrix.c
@@ -101,9 +101,9 @@ static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row)
101 // Start with a clear matrix row 101 // Start with a clear matrix row
102 matrix_row_t current_row_value = 0; 102 matrix_row_t current_row_value = 0;
103 103
104 // Select row and wait for row selecton to stabilize 104 // Select row
105 select_row(current_row); 105 select_row(current_row);
106 matrix_io_delay(); 106 matrix_output_select_delay();
107 107
108 // For each col... 108 // For each col...
109 for (uint8_t col_index = 0; col_index < MATRIX_COLS; col_index++) { 109 for (uint8_t col_index = 0; col_index < MATRIX_COLS; col_index++) {
@@ -116,6 +116,9 @@ static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row)
116 116
117 // Unselect row 117 // Unselect row
118 unselect_row(current_row); 118 unselect_row(current_row);
119 if (current_row + 1 < MATRIX_ROWS) {
120 matrix_output_unselect_delay(); // wait for row signal to go HIGH
121 }
119 122
120 // If the row has changed, store the row and return the changed flag. 123 // If the row has changed, store the row and return the changed flag.
121 if (current_matrix[current_row] != current_row_value) { 124 if (current_matrix[current_row] != current_row_value) {
@@ -147,9 +150,9 @@ static void init_pins(void) {
147static bool read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col) { 150static bool read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col) {
148 bool matrix_changed = false; 151 bool matrix_changed = false;
149 152
150 // Select col and wait for col selecton to stabilize 153 // Select col
151 select_col(current_col); 154 select_col(current_col);
152 matrix_io_delay(); 155 matrix_output_select_delay();
153 156
154 // For each row... 157 // For each row...
155 for (uint8_t row_index = 0; row_index < MATRIX_ROWS; row_index++) { 158 for (uint8_t row_index = 0; row_index < MATRIX_ROWS; row_index++) {
@@ -175,6 +178,9 @@ static bool read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col)
175 178
176 // Unselect col 179 // Unselect col
177 unselect_col(current_col); 180 unselect_col(current_col);
181 if (current_col + 1 < MATRIX_COLS) {
182 matrix_output_unselect_delay(); // wait for col signal to go HIGH
183 }
178 184
179 return matrix_changed; 185 return matrix_changed;
180} 186}
diff --git a/quantum/matrix_common.c b/quantum/matrix_common.c
index 15f1e0e82..01d2b38e5 100644
--- a/quantum/matrix_common.c
+++ b/quantum/matrix_common.c
@@ -1,3 +1,4 @@
1#include "quantum.h"
1#include "matrix.h" 2#include "matrix.h"
2#include "debounce.h" 3#include "debounce.h"
3#include "wait.h" 4#include "wait.h"
@@ -83,8 +84,12 @@ uint8_t matrix_key_count(void) {
83 return count; 84 return count;
84} 85}
85 86
87/* `matrix_io_delay ()` exists for backwards compatibility. From now on, use matrix_output_unselect_delay(). */
86__attribute__((weak)) void matrix_io_delay(void) { wait_us(MATRIX_IO_DELAY); } 88__attribute__((weak)) void matrix_io_delay(void) { wait_us(MATRIX_IO_DELAY); }
87 89
90__attribute__((weak)) void matrix_output_select_delay(void) { waitInputPinDelay(); }
91__attribute__((weak)) void matrix_output_unselect_delay(void) { matrix_io_delay(); }
92
88// CUSTOM MATRIX 'LITE' 93// CUSTOM MATRIX 'LITE'
89__attribute__((weak)) void matrix_init_custom(void) {} 94__attribute__((weak)) void matrix_init_custom(void) {}
90 95
diff --git a/quantum/quantum.h b/quantum/quantum.h
index 83694c832..d234e6ea0 100644
--- a/quantum/quantum.h
+++ b/quantum/quantum.h
@@ -210,6 +210,13 @@ typedef uint8_t pin_t;
210 210
211# define togglePin(pin) (PORTx_ADDRESS(pin) ^= _BV((pin)&0xF)) 211# define togglePin(pin) (PORTx_ADDRESS(pin) ^= _BV((pin)&0xF))
212 212
213/* The AVR series GPIOs have a one clock read delay for changes in the digital input signal.
214 * But here's more margin to make it two clocks. */
215# if !defined(GPIO_INPUT_PIN_DELAY)
216# define GPIO_INPUT_PIN_DELAY 2
217# endif
218# define waitInputPinDelay() wait_cpuclock(GPIO_INPUT_PIN_DELAY)
219
213#elif defined(PROTOCOL_CHIBIOS) 220#elif defined(PROTOCOL_CHIBIOS)
214typedef ioline_t pin_t; 221typedef ioline_t pin_t;
215 222
@@ -225,6 +232,28 @@ typedef ioline_t pin_t;
225# define readPin(pin) palReadLine(pin) 232# define readPin(pin) palReadLine(pin)
226 233
227# define togglePin(pin) palToggleLine(pin) 234# define togglePin(pin) palToggleLine(pin)
235
236#endif
237
238#if defined(__ARMEL__) || defined(__ARMEB__)
239/* For GPIOs on ARM-based MCUs, the input pins are sampled by the clock of the bus
240 * to which the GPIO is connected.
241 * The connected buses differ depending on the various series of MCUs.
242 * And since the instruction execution clock of the CPU and the bus clock of GPIO are different,
243 * there is a delay of several clocks to read the change of the input signal.
244 *
245 * Define this delay with the GPIO_INPUT_PIN_DELAY macro.
246 * If the GPIO_INPUT_PIN_DELAY macro is not defined, the following default values will be used.
247 * (A fairly large value of 0.25 microseconds is set.)
248 */
249# if !defined(GPIO_INPUT_PIN_DELAY)
250# if defined(STM32_SYSCLK)
251# define GPIO_INPUT_PIN_DELAY (STM32_SYSCLK/1000000L / 4)
252# elif defined(KINETIS_SYSCLK_FREQUENCY)
253# define GPIO_INPUT_PIN_DELAY (KINETIS_SYSCLK_FREQUENCY/1000000L / 4)
254# endif
255# endif
256# define waitInputPinDelay() wait_cpuclock(GPIO_INPUT_PIN_DELAY)
228#endif 257#endif
229 258
230// Atomic macro to help make GPIO and other controls atomic. 259// Atomic macro to help make GPIO and other controls atomic.
diff --git a/quantum/split_common/matrix.c b/quantum/split_common/matrix.c
index 06bab734e..067815c99 100644
--- a/quantum/split_common/matrix.c
+++ b/quantum/split_common/matrix.c
@@ -114,9 +114,9 @@ static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row)
114 // Start with a clear matrix row 114 // Start with a clear matrix row
115 matrix_row_t current_row_value = 0; 115 matrix_row_t current_row_value = 0;
116 116
117 // Select row and wait for row selecton to stabilize 117 // Select row
118 select_row(current_row); 118 select_row(current_row);
119 matrix_io_delay(); 119 matrix_output_select_delay();
120 120
121 // For each col... 121 // For each col...
122 for (uint8_t col_index = 0; col_index < MATRIX_COLS; col_index++) { 122 for (uint8_t col_index = 0; col_index < MATRIX_COLS; col_index++) {
@@ -129,6 +129,9 @@ static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row)
129 129
130 // Unselect row 130 // Unselect row
131 unselect_row(current_row); 131 unselect_row(current_row);
132 if (current_row + 1 < MATRIX_ROWS) {
133 matrix_output_unselect_delay(); // wait for row signal to go HIGH
134 }
132 135
133 // If the row has changed, store the row and return the changed flag. 136 // If the row has changed, store the row and return the changed flag.
134 if (current_matrix[current_row] != current_row_value) { 137 if (current_matrix[current_row] != current_row_value) {
@@ -160,9 +163,9 @@ static void init_pins(void) {
160static bool read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col) { 163static bool read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col) {
161 bool matrix_changed = false; 164 bool matrix_changed = false;
162 165
163 // Select col and wait for col selecton to stabilize 166 // Select col
164 select_col(current_col); 167 select_col(current_col);
165 matrix_io_delay(); 168 matrix_output_select_delay();
166 169
167 // For each row... 170 // For each row...
168 for (uint8_t row_index = 0; row_index < ROWS_PER_HAND; row_index++) { 171 for (uint8_t row_index = 0; row_index < ROWS_PER_HAND; row_index++) {
@@ -188,6 +191,9 @@ static bool read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col)
188 191
189 // Unselect col 192 // Unselect col
190 unselect_col(current_col); 193 unselect_col(current_col);
194 if (current_col + 1 < MATRIX_COLS) {
195 matrix_output_unselect_delay(); // wait for col signal to go HIGH
196 }
191 197
192 return matrix_changed; 198 return matrix_changed;
193} 199}
diff --git a/tmk_core/common/matrix.h b/tmk_core/common/matrix.h
index b570227a3..ce57010a4 100644
--- a/tmk_core/common/matrix.h
+++ b/tmk_core/common/matrix.h
@@ -55,6 +55,9 @@ matrix_row_t matrix_get_row(uint8_t row);
55/* print matrix for debug */ 55/* print matrix for debug */
56void matrix_print(void); 56void matrix_print(void);
57/* delay between changing matrix pin state and reading values */ 57/* delay between changing matrix pin state and reading values */
58void matrix_output_select_delay(void);
59void matrix_output_unselect_delay(void);
60/* only for backwards compatibility. delay between changing matrix pin state and reading values */
58void matrix_io_delay(void); 61void matrix_io_delay(void);
59 62
60/* power control */ 63/* power control */
diff --git a/tmk_core/common/wait.h b/tmk_core/common/wait.h
index 89128e9da..0b3fd755a 100644
--- a/tmk_core/common/wait.h
+++ b/tmk_core/common/wait.h
@@ -6,10 +6,62 @@
6extern "C" { 6extern "C" {
7#endif 7#endif
8 8
9#if defined(__ARMEL__) || defined(__ARMEB__)
10# ifndef __OPTIMIZE__
11# pragma message "Compiler optimizations disabled; wait_cpuclock() won't work as designed"
12# endif
13
14# define wait_cpuclock(x) wait_cpuclock_allnop(x)
15
16# define CLOCK_DELAY_NOP8 "nop\n\t nop\n\t nop\n\t nop\n\t nop\n\t nop\n\t nop\n\t nop\n\t"
17
18__attribute__((always_inline))
19static inline void wait_cpuclock_allnop(unsigned int n) { /* n: 1..135 */
20 /* The argument n must be a constant expression.
21 * That way, compiler optimization will remove unnecessary code. */
22 if (n < 1) { return; }
23 if (n > 8) {
24 unsigned int n8 = n/8;
25 n = n - n8*8;
26 switch (n8) {
27 case 16: asm volatile (CLOCK_DELAY_NOP8::: "memory");
28 case 15: asm volatile (CLOCK_DELAY_NOP8::: "memory");
29 case 14: asm volatile (CLOCK_DELAY_NOP8::: "memory");
30 case 13: asm volatile (CLOCK_DELAY_NOP8::: "memory");
31 case 12: asm volatile (CLOCK_DELAY_NOP8::: "memory");
32 case 11: asm volatile (CLOCK_DELAY_NOP8::: "memory");
33 case 10: asm volatile (CLOCK_DELAY_NOP8::: "memory");
34 case 9: asm volatile (CLOCK_DELAY_NOP8::: "memory");
35 case 8: asm volatile (CLOCK_DELAY_NOP8::: "memory");
36 case 7: asm volatile (CLOCK_DELAY_NOP8::: "memory");
37 case 6: asm volatile (CLOCK_DELAY_NOP8::: "memory");
38 case 5: asm volatile (CLOCK_DELAY_NOP8::: "memory");
39 case 4: asm volatile (CLOCK_DELAY_NOP8::: "memory");
40 case 3: asm volatile (CLOCK_DELAY_NOP8::: "memory");
41 case 2: asm volatile (CLOCK_DELAY_NOP8::: "memory");
42 case 1: asm volatile (CLOCK_DELAY_NOP8::: "memory");
43 case 0: break;
44 }
45 }
46 switch (n) {
47 case 8: asm volatile ("nop"::: "memory");
48 case 7: asm volatile ("nop"::: "memory");
49 case 6: asm volatile ("nop"::: "memory");
50 case 5: asm volatile ("nop"::: "memory");
51 case 4: asm volatile ("nop"::: "memory");
52 case 3: asm volatile ("nop"::: "memory");
53 case 2: asm volatile ("nop"::: "memory");
54 case 1: asm volatile ("nop"::: "memory");
55 case 0: break;
56 }
57}
58#endif
59
9#if defined(__AVR__) 60#if defined(__AVR__)
10# include <util/delay.h> 61# include <util/delay.h>
11# define wait_ms(ms) _delay_ms(ms) 62# define wait_ms(ms) _delay_ms(ms)
12# define wait_us(us) _delay_us(us) 63# define wait_us(us) _delay_us(us)
64# define wait_cpuclock(x) __builtin_avr_delay_cycles(x)
13#elif defined PROTOCOL_CHIBIOS 65#elif defined PROTOCOL_CHIBIOS
14# include <ch.h> 66# include <ch.h>
15# define wait_ms(ms) \ 67# define wait_ms(ms) \