aboutsummaryrefslogtreecommitdiff
path: root/keyboards/ergodox_ez/matrix.c
diff options
context:
space:
mode:
authorAlex Ong <the.onga@gmail.com>2019-04-04 08:45:55 +1100
committerDrashna Jaelre <drashna@live.com>2019-04-03 14:45:55 -0700
commit17e7762de7e3fdfc61c20aa61022f47370630c6a (patch)
treeacad10cdb64e24d78154c7c04de3585dece32cc3 /keyboards/ergodox_ez/matrix.c
parente1e08a494bf9ea46e1385559df76d5f49b8e9087 (diff)
downloadqmk_firmware-17e7762de7e3fdfc61c20aa61022f47370630c6a.tar.gz
qmk_firmware-17e7762de7e3fdfc61c20aa61022f47370630c6a.zip
Eager Per Row Debouncing added (added to Ergodox) (#5498)
* Implemented Eager Per Row debouncing algorithm. Good for when fingers can only press one row at a time (e.g. when keyboard is wired so that "rows" are vertical) * Added documentation for eager_pr * Ported ergodox_ez to eager_pr debouncing. * Removed check for changes in matrix_scan. * Added further clarification in docs. * Accidental merge with ergodox_ez * Small cleanup in eager_pr * Forgot to debounce_init - this would probably cause seg-faults.
Diffstat (limited to 'keyboards/ergodox_ez/matrix.c')
-rw-r--r--keyboards/ergodox_ez/matrix.c458
1 files changed, 196 insertions, 262 deletions
diff --git a/keyboards/ergodox_ez/matrix.c b/keyboards/ergodox_ez/matrix.c
index 860cf7b22..97f764113 100644
--- a/keyboards/ergodox_ez/matrix.c
+++ b/keyboards/ergodox_ez/matrix.c
@@ -33,14 +33,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
33#include "debug.h" 33#include "debug.h"
34#include "util.h" 34#include "util.h"
35#include "matrix.h" 35#include "matrix.h"
36#include "debounce.h"
36#include QMK_KEYBOARD_H 37#include QMK_KEYBOARD_H
37#ifdef DEBUG_MATRIX_SCAN_RATE 38#ifdef DEBUG_MATRIX_SCAN_RATE
38#include "timer.h" 39# include "timer.h"
39#endif 40#endif
40 41
41/* 42/*
42 * This constant define not debouncing time in msecs, but amount of matrix 43 * This constant define not debouncing time in msecs, assuming eager_pr.
43 * scan loops which should be made to get stable debounced results.
44 * 44 *
45 * On Ergodox matrix scan rate is relatively low, because of slow I2C. 45 * On Ergodox matrix scan rate is relatively low, because of slow I2C.
46 * Now it's only 317 scans/second, or about 3.15 msec/scan. 46 * Now it's only 317 scans/second, or about 3.15 msec/scan.
@@ -52,26 +52,17 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
52 */ 52 */
53 53
54#ifndef DEBOUNCE 54#ifndef DEBOUNCE
55# define DEBOUNCE 5 55# define DEBOUNCE 5
56#endif 56#endif
57 57
58/* matrix state(1:on, 0:off) */ 58/* matrix state(1:on, 0:off) */
59static matrix_row_t matrix[MATRIX_ROWS]; 59static matrix_row_t raw_matrix[MATRIX_ROWS]; // raw values
60/* 60static matrix_row_t matrix[MATRIX_ROWS]; // debounced values
61 * matrix state(1:on, 0:off)
62 * contains the raw values without debounce filtering of the last read cycle.
63 */
64static matrix_row_t raw_matrix[MATRIX_ROWS];
65
66// Debouncing: store for each key the number of scans until it's eligible to
67// change. When scanning the matrix, ignore any changes in keys that have
68// already changed in the last DEBOUNCE scans.
69static uint8_t debounce_matrix[MATRIX_ROWS * MATRIX_COLS];
70 61
71static matrix_row_t read_cols(uint8_t row); 62static matrix_row_t read_cols(uint8_t row);
72static void init_cols(void); 63static void init_cols(void);
73static void unselect_rows(void); 64static void unselect_rows(void);
74static void select_row(uint8_t row); 65static void select_row(uint8_t row);
75 66
76static uint8_t mcp23018_reset_loop; 67static uint8_t mcp23018_reset_loop;
77// static uint16_t mcp23018_reset_loop; 68// static uint16_t mcp23018_reset_loop;
@@ -81,197 +72,137 @@ uint32_t matrix_timer;
81uint32_t matrix_scan_count; 72uint32_t matrix_scan_count;
82#endif 73#endif
83 74
75__attribute__((weak)) void matrix_init_user(void) {}
84 76
85__attribute__ ((weak)) 77__attribute__((weak)) void matrix_scan_user(void) {}
86void matrix_init_user(void) {}
87 78
88__attribute__ ((weak)) 79__attribute__((weak)) void matrix_init_kb(void) { matrix_init_user(); }
89void matrix_scan_user(void) {}
90 80
91__attribute__ ((weak)) 81__attribute__((weak)) void matrix_scan_kb(void) { matrix_scan_user(); }
92void matrix_init_kb(void) {
93 matrix_init_user();
94}
95 82
96__attribute__ ((weak)) 83inline uint8_t matrix_rows(void) { return MATRIX_ROWS; }
97void matrix_scan_kb(void) {
98 matrix_scan_user();
99}
100
101inline
102uint8_t matrix_rows(void)
103{
104 return MATRIX_ROWS;
105}
106 84
107inline 85inline uint8_t matrix_cols(void) { return MATRIX_COLS; }
108uint8_t matrix_cols(void)
109{
110 return MATRIX_COLS;
111}
112 86
113void matrix_init(void) 87void matrix_init(void) {
114{ 88 // initialize row and col
115 // initialize row and col
116 89
117 mcp23018_status = init_mcp23018(); 90 mcp23018_status = init_mcp23018();
118 91
92 unselect_rows();
93 init_cols();
119 94
120 unselect_rows(); 95 // initialize matrix state: all keys off
121 init_cols(); 96 for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
122 97 matrix[i] = 0;
123 // initialize matrix state: all keys off 98 raw_matrix[i] = 0;
124 for (uint8_t i=0; i < MATRIX_ROWS; i++) { 99 }
125 matrix[i] = 0;
126 raw_matrix[i] = 0;
127 for (uint8_t j=0; j < MATRIX_COLS; ++j) {
128 debounce_matrix[i * MATRIX_COLS + j] = 0;
129 }
130 }
131 100
132#ifdef DEBUG_MATRIX_SCAN_RATE 101#ifdef DEBUG_MATRIX_SCAN_RATE
133 matrix_timer = timer_read32(); 102 matrix_timer = timer_read32();
134 matrix_scan_count = 0; 103 matrix_scan_count = 0;
135#endif 104#endif
136 105 debounce_init(MATRIX_ROWS);
137 matrix_init_quantum(); 106 matrix_init_quantum();
138
139} 107}
140 108
141void matrix_power_up(void) { 109void matrix_power_up(void) {
142 mcp23018_status = init_mcp23018(); 110 mcp23018_status = init_mcp23018();
143 111
144 unselect_rows(); 112 unselect_rows();
145 init_cols(); 113 init_cols();
146 114
147 // initialize matrix state: all keys off 115 // initialize matrix state: all keys off
148 for (uint8_t i=0; i < MATRIX_ROWS; i++) { 116 for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
149 matrix[i] = 0; 117 matrix[i] = 0;
150 } 118 }
151 119
152#ifdef DEBUG_MATRIX_SCAN_RATE 120#ifdef DEBUG_MATRIX_SCAN_RATE
153 matrix_timer = timer_read32(); 121 matrix_timer = timer_read32();
154 matrix_scan_count = 0; 122 matrix_scan_count = 0;
155#endif 123#endif
156} 124}
157 125
158// Returns a matrix_row_t whose bits are set if the corresponding key should be 126uint8_t matrix_scan(void) {
159// eligible to change in this scan. 127 if (mcp23018_status) { // if there was an error
160matrix_row_t debounce_mask(matrix_row_t rawcols, uint8_t row) { 128 if (++mcp23018_reset_loop == 0) {
161 matrix_row_t result = 0; 129 // if (++mcp23018_reset_loop >= 1300) {
162 matrix_row_t change = rawcols ^ raw_matrix[row]; 130 // since mcp23018_reset_loop is 8 bit - we'll try to reset once in 255 matrix scans
163 raw_matrix[row] = rawcols; 131 // this will be approx bit more frequent than once per second
164 for (uint8_t i = 0; i < MATRIX_COLS; ++i) { 132 print("trying to reset mcp23018\n");
165 if (debounce_matrix[row * MATRIX_COLS + i]) { 133 mcp23018_status = init_mcp23018();
166 --debounce_matrix[row * MATRIX_COLS + i]; 134 if (mcp23018_status) {
167 } else { 135 print("left side not responding\n");
168 result |= (1 << i); 136 } else {
169 } 137 print("left side attached\n");
170 if (change & (1 << i)) { 138 ergodox_blink_all_leds();
171 debounce_matrix[row * MATRIX_COLS + i] = DEBOUNCE; 139 }
172 } 140 }
173 } 141 }
174 return result;
175}
176
177matrix_row_t debounce_read_cols(uint8_t row) {
178 // Read the row without debouncing filtering and store it for later usage.
179 matrix_row_t cols = read_cols(row);
180 // Get the Debounce mask.
181 matrix_row_t mask = debounce_mask(cols, row);
182 // debounce the row and return the result.
183 return (cols & mask) | (matrix[row] & ~mask);;
184}
185
186uint8_t matrix_scan(void)
187{
188 if (mcp23018_status) { // if there was an error
189 if (++mcp23018_reset_loop == 0) {
190 // if (++mcp23018_reset_loop >= 1300) {
191 // since mcp23018_reset_loop is 8 bit - we'll try to reset once in 255 matrix scans
192 // this will be approx bit more frequent than once per second
193 print("trying to reset mcp23018\n");
194 mcp23018_status = init_mcp23018();
195 if (mcp23018_status) {
196 print("left side not responding\n");
197 } else {
198 print("left side attached\n");
199 ergodox_blink_all_leds();
200 }
201 }
202 }
203 142
204#ifdef DEBUG_MATRIX_SCAN_RATE 143#ifdef DEBUG_MATRIX_SCAN_RATE
205 matrix_scan_count++; 144 matrix_scan_count++;
206 145
207 uint32_t timer_now = timer_read32(); 146 uint32_t timer_now = timer_read32();
208 if (TIMER_DIFF_32(timer_now, matrix_timer)>1000) { 147 if (TIMER_DIFF_32(timer_now, matrix_timer) > 1000) {
209 print("matrix scan frequency: "); 148 print("matrix scan frequency: ");
210 pdec(matrix_scan_count); 149 pdec(matrix_scan_count);
211 print("\n"); 150 print("\n");
212 151
213 matrix_timer = timer_now; 152 matrix_timer = timer_now;
214 matrix_scan_count = 0; 153 matrix_scan_count = 0;
215 } 154 }
216#endif 155#endif
217 156
218#ifdef LEFT_LEDS 157#ifdef LEFT_LEDS
219 mcp23018_status = ergodox_left_leds_update(); 158 mcp23018_status = ergodox_left_leds_update();
220#endif // LEFT_LEDS 159#endif // LEFT_LEDS
221 for (uint8_t i = 0; i < MATRIX_ROWS_PER_SIDE; i++) { 160 for (uint8_t i = 0; i < MATRIX_ROWS_PER_SIDE; i++) {
222 select_row(i); 161 // select rows from left and right hands
223 // and select on left hand 162 select_row(i);
224 select_row(i + MATRIX_ROWS_PER_SIDE); 163 select_row(i + MATRIX_ROWS_PER_SIDE);
225 // we don't need a 30us delay anymore, because selecting a 164
226 // left-hand row requires more than 30us for i2c. 165 // we don't need a 30us delay anymore, because selecting a
227 166 // left-hand row requires more than 30us for i2c.
228 // grab cols from left hand 167
229 matrix[i] = debounce_read_cols(i); 168 // grab left + right cols.
230 // grab cols from right hand 169 raw_matrix[i] = read_cols(i);
231 matrix[i + MATRIX_ROWS_PER_SIDE] = debounce_read_cols(i + MATRIX_ROWS_PER_SIDE); 170 raw_matrix[i+MATRIX_ROWS_PER_SIDE] = read_cols(i+MATRIX_ROWS_PER_SIDE);
232 171
233 unselect_rows(); 172 unselect_rows();
234 } 173 }
235 174
236 matrix_scan_quantum(); 175 debounce(raw_matrix, matrix, MATRIX_ROWS, true);
176 matrix_scan_quantum();
237 177
238 return 1; 178 return 1;
239} 179}
240 180
241bool matrix_is_modified(void) // deprecated and evidently not called. 181bool matrix_is_modified(void) // deprecated and evidently not called.
242{ 182{
243 return true; 183 return true;
244} 184}
245 185
246inline 186inline bool matrix_is_on(uint8_t row, uint8_t col) { return (matrix[row] & ((matrix_row_t)1 << col)); }
247bool matrix_is_on(uint8_t row, uint8_t col)
248{
249 return (matrix[row] & ((matrix_row_t)1<<col));
250}
251 187
252inline 188inline matrix_row_t matrix_get_row(uint8_t row) { return matrix[row]; }
253matrix_row_t matrix_get_row(uint8_t row)
254{
255 return matrix[row];
256}
257 189
258void matrix_print(void) 190void matrix_print(void) {
259{ 191 print("\nr/c 0123456789ABCDEF\n");
260 print("\nr/c 0123456789ABCDEF\n"); 192 for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
261 for (uint8_t row = 0; row < MATRIX_ROWS; row++) { 193 phex(row);
262 phex(row); print(": "); 194 print(": ");
263 pbin_reverse16(matrix_get_row(row)); 195 pbin_reverse16(matrix_get_row(row));
264 print("\n"); 196 print("\n");
265 } 197 }
266} 198}
267 199
268uint8_t matrix_key_count(void) 200uint8_t matrix_key_count(void) {
269{ 201 uint8_t count = 0;
270 uint8_t count = 0; 202 for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
271 for (uint8_t i = 0; i < MATRIX_ROWS; i++) { 203 count += bitpop16(matrix[i]);
272 count += bitpop16(matrix[i]); 204 }
273 } 205 return count;
274 return count;
275} 206}
276 207
277/* Column pin configuration 208/* Column pin configuration
@@ -284,43 +215,45 @@ uint8_t matrix_key_count(void)
284 * col: 0 1 2 3 4 5 215 * col: 0 1 2 3 4 5
285 * pin: B5 B4 B3 B2 B1 B0 216 * pin: B5 B4 B3 B2 B1 B0
286 */ 217 */
287static void init_cols(void) 218static void init_cols(void) {
288{ 219 // init on mcp23018
289 // init on mcp23018 220 // not needed, already done as part of init_mcp23018()
290 // not needed, already done as part of init_mcp23018() 221
291 222 // init on teensy
292 // init on teensy 223 // Input with pull-up(DDR:0, PORT:1)
293 // Input with pull-up(DDR:0, PORT:1) 224 DDRF &= ~(1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 1 | 1 << 0);
294 DDRF &= ~(1<<7 | 1<<6 | 1<<5 | 1<<4 | 1<<1 | 1<<0); 225 PORTF |= (1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 1 | 1 << 0);
295 PORTF |= (1<<7 | 1<<6 | 1<<5 | 1<<4 | 1<<1 | 1<<0);
296} 226}
297 227
298static matrix_row_t read_cols(uint8_t row) 228static matrix_row_t read_cols(uint8_t row) {
299{ 229 if (row < 7) {
300 if (row < 7) { 230 if (mcp23018_status) { // if there was an error
301 if (mcp23018_status) { // if there was an error 231 return 0;
302 return 0;
303 } else {
304 uint8_t data = 0;
305 mcp23018_status = i2c_start(I2C_ADDR_WRITE, ERGODOX_EZ_I2C_TIMEOUT); if (mcp23018_status) goto out;
306 mcp23018_status = i2c_write(GPIOB, ERGODOX_EZ_I2C_TIMEOUT); if (mcp23018_status) goto out;
307 mcp23018_status = i2c_start(I2C_ADDR_READ, ERGODOX_EZ_I2C_TIMEOUT); if (mcp23018_status) goto out;
308 mcp23018_status = i2c_read_nack(ERGODOX_EZ_I2C_TIMEOUT); if (mcp23018_status < 0) goto out;
309 data = ~((uint8_t)mcp23018_status);
310 mcp23018_status = I2C_STATUS_SUCCESS;
311 out:
312 i2c_stop();
313 return data;
314 }
315 } else { 232 } else {
316 /* read from teensy 233 uint8_t data = 0;
317 * bitmask is 0b11110011, but we want those all 234 mcp23018_status = i2c_start(I2C_ADDR_WRITE, ERGODOX_EZ_I2C_TIMEOUT);
318 * in the lower six bits. 235 if (mcp23018_status) goto out;
319 * we'll return 1s for the top two, but that's harmless. 236 mcp23018_status = i2c_write(GPIOB, ERGODOX_EZ_I2C_TIMEOUT);
320 */ 237 if (mcp23018_status) goto out;
321 238 mcp23018_status = i2c_start(I2C_ADDR_READ, ERGODOX_EZ_I2C_TIMEOUT);
322 return ~((PINF & 0x03) | ((PINF & 0xF0) >> 2)); 239 if (mcp23018_status) goto out;
240 mcp23018_status = i2c_read_nack(ERGODOX_EZ_I2C_TIMEOUT);
241 if (mcp23018_status < 0) goto out;
242 data = ~((uint8_t)mcp23018_status);
243 mcp23018_status = I2C_STATUS_SUCCESS;
244 out:
245 i2c_stop();
246 return data;
323 } 247 }
248 } else {
249 /* read from teensy
250 * bitmask is 0b11110011, but we want those all
251 * in the lower six bits.
252 * we'll return 1s for the top two, but that's harmless.
253 */
254
255 return ~((PINF & 0x03) | ((PINF & 0xF0) >> 2));
256 }
324} 257}
325 258
326/* Row pin configuration 259/* Row pin configuration
@@ -333,69 +266,70 @@ static matrix_row_t read_cols(uint8_t row)
333 * row: 0 1 2 3 4 5 6 266 * row: 0 1 2 3 4 5 6
334 * pin: A0 A1 A2 A3 A4 A5 A6 267 * pin: A0 A1 A2 A3 A4 A5 A6
335 */ 268 */
336static void unselect_rows(void) 269static void unselect_rows(void) {
337{ 270 // no need to unselect on mcp23018, because the select step sets all
338 // no need to unselect on mcp23018, because the select step sets all 271 // the other row bits high, and it's not changing to a different
339 // the other row bits high, and it's not changing to a different 272 // direction
340 // direction 273
341 274 // unselect on teensy
342 // unselect on teensy 275 // Hi-Z(DDR:0, PORT:0) to unselect
343 // Hi-Z(DDR:0, PORT:0) to unselect 276 DDRB &= ~(1 << 0 | 1 << 1 | 1 << 2 | 1 << 3);
344 DDRB &= ~(1<<0 | 1<<1 | 1<<2 | 1<<3); 277 PORTB &= ~(1 << 0 | 1 << 1 | 1 << 2 | 1 << 3);
345 PORTB &= ~(1<<0 | 1<<1 | 1<<2 | 1<<3); 278 DDRD &= ~(1 << 2 | 1 << 3);
346 DDRD &= ~(1<<2 | 1<<3); 279 PORTD &= ~(1 << 2 | 1 << 3);
347 PORTD &= ~(1<<2 | 1<<3); 280 DDRC &= ~(1 << 6);
348 DDRC &= ~(1<<6); 281 PORTC &= ~(1 << 6);
349 PORTC &= ~(1<<6);
350} 282}
351 283
352static void select_row(uint8_t row) 284static void select_row(uint8_t row) {
353{ 285 if (row < 7) {
354 if (row < 7) { 286 // select on mcp23018
355 // select on mcp23018 287 if (mcp23018_status) { // if there was an error
356 if (mcp23018_status) { // if there was an error 288 // do nothing
357 // do nothing
358 } else {
359 // set active row low : 0
360 // set other rows hi-Z : 1
361 mcp23018_status = i2c_start(I2C_ADDR_WRITE, ERGODOX_EZ_I2C_TIMEOUT); if (mcp23018_status) goto out;
362 mcp23018_status = i2c_write(GPIOA, ERGODOX_EZ_I2C_TIMEOUT); if (mcp23018_status) goto out;
363 mcp23018_status = i2c_write(0xFF & ~(1<<row), ERGODOX_EZ_I2C_TIMEOUT); if (mcp23018_status) goto out;
364 out:
365 i2c_stop();
366 }
367 } else { 289 } else {
368 // select on teensy 290 // set active row low : 0
369 // Output low(DDR:1, PORT:0) to select 291 // set other rows hi-Z : 1
370 switch (row) { 292 mcp23018_status = i2c_start(I2C_ADDR_WRITE, ERGODOX_EZ_I2C_TIMEOUT);
371 case 7: 293 if (mcp23018_status) goto out;
372 DDRB |= (1<<0); 294 mcp23018_status = i2c_write(GPIOA, ERGODOX_EZ_I2C_TIMEOUT);
373 PORTB &= ~(1<<0); 295 if (mcp23018_status) goto out;
374 break; 296 mcp23018_status = i2c_write(0xFF & ~(1 << row), ERGODOX_EZ_I2C_TIMEOUT);
375 case 8: 297 if (mcp23018_status) goto out;
376 DDRB |= (1<<1); 298 out:
377 PORTB &= ~(1<<1); 299 i2c_stop();
378 break; 300 }
379 case 9: 301 } else {
380 DDRB |= (1<<2); 302 // select on teensy
381 PORTB &= ~(1<<2); 303 // Output low(DDR:1, PORT:0) to select
382 break; 304 switch (row) {
383 case 10: 305 case 7:
384 DDRB |= (1<<3); 306 DDRB |= (1 << 0);
385 PORTB &= ~(1<<3); 307 PORTB &= ~(1 << 0);
386 break; 308 break;
387 case 11: 309 case 8:
388 DDRD |= (1<<2); 310 DDRB |= (1 << 1);
389 PORTD &= ~(1<<2); 311 PORTB &= ~(1 << 1);
390 break; 312 break;
391 case 12: 313 case 9:
392 DDRD |= (1<<3); 314 DDRB |= (1 << 2);
393 PORTD &= ~(1<<3); 315 PORTB &= ~(1 << 2);
394 break; 316 break;
395 case 13: 317 case 10:
396 DDRC |= (1<<6); 318 DDRB |= (1 << 3);
397 PORTC &= ~(1<<6); 319 PORTB &= ~(1 << 3);
398 break; 320 break;
399 } 321 case 11:
322 DDRD |= (1 << 2);
323 PORTD &= ~(1 << 2);
324 break;
325 case 12:
326 DDRD |= (1 << 3);
327 PORTD &= ~(1 << 3);
328 break;
329 case 13:
330 DDRC |= (1 << 6);
331 PORTC &= ~(1 << 6);
332 break;
400 } 333 }
334 }
401} 335}