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