aboutsummaryrefslogtreecommitdiff
path: root/quantum/matrix.c
diff options
context:
space:
mode:
authorEric Tang <e_l_tang@outlook.com>2016-05-23 20:42:21 -0700
committerJack Humbert <jack.humb@gmail.com>2016-05-23 23:42:21 -0400
commitaaa758f1d3f97dda39879f2b055ad2da9680adfe (patch)
treecb0749cda23c0507dd2b230af3eb0ca81a97b8af /quantum/matrix.c
parentd66aa0abf96b5e887250cf0a7fa5e575f18c5a91 (diff)
downloadqmk_firmware-aaa758f1d3f97dda39879f2b055ad2da9680adfe.tar.gz
qmk_firmware-aaa758f1d3f97dda39879f2b055ad2da9680adfe.zip
Optimize matrix scanning (#343)
Diffstat (limited to 'quantum/matrix.c')
-rw-r--r--quantum/matrix.c369
1 files changed, 140 insertions, 229 deletions
diff --git a/quantum/matrix.c b/quantum/matrix.c
index cab39e117..22126aa7a 100644
--- a/quantum/matrix.c
+++ b/quantum/matrix.c
@@ -1,6 +1,6 @@
1/* 1/*
2Copyright 2012 Jun Wako 2Copyright 2012 Jun Wako
3Generated by planckkeyboard.com (2014 Jack Humbert) 3Copyright 2014 Jack Humbert
4 4
5This program is free software: you can redistribute it and/or modify 5This program is free software: you can redistribute it and/or modify
6it under the terms of the GNU General Public License as published by 6it under the terms of the GNU General Public License as published by
@@ -15,300 +15,211 @@ GNU General Public License for more details.
15You should have received a copy of the GNU General Public License 15You should have received a copy of the GNU General Public License
16along with this program. If not, see <http://www.gnu.org/licenses/>. 16along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/ 17*/
18
19/*
20 * scan matrix
21 */
22#include <stdint.h> 18#include <stdint.h>
23#include <stdbool.h> 19#include <stdbool.h>
24#include <avr/io.h> 20#include <avr/io.h>
25#include <util/delay.h> 21#include "wait.h"
26#include "print.h" 22#include "print.h"
27#include "debug.h" 23#include "debug.h"
28#include "util.h" 24#include "util.h"
29#include "matrix.h" 25#include "matrix.h"
30 26
31#ifndef DEBOUNCE 27#ifdef MATRIX_HAS_GHOST
32# define DEBOUNCE 10 28# error "The universal matrix.c file cannot be used for this keyboard."
33#endif 29#endif
34static uint8_t debouncing = DEBOUNCE;
35 30
36/* matrix state(1:on, 0:off) */ 31#ifndef DEBOUNCING_DELAY
37static matrix_row_t matrix[MATRIX_ROWS]; 32# define DEBOUNCING_DELAY 5
38static matrix_row_t matrix_debouncing[MATRIX_ROWS];
39
40#if DIODE_DIRECTION == ROW2COL
41 static matrix_row_t matrix_reversed[MATRIX_COLS];
42 static matrix_row_t matrix_reversed_debouncing[MATRIX_COLS];
43#endif 33#endif
44 34
45 35static const io_pin_t row_pins[MATRIX_ROWS] = MATRIX_ROW_PINS;
46#if MATRIX_COLS > 16 36static const io_pin_t col_pins[MATRIX_COLS] = MATRIX_COL_PINS;
47 #define SHIFTER 1UL 37/* matrix state */
38#if DIODE_DIRECTION == COL2ROW
39static matrix_row_t matrix[MATRIX_ROWS];
40static matrix_row_t debouncing_matrix[MATRIX_ROWS];
48#else 41#else
49 #define SHIFTER 1 42static matrix_col_t matrix[MATRIX_COLS];
43static matrix_col_t debouncing_matrix[MATRIX_COLS];
50#endif 44#endif
45static int8_t debouncing_delay = -1;
51 46
47#if DIODE_DIRECTION == COL2ROW
48static void toggle_row(uint8_t row);
52static matrix_row_t read_cols(void); 49static matrix_row_t read_cols(void);
53static void init_cols(void); 50#else
54static void unselect_rows(void); 51static void toggle_col(uint8_t col);
55static void select_row(uint8_t row); 52static matrix_col_t read_rows(void);
53#endif
56 54
57__attribute__ ((weak)) 55__attribute__ ((weak))
58void matrix_init_quantum(void) { 56void matrix_init_quantum(void) {
59
60} 57}
61 58
62__attribute__ ((weak)) 59__attribute__ ((weak))
63void matrix_scan_quantum(void) { 60void matrix_scan_quantum(void) {
64
65} 61}
66 62
67inline 63uint8_t matrix_rows(void) {
68uint8_t matrix_rows(void)
69{
70 return MATRIX_ROWS; 64 return MATRIX_ROWS;
71} 65}
72 66
73inline 67uint8_t matrix_cols(void) {
74uint8_t matrix_cols(void)
75{
76 return MATRIX_COLS; 68 return MATRIX_COLS;
77} 69}
78 70
79void matrix_init(void) 71void matrix_init(void) {
80{ 72 /* frees PORTF by setting the JTD bit twice within four cycles */
81 // To use PORTF disable JTAG with writing JTD bit twice within four cycles. 73 MCUCR |= _BV(JTD);
82 MCUCR |= (1<<JTD); 74 MCUCR |= _BV(JTD);
83 MCUCR |= (1<<JTD); 75 /* initializes the I/O pins */
84 76#if DIODE_DIRECTION == COL2ROW
85 77 for (int8_t r = MATRIX_ROWS - 1; r >= 0; --r) {
86 // initialize row and col 78 /* DDRxn */
87 unselect_rows(); 79 _SFR_IO8(row_pins[r].input_addr + 1) |= _BV(row_pins[r].bit);
88 init_cols(); 80 toggle_row(r);
89
90 // initialize matrix state: all keys off
91 for (uint8_t i=0; i < MATRIX_ROWS; i++) {
92 matrix[i] = 0;
93 matrix_debouncing[i] = 0;
94 } 81 }
95 82 for (int8_t c = MATRIX_COLS - 1; c >= 0; --c) {
83 /* PORTxn */
84 _SFR_IO8(col_pins[c].input_addr + 2) |= _BV(col_pins[c].bit);
85 }
86#else
87 for (int8_t c = MATRIX_COLS - 1; c >= 0; --c) {
88 /* DDRxn */
89 _SFR_IO8(col_pins[c].input_addr + 1) |= _BV(col_pins[c].bit);
90 toggle_col(c);
91 }
92 for (int8_t r = MATRIX_ROWS - 1; r >= 0; --r) {
93 /* PORTxn */
94 _SFR_IO8(row_pins[r].input_addr + 2) |= _BV(row_pins[r].bit);
95 }
96#endif
96 matrix_init_quantum(); 97 matrix_init_quantum();
97} 98}
98 99
99
100uint8_t matrix_scan(void)
101{
102
103#if DIODE_DIRECTION == COL2ROW 100#if DIODE_DIRECTION == COL2ROW
104 for (uint8_t i = 0; i < MATRIX_ROWS; i++) { 101uint8_t matrix_scan(void) {
105 select_row(i); 102 for (int8_t r = MATRIX_ROWS - 1; r >= 0; --r) {
106 _delay_us(30); // without this wait read unstable value. 103 toggle_row(r);
107 matrix_row_t cols = read_cols(); 104 matrix_row_t state = read_cols();
108 if (matrix_debouncing[i] != cols) { 105 if (debouncing_matrix[r] != state) {
109 matrix_debouncing[i] = cols; 106 debouncing_matrix[r] = state;
110 if (debouncing) { 107 debouncing_delay = DEBOUNCING_DELAY;
111 debug("bounce!: "); debug_hex(debouncing); debug("\n");
112 }
113 debouncing = DEBOUNCE;
114 } 108 }
115 unselect_rows(); 109 toggle_row(r);
116 } 110 }
117 111 if (debouncing_delay >= 0) {
118 if (debouncing) { 112 dprintf("Debouncing delay remaining: %X\n", debouncing_delay);
119 if (--debouncing) { 113 --debouncing_delay;
120 _delay_ms(1); 114 if (debouncing_delay >= 0) {
121 } else { 115 wait_ms(1);
122 for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
123 matrix[i] = matrix_debouncing[i];
124 }
125 } 116 }
126 } 117 else {
127#else 118 for (int8_t r = MATRIX_ROWS - 1; r >= 0; --r) {
128 for (uint8_t i = 0; i < MATRIX_COLS; i++) { 119 matrix[r] = debouncing_matrix[r];
129 select_row(i);
130 _delay_us(30); // without this wait read unstable value.
131 matrix_row_t rows = read_cols();
132 if (matrix_reversed_debouncing[i] != rows) {
133 matrix_reversed_debouncing[i] = rows;
134 if (debouncing) {
135 debug("bounce!: "); debug_hex(debouncing); debug("\n");
136 } 120 }
137 debouncing = DEBOUNCE;
138 } 121 }
139 unselect_rows();
140 } 122 }
141
142 if (debouncing) {
143 if (--debouncing) {
144 _delay_ms(1);
145 } else {
146 for (uint8_t i = 0; i < MATRIX_COLS; i++) {
147 matrix_reversed[i] = matrix_reversed_debouncing[i];
148 }
149 }
150 }
151 for (uint8_t y = 0; y < MATRIX_ROWS; y++) {
152 matrix_row_t row = 0;
153 for (uint8_t x = 0; x < MATRIX_COLS; x++) {
154 row |= ((matrix_reversed[x] & (1<<y)) >> y) << x;
155 }
156 matrix[y] = row;
157 }
158#endif
159
160 matrix_scan_quantum(); 123 matrix_scan_quantum();
161
162 return 1; 124 return 1;
163} 125}
164 126
165bool matrix_is_modified(void) 127static void toggle_row(uint8_t row) {
166{ 128 /* PINxn */
167 if (debouncing) return false; 129 _SFR_IO8(row_pins[row].input_addr) = _BV(row_pins[row].bit);
168 return true;
169} 130}
170 131
171inline 132static matrix_row_t read_cols(void) {
172bool matrix_is_on(uint8_t row, uint8_t col) 133 matrix_row_t state = 0;
173{ 134 for (int8_t c = MATRIX_COLS - 1; c >= 0; --c) {
174 return (matrix[row] & ((matrix_row_t)1<col)); 135 /* PINxn */
136 if (!(_SFR_IO8(col_pins[c].input_addr) & _BV(col_pins[c].bit))) {
137 state |= (matrix_row_t)1 << c;
138 }
139 }
140 return state;
175} 141}
176 142
177inline 143matrix_row_t matrix_get_row(uint8_t row) {
178matrix_row_t matrix_get_row(uint8_t row)
179{
180 return matrix[row]; 144 return matrix[row];
181} 145}
182 146
183void matrix_print(void) 147#else
184{ 148uint8_t matrix_scan(void) {
185 print("\nr/c 0123456789ABCDEF\n"); 149 for (int8_t c = MATRIX_COLS - 1; c >= 0; --c) {
186 for (uint8_t row = 0; row < MATRIX_ROWS; row++) { 150 toggle_col(c);
187 phex(row); print(": "); 151 matrix_col_t state = read_rows();
188 pbin_reverse16(matrix_get_row(row)); 152 if (debouncing_matrix[c] != state) {
189 print("\n"); 153 debouncing_matrix[c] = state;
154 debouncing_delay = DEBOUNCING_DELAY;
155 }
156 toggle_col(c);
190 } 157 }
191} 158 if (debouncing_delay >= 0) {
192 159 dprintf("Debouncing delay remaining: %X\n", debouncing_delay);
193uint8_t matrix_key_count(void) 160 --debouncing_delay;
194{ 161 if (debouncing_delay >= 0) {
195 uint8_t count = 0; 162 wait_ms(1);
196 for (uint8_t i = 0; i < MATRIX_ROWS; i++) { 163 }
197 count += bitpop16(matrix[i]); 164 else {
165 for (int8_t c = MATRIX_COLS - 1; c >= 0; --c) {
166 matrix[c] = debouncing_matrix[c];
167 }
168 }
198 } 169 }
199 return count; 170 matrix_scan_quantum();
171 return 1;
200} 172}
201 173
202static void init_cols(void) 174static void toggle_col(uint8_t col) {
203{ 175 /* PINxn */
204 int B = 0, C = 0, D = 0, E = 0, F = 0; 176 _SFR_IO8(col_pins[col].input_addr) = _BV(col_pins[col].bit);
177}
205 178
206#if DIODE_DIRECTION == COL2ROW 179static matrix_col_t read_rows(void) {
207 for(int x = 0; x < MATRIX_COLS; x++) { 180 matrix_col_t state = 0;
208 int col = COLS[x]; 181 for (int8_t r = MATRIX_ROWS - 1; r >= 0; --r) {
209#else 182 /* PINxn */
210 for(int x = 0; x < MATRIX_ROWS; x++) { 183 if (!(_SFR_IO8(row_pins[r].input_addr) & _BV(row_pins[r].bit))) {
211 int col = ROWS[x]; 184 state |= (matrix_col_t)1 << r;
212#endif 185 }
213 if ((col & 0xF0) == 0x20) {
214 B |= (1<<(col & 0x0F));
215 } else if ((col & 0xF0) == 0x30) {
216 C |= (1<<(col & 0x0F));
217 } else if ((col & 0xF0) == 0x40) {
218 D |= (1<<(col & 0x0F));
219 } else if ((col & 0xF0) == 0x50) {
220 E |= (1<<(col & 0x0F));
221 } else if ((col & 0xF0) == 0x60) {
222 F |= (1<<(col & 0x0F));
223 }
224 } 186 }
225 DDRB &= ~(B); PORTB |= (B); 187 return state;
226 DDRC &= ~(C); PORTC |= (C);
227 DDRD &= ~(D); PORTD |= (D);
228 DDRE &= ~(E); PORTE |= (E);
229 DDRF &= ~(F); PORTF |= (F);
230} 188}
231 189
232static matrix_row_t read_cols(void) 190matrix_row_t matrix_get_row(uint8_t row) {
233{ 191 matrix_row_t state = 0;
234 matrix_row_t result = 0; 192 matrix_col_t mask = (matrix_col_t)1 << row;
193 for (int8_t c = MATRIX_COLS - 1; c >= 0; --c) {
194 if (matrix[c] & mask) {
195 state |= (matrix_row_t)1 << c;
196 }
197 }
198 return state;
199}
235 200
236#if DIODE_DIRECTION == COL2ROW
237 for(int x = 0; x < MATRIX_COLS; x++) {
238 int col = COLS[x];
239#else
240 for(int x = 0; x < MATRIX_ROWS; x++) {
241 int col = ROWS[x];
242#endif 201#endif
243 202
244 if ((col & 0xF0) == 0x20) { 203bool matrix_is_modified(void) {
245 result |= (PINB&(1<<(col & 0x0F)) ? 0 : (SHIFTER<<x)); 204 if (debouncing_delay >= 0) return false;
246 } else if ((col & 0xF0) == 0x30) { 205 return true;
247 result |= (PINC&(1<<(col & 0x0F)) ? 0 : (SHIFTER<<x));
248 } else if ((col & 0xF0) == 0x40) {
249 result |= (PIND&(1<<(col & 0x0F)) ? 0 : (SHIFTER<<x));
250 } else if ((col & 0xF0) == 0x50) {
251 result |= (PINE&(1<<(col & 0x0F)) ? 0 : (SHIFTER<<x));
252 } else if ((col & 0xF0) == 0x60) {
253 result |= (PINF&(1<<(col & 0x0F)) ? 0 : (SHIFTER<<x));
254 }
255 }
256 return result;
257} 206}
258 207
259static void unselect_rows(void) 208bool matrix_is_on(uint8_t row, uint8_t col) {
260{ 209 return matrix_get_row(row) & (matrix_row_t)1 << col;
261 int B = 0, C = 0, D = 0, E = 0, F = 0; 210}
262 211
263#if DIODE_DIRECTION == COL2ROW 212void matrix_print(void) {
264 for(int x = 0; x < MATRIX_ROWS; x++) { 213 dprintln("Human-readable matrix state:");
265 int row = ROWS[x]; 214 for (uint8_t r = 0; r < MATRIX_ROWS; r++) {
266#else 215 dprintf("State of row %X: %016b\n", r, bitrev16(matrix_get_row(r)));
267 for(int x = 0; x < MATRIX_COLS; x++) {
268 int row = COLS[x];
269#endif
270 if ((row & 0xF0) == 0x20) {
271 B |= (1<<(row & 0x0F));
272 } else if ((row & 0xF0) == 0x30) {
273 C |= (1<<(row & 0x0F));
274 } else if ((row & 0xF0) == 0x40) {
275 D |= (1<<(row & 0x0F));
276 } else if ((row & 0xF0) == 0x50) {
277 E |= (1<<(row & 0x0F));
278 } else if ((row & 0xF0) == 0x60) {
279 F |= (1<<(row & 0x0F));
280 }
281 } 216 }
282 DDRB &= ~(B); PORTB |= (B);
283 DDRC &= ~(C); PORTC |= (C);
284 DDRD &= ~(D); PORTD |= (D);
285 DDRE &= ~(E); PORTE |= (E);
286 DDRF &= ~(F); PORTF |= (F);
287} 217}
288 218
289static void select_row(uint8_t row) 219uint8_t matrix_key_count(void) {
290{ 220 uint8_t count = 0;
291 221 for (int8_t r = MATRIX_ROWS - 1; r >= 0; --r) {
292#if DIODE_DIRECTION == COL2ROW 222 count += bitpop16(matrix_get_row(r));
293 int row_pin = ROWS[row]; 223 }
294#else 224 return count;
295 int row_pin = COLS[row]; 225}
296#endif
297
298 if ((row_pin & 0xF0) == 0x20) {
299 DDRB |= (1<<(row_pin & 0x0F));
300 PORTB &= ~(1<<(row_pin & 0x0F));
301 } else if ((row_pin & 0xF0) == 0x30) {
302 DDRC |= (1<<(row_pin & 0x0F));
303 PORTC &= ~(1<<(row_pin & 0x0F));
304 } else if ((row_pin & 0xF0) == 0x40) {
305 DDRD |= (1<<(row_pin & 0x0F));
306 PORTD &= ~(1<<(row_pin & 0x0F));
307 } else if ((row_pin & 0xF0) == 0x50) {
308 DDRE |= (1<<(row_pin & 0x0F));
309 PORTE &= ~(1<<(row_pin & 0x0F));
310 } else if ((row_pin & 0xF0) == 0x60) {
311 DDRF |= (1<<(row_pin & 0x0F));
312 PORTF &= ~(1<<(row_pin & 0x0F));
313 }
314} \ No newline at end of file