diff options
author | Takeshi ISHII <2170248+mtei@users.noreply.github.com> | 2021-01-13 10:46:22 +0900 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-01-13 12:46:22 +1100 |
commit | 302b35c2a0ac90208e523944e8cc4b44a793d8d5 (patch) | |
tree | 473bf6d47b42125027fde59c409971b0b1c925c6 | |
parent | 017aa5988af308ae6d585b4afea6f28c28e2d238 (diff) | |
download | qmk_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.c | 14 | ||||
-rw-r--r-- | quantum/matrix_common.c | 5 | ||||
-rw-r--r-- | quantum/quantum.h | 29 | ||||
-rw-r--r-- | quantum/split_common/matrix.c | 14 | ||||
-rw-r--r-- | tmk_core/common/matrix.h | 3 | ||||
-rw-r--r-- | tmk_core/common/wait.h | 52 |
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) { | |||
147 | static bool read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col) { | 150 | static 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) |
214 | typedef ioline_t pin_t; | 221 | typedef 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) { | |||
160 | static bool read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col) { | 163 | static 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 */ |
56 | void matrix_print(void); | 56 | void matrix_print(void); |
57 | /* delay between changing matrix pin state and reading values */ | 57 | /* delay between changing matrix pin state and reading values */ |
58 | void matrix_output_select_delay(void); | ||
59 | void matrix_output_unselect_delay(void); | ||
60 | /* only for backwards compatibility. delay between changing matrix pin state and reading values */ | ||
58 | void matrix_io_delay(void); | 61 | void 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 @@ | |||
6 | extern "C" { | 6 | extern "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)) | ||
19 | static 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) \ |