diff options
| -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) \ |
