]> git.donarmstrong.com Git - qmk_firmware.git/blob - keyboards/handwired/dactyl/matrix.c
Handwired/Dactyl keyboard (#2058)
[qmk_firmware.git] / keyboards / handwired / dactyl / matrix.c
1 /*
2
3 Copyright 2013 Oleg Kostyuk <cub.uanic@gmail.com>
4 Copyright 2017 Erin Call <hello@erincall.com>
5
6 This program is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 /*
21  * scan matrix
22  */
23 #include <stdint.h>
24 #include <stdbool.h>
25 #include <avr/io.h>
26 #include "wait.h"
27 #include "action_layer.h"
28 #include "print.h"
29 #include "debug.h"
30 #include "util.h"
31 #include "matrix.h"
32 #include "dactyl.h"
33 #include "i2cmaster.h"
34 #ifdef DEBUG_MATRIX_SCAN_RATE
35 #include  "timer.h"
36 #endif
37
38 /*
39  * This constant define not debouncing time in msecs, but amount of matrix
40  * scan loops which should be made to get stable debounced results.
41  *
42  * On the Dactyl, the matrix scan rate is relatively low, because
43  * communicating with the left hand's I/O expander is slower than simply
44  * selecting local pins.
45  * Now it's only 317 scans/second, or about 3.15 msec/scan.
46  * According to Cherry specs, debouncing time is 5 msec.
47  *
48  * And so, there is no sense to have DEBOUNCE higher than 2.
49  */
50
51 #ifndef DEBOUNCE
52 #   define DEBOUNCE     5
53 #endif
54
55 /* matrix state(1:on, 0:off) */
56 static matrix_row_t matrix[MATRIX_ROWS];
57
58 // Debouncing: store for each key the number of scans until it's eligible to
59 // change.  When scanning the matrix, ignore any changes in keys that have
60 // already changed in the last DEBOUNCE scans.
61 static uint8_t debounce_matrix[MATRIX_ROWS * MATRIX_COLS];
62
63 static matrix_row_t read_cols(uint8_t row);
64 static void init_cols(void);
65 static void unselect_rows(void);
66 static void select_row(uint8_t row);
67
68 static uint8_t mcp23018_reset_loop;
69
70 #ifdef DEBUG_MATRIX_SCAN_RATE
71 uint32_t matrix_timer;
72 uint32_t matrix_scan_count;
73 #endif
74
75
76 __attribute__ ((weak))
77 void matrix_init_user(void) {}
78
79 __attribute__ ((weak))
80 void matrix_scan_user(void) {}
81
82 __attribute__ ((weak))
83 void matrix_init_kb(void) {
84   matrix_init_user();
85 }
86
87 __attribute__ ((weak))
88 void matrix_scan_kb(void) {
89   matrix_scan_user();
90 }
91
92 inline
93 uint8_t matrix_rows(void)
94 {
95     return MATRIX_ROWS;
96 }
97
98 inline
99 uint8_t matrix_cols(void)
100 {
101     return MATRIX_COLS;
102 }
103
104 void matrix_init(void)
105 {
106     // initialize row and col
107
108     mcp23018_status = init_mcp23018();
109
110
111     unselect_rows();
112     init_cols();
113
114     // initialize matrix state: all keys off
115     for (uint8_t i=0; i < MATRIX_ROWS; i++) {
116         matrix[i] = 0;
117         for (uint8_t j=0; j < MATRIX_COLS; ++j) {
118             debounce_matrix[i * MATRIX_COLS + j] = 0;
119         }
120     }
121
122 #ifdef DEBUG_MATRIX_SCAN_RATE
123     matrix_timer = timer_read32();
124     matrix_scan_count = 0;
125 #endif
126
127     matrix_init_quantum();
128
129 }
130
131 void matrix_power_up(void) {
132     mcp23018_status = init_mcp23018();
133
134     unselect_rows();
135     init_cols();
136
137     // initialize matrix state: all keys off
138     for (uint8_t i=0; i < MATRIX_ROWS; i++) {
139         matrix[i] = 0;
140     }
141
142 #ifdef DEBUG_MATRIX_SCAN_RATE
143     matrix_timer = timer_read32();
144     matrix_scan_count = 0;
145 #endif
146 }
147
148 // Returns a matrix_row_t whose bits are set if the corresponding key should be
149 // eligible to change in this scan.
150 matrix_row_t debounce_mask(uint8_t row) {
151   matrix_row_t result = 0;
152   for (uint8_t j=0; j < MATRIX_COLS; ++j) {
153     if (debounce_matrix[row * MATRIX_COLS + j]) {
154       --debounce_matrix[row * MATRIX_COLS + j];
155     } else {
156       result |= (1 << j);
157     }
158   }
159   return result;
160 }
161
162 // Report changed keys in the given row.  Resets the debounce countdowns
163 // corresponding to each set bit in 'change' to DEBOUNCE.
164 void debounce_report(matrix_row_t change, uint8_t row) {
165   for (uint8_t i = 0; i < MATRIX_COLS; ++i) {
166     if (change & (1 << i)) {
167       debounce_matrix[row * MATRIX_COLS + i] = DEBOUNCE;
168     }
169   }
170 }
171
172 uint8_t matrix_scan(void)
173 {
174     if (mcp23018_status) { // if there was an error
175         if (++mcp23018_reset_loop == 0) {
176             // since mcp23018_reset_loop is 8 bit - we'll try to reset once in 255 matrix scans
177             // this will be approx bit more frequent than once per second
178             print("trying to reset mcp23018\n");
179             mcp23018_status = init_mcp23018();
180             if (mcp23018_status) {
181                 print("left side not responding\n");
182             } else {
183                 print("left side attached\n");
184             }
185         }
186     }
187
188 #ifdef DEBUG_MATRIX_SCAN_RATE
189     matrix_scan_count++;
190
191     uint32_t timer_now = timer_read32();
192     if (TIMER_DIFF_32(timer_now, matrix_timer)>1000) {
193         print("matrix scan frequency: ");
194         pdec(matrix_scan_count);
195         print("\n");
196
197         matrix_timer = timer_now;
198         matrix_scan_count = 0;
199     }
200 #endif
201
202     for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
203         select_row(i);
204         wait_us(30);  // without this wait read unstable value.
205         matrix_row_t mask = debounce_mask(i);
206         matrix_row_t cols = (read_cols(i) & mask) | (matrix[i] & ~mask);
207         debounce_report(cols ^ matrix[i], i);
208         matrix[i] = cols;
209
210         unselect_rows();
211     }
212
213     matrix_scan_quantum();
214
215     return 1;
216 }
217
218 bool matrix_is_modified(void) // deprecated and evidently not called.
219 {
220     return true;
221 }
222
223 inline
224 bool matrix_is_on(uint8_t row, uint8_t col)
225 {
226     return (matrix[row] & ((matrix_row_t)1<<col));
227 }
228
229 inline
230 matrix_row_t matrix_get_row(uint8_t row)
231 {
232     return matrix[row];
233 }
234
235 void matrix_print(void)
236 {
237     print("\nr/c 0123456789ABCDEF\n");
238     for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
239         phex(row); print(": ");
240         pbin_reverse16(matrix_get_row(row));
241         print("\n");
242     }
243 }
244
245 uint8_t matrix_key_count(void)
246 {
247     uint8_t count = 0;
248     for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
249         count += bitpop16(matrix[i]);
250     }
251     return count;
252 }
253
254 /* Column pin configuration
255  *
256  * Teensy
257  * col: 0   1   2   3   4   5
258  * pin: F0  F1  F4  F5  F6  F7
259  *
260  * MCP23018
261  * col: 0   1   2   3   4   5
262  * pin: B5  B4  B3  B2  B1  B0
263  */
264 static void  init_cols(void)
265 {
266     // init on mcp23018
267     // not needed, already done as part of init_mcp23018()
268
269     // init on teensy
270     // Input with pull-up(DDR:0, PORT:1)
271     DDRF  &= ~(1<<7 | 1<<6 | 1<<5 | 1<<4 | 1<<1 | 1<<0);
272     PORTF |=  (1<<7 | 1<<6 | 1<<5 | 1<<4 | 1<<1 | 1<<0);
273 }
274
275 static matrix_row_t read_cols(uint8_t row)
276 {
277     if (row < 6) {
278         if (mcp23018_status) { // if there was an error
279             return 0;
280         } else {
281             uint8_t data = 0;
282             mcp23018_status = i2c_start(I2C_ADDR_WRITE);    if (mcp23018_status) goto out;
283             mcp23018_status = i2c_write(GPIOB);             if (mcp23018_status) goto out;
284             mcp23018_status = i2c_start(I2C_ADDR_READ);     if (mcp23018_status) goto out;
285             data = i2c_readNak();
286             data = ~data;
287         out:
288             i2c_stop();
289             return data;
290         }
291     } else {
292         // read from teensy
293         return
294             (PINF&(1<<0) ? 0 : (1<<0)) |
295             (PINF&(1<<1) ? 0 : (1<<1)) |
296             (PINF&(1<<4) ? 0 : (1<<2)) |
297             (PINF&(1<<5) ? 0 : (1<<3)) |
298             (PINF&(1<<6) ? 0 : (1<<4)) |
299             (PINF&(1<<7) ? 0 : (1<<5)) ;
300     }
301 }
302
303 /* Row pin configuration
304  *
305  * Teensy
306  * row: 6   7   8   9   10  11
307  * pin: B1  B2  B3  D2  D3  C6
308  *
309  * MCP23018
310  * row: 0   1   2   3   4   5
311  * pin: A0  A1  A2  A3  A4  A5
312  */
313 static void unselect_rows(void)
314 {
315     // unselect on mcp23018
316     if (mcp23018_status) { // if there was an error
317         // do nothing
318     } else {
319         // set all rows hi-Z : 1
320         mcp23018_status = i2c_start(I2C_ADDR_WRITE); if (mcp23018_status) goto out;
321         mcp23018_status = i2c_write(GPIOA);          if (mcp23018_status) goto out;
322         mcp23018_status = i2c_write(0xFF);           if (mcp23018_status) goto out;
323     out:
324         i2c_stop();
325     }
326
327     // unselect on teensy
328     // Hi-Z(DDR:0, PORT:0) to unselect
329     DDRB  &= ~(1<<1 | 1<<2 | 1<<3);
330     PORTB &= ~(1<<1 | 1<<2 | 1<<3);
331     DDRD  &= ~(1<<2 | 1<<3);
332     PORTD &= ~(1<<2 | 1<<3);
333     DDRC  &= ~(1<<6);
334     PORTC &= ~(1<<6);
335 }
336
337 /* Row pin configuration
338  *
339  * Teensy
340  * row: 6   7   8   9   10  11
341  * pin: B1  B2  B3  D2  D3  C6
342  *
343  * MCP23018
344  * row: 0   1   2   3   4   5
345  * pin: A0  A1  A2  A3  A4  A5
346  */
347 static void select_row(uint8_t row)
348 {
349     if (row < 6) {
350         // select on mcp23018
351         if (mcp23018_status) { // if there was an error
352             // do nothing
353         } else {
354             // set active row low  : 0
355             // set other rows hi-Z : 1
356             mcp23018_status = i2c_start(I2C_ADDR_WRITE);   if (mcp23018_status) goto out;
357             mcp23018_status = i2c_write(GPIOA);            if (mcp23018_status) goto out;
358             mcp23018_status = i2c_write(0xFF & ~(1<<row)); if (mcp23018_status) goto out;
359         out:
360             i2c_stop();
361         }
362     } else {
363         // select on teensy
364         // Output low(DDR:1, PORT:0) to select
365         switch (row) {
366             case 6:
367                 DDRB  |= (1<<1);
368                 PORTB &= ~(1<<1);
369                 break;
370             case 7:
371                 DDRB  |= (1<<2);
372                 PORTB &= ~(1<<2);
373                 break;
374             case 8:
375                 DDRB  |= (1<<3);
376                 PORTB &= ~(1<<3);
377                 break;
378             case 9:
379                 DDRD  |= (1<<2);
380                 PORTD &= ~(1<<3);
381                 break;
382             case 10:
383                 DDRD  |= (1<<3);
384                 PORTD &= ~(1<<3);
385                 break;
386             case 11:
387                 DDRC  |= (1<<6);
388                 PORTC &= ~(1<<6);
389                 break;
390         }
391     }
392 }
393