]> git.donarmstrong.com Git - qmk_firmware.git/blob - keyboards/handwired/dactyl/matrix.c
[Keyboard] Added DMOTE (#6087)
[qmk_firmware.git] / keyboards / handwired / dactyl / matrix.c
1 /*
2 Copyright 2013 Oleg Kostyuk <cub.uanic@gmail.com>
3 Copyright 2017 Erin Call <hello@erincall.com>
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18 #include <stdint.h>
19 #include <stdbool.h>
20 #include <avr/io.h>
21 #include "wait.h"
22 #include "action_layer.h"
23 #include "print.h"
24 #include "debug.h"
25 #include "util.h"
26 #include "matrix.h"
27 #include "dactyl.h"
28 #include "i2cmaster.h"
29 #include "timer.h"
30
31
32 /* Set 0 if debouncing isn't needed */
33
34 #ifndef DEBOUNCE
35 #   define DEBOUNCE 5
36 #endif
37
38 #if (DEBOUNCE > 0)
39     static uint16_t debouncing_time;
40     static bool debouncing = false;
41 #endif
42
43 #ifdef MATRIX_MASKED
44     extern const matrix_row_t matrix_mask[];
45 #endif
46
47 #if (DIODE_DIRECTION == ROW2COL) || (DIODE_DIRECTION == COL2ROW)
48 static const uint8_t onboard_row_pins[MATRIX_ROWS] = MATRIX_ONBOARD_ROW_PINS;
49 static const uint8_t onboard_col_pins[MATRIX_COLS] = MATRIX_ONBOARD_COL_PINS;
50 static const bool col_expanded[MATRIX_COLS] = COL_EXPANDED;
51 #endif
52
53 /* matrix state(1:on, 0:off) */
54 static matrix_row_t matrix[MATRIX_ROWS];
55
56 static matrix_row_t matrix_debouncing[MATRIX_ROWS];
57
58 #if (DIODE_DIRECTION == COL2ROW)
59     static const uint8_t expander_col_pins[MATRIX_COLS] = MATRIX_EXPANDER_COL_PINS;
60     static void init_cols(void);
61     static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row);
62     static void unselect_rows(void);
63     static void select_row(uint8_t row);
64     static void unselect_row(uint8_t row);
65 #elif (DIODE_DIRECTION == ROW2COL)
66     static const uint8_t expander_row_pins[MATRIX_ROWS] = MATRIX_EXPANDER_ROW_PINS;
67     static void init_rows(void);
68     static bool read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col);
69     static void unselect_cols(void);
70     static void select_col(uint8_t col);
71     static void unselect_col(uint8_t col);
72 #endif
73
74 static uint8_t expander_reset_loop;
75 uint8_t expander_status;
76 uint8_t expander_input_pin_mask;
77 bool i2c_initialized = false;
78
79 #ifdef DEBUG_MATRIX_SCAN_RATE
80 uint32_t matrix_timer;
81 uint32_t matrix_scan_count;
82 #endif
83
84 #define ROW_SHIFTER ((matrix_row_t)1)
85 #if (DIODE_DIRECTION == COL2ROW)
86 // bitmask to ensure the row state from the expander only applies to its columns
87 #define EXPANDER_MASK ((matrix_row_t)0b00111111)
88 #endif
89
90 __attribute__ ((weak))
91 void matrix_init_user(void) {}
92
93 __attribute__ ((weak))
94 void matrix_scan_user(void) {}
95
96 __attribute__ ((weak))
97 void matrix_init_kb(void) {
98   matrix_init_user();
99 }
100
101 __attribute__ ((weak))
102 void matrix_scan_kb(void) {
103   matrix_scan_user();
104 }
105
106 inline
107 uint8_t matrix_rows(void)
108 {
109     return MATRIX_ROWS;
110 }
111
112 inline
113 uint8_t matrix_cols(void)
114 {
115     return MATRIX_COLS;
116 }
117
118 void matrix_init(void)
119 {
120     init_expander();
121
122 #if (DIODE_DIRECTION == COL2ROW)
123     unselect_rows();
124     init_cols();
125 #elif (DIODE_DIRECTION == ROW2COL)
126     unselect_cols();
127     init_rows();
128 #endif
129
130     // initialize matrix state: all keys off
131     for (uint8_t i=0; i < MATRIX_ROWS; i++) {
132         matrix[i] = 0;
133         matrix_debouncing[i] = 0;
134     }
135
136 #ifdef DEBUG_MATRIX_SCAN_RATE
137     matrix_timer = timer_read32();
138     matrix_scan_count = 0;
139 #endif
140
141     matrix_init_quantum();
142 }
143
144 void init_expander(void) {
145     if (! i2c_initialized) {
146         i2c_init();
147         wait_us(1000000);
148     }
149
150     if (! expander_input_pin_mask) {
151 #if (DIODE_DIRECTION == COL2ROW)
152         for (int col = 0; col < MATRIX_COLS; col++) {
153             if (col_expanded[col]) {
154                 expander_input_pin_mask |= (1 << expander_col_pins[col]);
155             }
156         }
157 #elif (DIODE_DIRECTION == ROW2COL)
158         for (int row = 0; row < MATRIX_ROWS; row++) {
159             expander_input_pin_mask |= (1 << expander_row_pins[row]);
160         }
161 #endif
162     }
163
164     expander_status = i2c_start(I2C_ADDR_WRITE); if (expander_status) goto out;
165     expander_status = i2c_write(IODIRA);         if (expander_status) goto out;
166
167     /*
168     Pin direction and pull-up depends on both the diode direction
169     and on whether the column register is 0 ("A") or 1 ("B"):
170     +-------+---------------+---------------+
171     |       | ROW2COL       | COL2ROW       |
172     +-------+---------------+---------------+
173     | Reg 0 | input, output | output, input |
174     +-------+---------------+---------------+
175     | Reg 1 | output, input | input, output |
176     +-------+---------------+---------------+
177     */
178
179 #if (EXPANDER_COLUMN_REGISTER == 0)
180 #   if (DIODE_DIRECTION == COL2ROW)
181         expander_status = i2c_write(expander_input_pin_mask); if (expander_status) goto out;
182         expander_status = i2c_write(0);                       if (expander_status) goto out;
183 #   elif (DIODE_DIRECTION == ROW2COL)
184         expander_status = i2c_write(0);                       if (expander_status) goto out;
185         expander_status = i2c_write(expander_input_pin_mask); if (expander_status) goto out;
186 #   endif
187 #elif (EXPANDER_COLUMN_REGISTER == 1)
188 #   if (DIODE_DIRECTION == COL2ROW)
189         expander_status = i2c_write(0);                       if (expander_status) goto out;
190         expander_status = i2c_write(expander_input_pin_mask); if (expander_status) goto out;
191 #   elif (DIODE_DIRECTION == ROW2COL)
192         expander_status = i2c_write(expander_input_pin_mask); if (expander_status) goto out;
193         expander_status = i2c_write(0);                       if (expander_status) goto out;
194 #   endif
195 #endif
196
197     i2c_stop();
198
199     // set pull-up
200     // - unused  : off : 0
201     // - input   : on  : 1
202     // - driving : off : 0
203     expander_status = i2c_start(I2C_ADDR_WRITE);              if (expander_status) goto out;
204     expander_status = i2c_write(GPPUA);                       if (expander_status) goto out;
205 #if (EXPANDER_COLUMN_REGISTER == 0)
206 #   if (DIODE_DIRECTION == COL2ROW)
207         expander_status = i2c_write(expander_input_pin_mask); if (expander_status) goto out;
208         expander_status = i2c_write(0);                       if (expander_status) goto out;
209 #   elif (DIODE_DIRECTION == ROW2COL)
210         expander_status = i2c_write(0);                       if (expander_status) goto out;
211         expander_status = i2c_write(expander_input_pin_mask); if (expander_status) goto out;
212 #   endif
213 #elif (EXPANDER_COLUMN_REGISTER == 1)
214 #   if (DIODE_DIRECTION == COL2ROW)
215         expander_status = i2c_write(0);                       if (expander_status) goto out;
216         expander_status = i2c_write(expander_input_pin_mask); if (expander_status) goto out;
217 #   elif (DIODE_DIRECTION == ROW2COL)
218         expander_status = i2c_write(expander_input_pin_mask); if (expander_status) goto out;
219         expander_status = i2c_write(0);                       if (expander_status) goto out;
220 #   endif
221 #endif
222
223 out:
224     i2c_stop();
225 }
226
227 uint8_t matrix_scan(void)
228 {
229     if (expander_status) { // if there was an error
230         if (++expander_reset_loop == 0) {
231             // since expander_reset_loop is 8 bit - we'll try to reset once in 255 matrix scans
232             // this will be approx bit more frequent than once per second
233             print("trying to reset expander\n");
234             init_expander();
235             if (expander_status) {
236                 print("left side not responding\n");
237             } else {
238                 print("left side attached\n");
239             }
240         }
241     }
242
243 #ifdef DEBUG_MATRIX_SCAN_RATE
244     matrix_scan_count++;
245
246     uint32_t timer_now = timer_read32();
247     if (TIMER_DIFF_32(timer_now, matrix_timer)>1000) {
248         print("matrix scan frequency: ");
249         pdec(matrix_scan_count);
250         print("\n");
251
252         matrix_timer = timer_now;
253         matrix_scan_count = 0;
254     }
255 #endif
256
257 #if (DIODE_DIRECTION == COL2ROW)
258     for (uint8_t current_row = 0; current_row < MATRIX_ROWS; current_row++) {
259 #       if (DEBOUNCE > 0)
260             bool matrix_changed = read_cols_on_row(matrix_debouncing, current_row);
261
262             if (matrix_changed) {
263                 debouncing = true;
264                 debouncing_time = timer_read();
265             }
266 #       else
267             read_cols_on_row(matrix, current_row);
268 #       endif
269     }
270
271 #elif (DIODE_DIRECTION == ROW2COL)
272     for (uint8_t current_col = 0; current_col < MATRIX_COLS; current_col++) {
273 #       if (DEBOUNCE > 0)
274             bool matrix_changed = read_rows_on_col(matrix_debouncing, current_col);
275
276             if (matrix_changed) {
277                 debouncing = true;
278                 debouncing_time = timer_read();
279             }
280 #       else
281             read_rows_on_col(matrix, current_col);
282 #       endif
283
284     }
285 #endif
286
287 #   if (DEBOUNCE > 0)
288         if (debouncing && (timer_elapsed(debouncing_time) > DEBOUNCE)) {
289             for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
290                 matrix[i] = matrix_debouncing[i];
291             }
292             debouncing = false;
293         }
294 #   endif
295
296     matrix_scan_quantum();
297     return 1;
298 }
299
300 bool matrix_is_modified(void) // deprecated and evidently not called.
301 {
302 #if (DEBOUNCE > 0)
303     if (debouncing) return false;
304 #endif
305     return true;
306 }
307
308 inline
309 bool matrix_is_on(uint8_t row, uint8_t col)
310 {
311     return (matrix[row] & (ROW_SHIFTER << col));
312 }
313
314 inline
315 matrix_row_t matrix_get_row(uint8_t row)
316 {
317 #ifdef MATRIX_MASKED
318     return matrix[row] & matrix_mask[row];
319 #else
320     return matrix[row];
321 #endif
322 }
323
324 void matrix_print(void)
325 {
326     print("\nr/c 0123456789ABCDEF\n");
327     for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
328         phex(row); print(": ");
329         pbin_reverse16(matrix_get_row(row));
330         print("\n");
331     }
332 }
333
334 uint8_t matrix_key_count(void)
335 {
336     uint8_t count = 0;
337     for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
338         count += bitpop16(matrix[i]);
339     }
340     return count;
341 }
342
343 #if (DIODE_DIRECTION == COL2ROW)
344
345 static void init_cols(void) {
346     for (uint8_t x = 0; x < MATRIX_COLS; x++) {
347         if (! col_expanded[x]) {
348             uint8_t pin = onboard_col_pins[x];
349             _SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF); // IN
350             _SFR_IO8((pin >> 4) + 2) |=  _BV(pin & 0xF); // HI
351         }
352     }
353 }
354
355 static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row) {
356     // Store last value of row prior to reading
357     matrix_row_t last_row_value = current_matrix[current_row];
358
359     // Clear data in matrix row
360     current_matrix[current_row] = 0;
361
362     // Select row and wait for row selection to stabilize
363     select_row(current_row);
364     wait_us(30);
365
366     // Read columns from expander, unless it's in an error state
367     if (! expander_status) {
368         expander_status = i2c_start(I2C_ADDR_WRITE); if (expander_status) goto out;
369         expander_status = i2c_write(GPIOA);          if (expander_status) goto out;
370         expander_status = i2c_start(I2C_ADDR_READ);  if (expander_status) goto out;
371
372         current_matrix[current_row] |= (~i2c_readNak()) & EXPANDER_MASK;
373
374         out:
375             i2c_stop();
376     }
377
378     // Read columns from onboard pins
379     for (uint8_t col_index = 0; col_index < MATRIX_COLS; col_index++) {
380         if (! col_expanded[col_index]) {
381             uint8_t pin = onboard_col_pins[col_index];
382             uint8_t pin_state = (_SFR_IO8(pin >> 4) & _BV(pin & 0xF));
383             current_matrix[current_row] |= pin_state ? 0 : (ROW_SHIFTER << col_index);
384         }
385     }
386
387     unselect_row(current_row);
388
389     return (last_row_value != current_matrix[current_row]);
390 }
391
392 static void select_row(uint8_t row) {
393     // select on expander, unless it's in an error state
394     if (! expander_status) {
395         // set active row low  : 0
396         // set other rows hi-Z : 1
397         expander_status = i2c_start(I2C_ADDR_WRITE);   if (expander_status) goto out;
398         expander_status = i2c_write(GPIOB);            if (expander_status) goto out;
399         expander_status = i2c_write(0xFF & ~(1<<row)); if (expander_status) goto out;
400     out:
401         i2c_stop();
402     }
403
404     // select on teensy
405     uint8_t pin = onboard_row_pins[row];
406     _SFR_IO8((pin >> 4) + 1) |=  _BV(pin & 0xF); // OUT
407     _SFR_IO8((pin >> 4) + 2) &= ~_BV(pin & 0xF); // LOW
408 }
409
410 static void unselect_row(uint8_t row)
411 {
412     // No need to explicitly unselect expander pins--their I/O state is
413     // set simultaneously, with a single bitmask sent to i2c_write. When
414     // select_row selects a single pin, it implicitly unselects all the
415     // other ones.
416
417     // unselect on teensy
418     uint8_t pin = onboard_row_pins[row];
419     _SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF); // OUT
420     _SFR_IO8((pin >> 4) + 2) |=  _BV(pin & 0xF); // LOW
421 }
422
423 static void unselect_rows(void) {
424     for (uint8_t x = 0; x < MATRIX_ROWS; x++) {
425         unselect_row(x);
426     }
427 }
428
429 #elif (DIODE_DIRECTION == ROW2COL)
430
431 static void init_rows(void)
432 {
433     for (uint8_t x = 0; x < MATRIX_ROWS; x++) {
434         uint8_t pin = onboard_row_pins[x];
435         _SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF); // IN
436         _SFR_IO8((pin >> 4) + 2) |=  _BV(pin & 0xF); // HI
437     }
438 }
439
440 static bool read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col)
441 {
442     bool matrix_changed = false;
443
444     uint8_t column_state = 0;
445
446     //select col and wait for selection to stabilize
447     select_col(current_col);
448     wait_us(30);
449
450     if (current_col < 6) {
451         // read rows from expander
452         if (expander_status) {
453             // it's already in an error state; nothing we can do
454             return false;
455         }
456
457         expander_status = i2c_start(I2C_ADDR_WRITE); if (expander_status) goto out;
458         expander_status = i2c_write(GPIOB);          if (expander_status) goto out;
459         expander_status = i2c_start(I2C_ADDR_READ);  if (expander_status) goto out;
460         column_state = i2c_readNak();
461
462         out:
463             i2c_stop();
464
465         column_state = ~column_state;
466     } else {
467         for (uint8_t current_row = 0; current_row < MATRIX_ROWS; current_row++) {
468             if ((_SFR_IO8(onboard_row_pins[current_row] >> 4) & _BV(onboard_row_pins[current_row] & 0xF)) == 0) {
469                 column_state |= (1 << current_row);
470             }
471         }
472     }
473
474     for (uint8_t current_row = 0; current_row < MATRIX_ROWS; current_row++) {
475         // Store last value of row prior to reading
476         matrix_row_t last_row_value = current_matrix[current_row];
477
478         if (column_state & (1 << current_row)) {
479             // key closed; set state bit in matrix
480             current_matrix[current_row] |= (ROW_SHIFTER << current_col);
481         } else {
482             // key open; clear state bit in matrix
483             current_matrix[current_row] &= ~(ROW_SHIFTER << current_col);
484         }
485
486         // Determine whether the matrix changed state
487         if ((last_row_value != current_matrix[current_row]) && !(matrix_changed))
488         {
489             matrix_changed = true;
490         }
491     }
492
493     unselect_col(current_col);
494
495     return matrix_changed;
496 }
497
498 static void select_col(uint8_t col)
499 {
500     if (col_expanded[col]) {
501         // select on expander
502         if (expander_status) { // if there was an error
503             // do nothing
504         } else {
505             // set active col low  : 0
506             // set other cols hi-Z : 1
507             expander_status = i2c_start(I2C_ADDR_WRITE);   if (expander_status) goto out;
508             expander_status = i2c_write(GPIOA);            if (expander_status) goto out;
509             expander_status = i2c_write(0xFF & ~(1<<col)); if (expander_status) goto out;
510         out:
511             i2c_stop();
512         }
513     } else {
514         // select on teensy
515         uint8_t pin = onboard_col_pins[col];
516         _SFR_IO8((pin >> 4) + 1) |=  _BV(pin & 0xF); // OUT
517         _SFR_IO8((pin >> 4) + 2) &= ~_BV(pin & 0xF); // LOW
518     }
519 }
520
521 static void unselect_col(uint8_t col)
522 {
523     if (col_expanded[col]) {
524         // No need to explicitly unselect expander pins--their I/O state is
525         // set simultaneously, with a single bitmask sent to i2c_write. When
526         // select_col selects a single pin, it implicitly unselects all the
527         // other ones.
528     } else {
529         // unselect on teensy
530         uint8_t pin = onboard_col_pins[col];
531         _SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF); // IN
532         _SFR_IO8((pin >> 4) + 2) |=  _BV(pin & 0xF); // HI
533     }
534 }
535
536 static void unselect_cols(void)
537 {
538     for(uint8_t x = 0; x < MATRIX_COLS; x++) {
539         unselect_col(x);
540     }
541 }
542 #endif