]> git.donarmstrong.com Git - qmk_firmware.git/blob - keyboards/ergodox_ez/matrix.c
[Keyboard] Add QMK configurator JSON for Alice PCB (#6397)
[qmk_firmware.git] / keyboards / ergodox_ez / matrix.c
1 /*
2
3
4 Copyright 2013 Oleg Kostyuk <cub.uanic@gmail.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 "debounce.h"
33 #include QMK_KEYBOARD_H
34 #ifdef DEBUG_MATRIX_SCAN_RATE
35 #  include "timer.h"
36 #endif
37
38 /*
39  * This constant define not debouncing time in msecs, assuming eager_pr.
40  *
41  * On Ergodox matrix scan rate is relatively low, because of slow I2C.
42  * Now it's only 317 scans/second, or about 3.15 msec/scan.
43  * According to Cherry specs, debouncing time is 5 msec.
44  *
45  * However, some switches seem to have higher debouncing requirements, or
46  * something else might be wrong. (Also, the scan speed has improved since
47  * that comment was written.)
48  */
49
50 #ifndef DEBOUNCE
51 #  define DEBOUNCE 5
52 #endif
53
54 /* matrix state(1:on, 0:off) */
55 static matrix_row_t raw_matrix[MATRIX_ROWS];  // raw values
56 static matrix_row_t matrix[MATRIX_ROWS];      // debounced values
57
58 static matrix_row_t read_cols(uint8_t row);
59 static void         init_cols(void);
60 static void         unselect_rows(void);
61 static void         select_row(uint8_t row);
62
63 static uint8_t mcp23018_reset_loop;
64 // static uint16_t mcp23018_reset_loop;
65
66 #ifdef DEBUG_MATRIX_SCAN_RATE
67 uint32_t matrix_timer;
68 uint32_t matrix_scan_count;
69 #endif
70
71 __attribute__((weak)) void matrix_init_user(void) {}
72
73 __attribute__((weak)) void matrix_scan_user(void) {}
74
75 __attribute__((weak)) void matrix_init_kb(void) { matrix_init_user(); }
76
77 __attribute__((weak)) void matrix_scan_kb(void) { matrix_scan_user(); }
78
79 inline uint8_t matrix_rows(void) { return MATRIX_ROWS; }
80
81 inline uint8_t matrix_cols(void) { return MATRIX_COLS; }
82
83 void matrix_init(void) {
84   // initialize row and col
85
86   mcp23018_status = init_mcp23018();
87
88   unselect_rows();
89   init_cols();
90
91   // initialize matrix state: all keys off
92   for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
93     matrix[i]     = 0;
94     raw_matrix[i] = 0;
95   }
96
97 #ifdef DEBUG_MATRIX_SCAN_RATE
98   matrix_timer      = timer_read32();
99   matrix_scan_count = 0;
100 #endif
101   debounce_init(MATRIX_ROWS);
102   matrix_init_quantum();
103 }
104
105 void matrix_power_up(void) {
106   mcp23018_status = init_mcp23018();
107
108   unselect_rows();
109   init_cols();
110
111   // initialize matrix state: all keys off
112   for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
113     matrix[i] = 0;
114   }
115
116 #ifdef DEBUG_MATRIX_SCAN_RATE
117   matrix_timer      = timer_read32();
118   matrix_scan_count = 0;
119 #endif
120 }
121
122 // Reads and stores a row, returning
123 // whether a change occurred.
124 static inline bool store_raw_matrix_row(uint8_t index) {
125   matrix_row_t temp = read_cols(index);
126   if (raw_matrix[index] != temp) {
127     raw_matrix[index] = temp;
128     return true;
129   }
130   return false;
131 }
132
133 uint8_t matrix_scan(void) {
134   if (mcp23018_status) {  // if there was an error
135     if (++mcp23018_reset_loop == 0) {
136       // if (++mcp23018_reset_loop >= 1300) {
137       // since mcp23018_reset_loop is 8 bit - we'll try to reset once in 255 matrix scans
138       // this will be approx bit more frequent than once per second
139       print("trying to reset mcp23018\n");
140       mcp23018_status = init_mcp23018();
141       if (mcp23018_status) {
142         print("left side not responding\n");
143       } else {
144         print("left side attached\n");
145         ergodox_blink_all_leds();
146       }
147     }
148   }
149
150 #ifdef DEBUG_MATRIX_SCAN_RATE
151   matrix_scan_count++;
152
153   uint32_t timer_now = timer_read32();
154   if (TIMER_DIFF_32(timer_now, matrix_timer) > 1000) {
155     print("matrix scan frequency: ");
156     pdec(matrix_scan_count);
157     print("\n");
158
159     matrix_timer      = timer_now;
160     matrix_scan_count = 0;
161   }
162 #endif
163
164 #ifdef LEFT_LEDS
165   mcp23018_status = ergodox_left_leds_update();
166 #endif  // LEFT_LEDS
167   bool changed = false;
168   for (uint8_t i = 0; i < MATRIX_ROWS_PER_SIDE; i++) {
169     // select rows from left and right hands
170     uint8_t left_index = i;
171     uint8_t right_index = i + MATRIX_ROWS_PER_SIDE;
172     select_row(left_index);
173     select_row(right_index);
174
175     // we don't need a 30us delay anymore, because selecting a
176     // left-hand row requires more than 30us for i2c.
177
178     changed |= store_raw_matrix_row(left_index);
179     changed |= store_raw_matrix_row(right_index);
180
181     unselect_rows();
182   }
183
184   debounce(raw_matrix, matrix, MATRIX_ROWS, changed);
185   matrix_scan_quantum();
186
187   return 1;
188 }
189
190 bool matrix_is_modified(void)  // deprecated and evidently not called.
191 {
192   return true;
193 }
194
195 inline bool matrix_is_on(uint8_t row, uint8_t col) { return (matrix[row] & ((matrix_row_t)1 << col)); }
196
197 inline matrix_row_t matrix_get_row(uint8_t row) { return matrix[row]; }
198
199 void matrix_print(void) {
200   print("\nr/c 0123456789ABCDEF\n");
201   for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
202     phex(row);
203     print(": ");
204     pbin_reverse16(matrix_get_row(row));
205     print("\n");
206   }
207 }
208
209 uint8_t matrix_key_count(void) {
210   uint8_t count = 0;
211   for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
212     count += bitpop16(matrix[i]);
213   }
214   return count;
215 }
216
217 /* Column pin configuration
218  *
219  * Teensy
220  * col: 0   1   2   3   4   5
221  * pin: F0  F1  F4  F5  F6  F7
222  *
223  * MCP23018
224  * col: 0   1   2   3   4   5
225  * pin: B5  B4  B3  B2  B1  B0
226  */
227 static void init_cols(void) {
228   // init on mcp23018
229   // not needed, already done as part of init_mcp23018()
230
231   // init on teensy
232   // Input with pull-up(DDR:0, PORT:1)
233   DDRF &= ~(1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 1 | 1 << 0);
234   PORTF |= (1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 1 | 1 << 0);
235 }
236
237 static matrix_row_t read_cols(uint8_t row) {
238   if (row < 7) {
239     if (mcp23018_status) {  // if there was an error
240       return 0;
241     } else {
242       uint8_t data    = 0;
243       mcp23018_status = i2c_start(I2C_ADDR_WRITE, ERGODOX_EZ_I2C_TIMEOUT);
244       if (mcp23018_status) goto out;
245       mcp23018_status = i2c_write(GPIOB, ERGODOX_EZ_I2C_TIMEOUT);
246       if (mcp23018_status) goto out;
247       mcp23018_status = i2c_start(I2C_ADDR_READ, ERGODOX_EZ_I2C_TIMEOUT);
248       if (mcp23018_status) goto out;
249       mcp23018_status = i2c_read_nack(ERGODOX_EZ_I2C_TIMEOUT);
250       if (mcp23018_status < 0) goto out;
251       data            = ~((uint8_t)mcp23018_status);
252       mcp23018_status = I2C_STATUS_SUCCESS;
253     out:
254       i2c_stop();
255       return data;
256     }
257   } else {
258     /* read from teensy
259      * bitmask is 0b11110011, but we want those all
260      * in the lower six bits.
261      * we'll return 1s for the top two, but that's harmless.
262      */
263
264     return ~((PINF & 0x03) | ((PINF & 0xF0) >> 2));
265   }
266 }
267
268 /* Row pin configuration
269  *
270  * Teensy
271  * row: 7   8   9   10  11  12  13
272  * pin: B0  B1  B2  B3  D2  D3  C6
273  *
274  * MCP23018
275  * row: 0   1   2   3   4   5   6
276  * pin: A0  A1  A2  A3  A4  A5  A6
277  */
278 static void unselect_rows(void) {
279   // no need to unselect on mcp23018, because the select step sets all
280   // the other row bits high, and it's not changing to a different
281   // direction
282
283   // unselect on teensy
284   // Hi-Z(DDR:0, PORT:0) to unselect
285   DDRB &= ~(1 << 0 | 1 << 1 | 1 << 2 | 1 << 3);
286   PORTB &= ~(1 << 0 | 1 << 1 | 1 << 2 | 1 << 3);
287   DDRD &= ~(1 << 2 | 1 << 3);
288   PORTD &= ~(1 << 2 | 1 << 3);
289   DDRC &= ~(1 << 6);
290   PORTC &= ~(1 << 6);
291 }
292
293 static void select_row(uint8_t row) {
294   if (row < 7) {
295     // select on mcp23018
296     if (mcp23018_status) {  // if there was an error
297                             // do nothing
298     } else {
299       // set active row low  : 0
300       // set other rows hi-Z : 1
301       mcp23018_status = i2c_start(I2C_ADDR_WRITE, ERGODOX_EZ_I2C_TIMEOUT);
302       if (mcp23018_status) goto out;
303       mcp23018_status = i2c_write(GPIOA, ERGODOX_EZ_I2C_TIMEOUT);
304       if (mcp23018_status) goto out;
305       mcp23018_status = i2c_write(0xFF & ~(1 << row), ERGODOX_EZ_I2C_TIMEOUT);
306       if (mcp23018_status) goto out;
307     out:
308       i2c_stop();
309     }
310   } else {
311     // select on teensy
312     // Output low(DDR:1, PORT:0) to select
313     switch (row) {
314       case 7:
315         DDRB |= (1 << 0);
316         PORTB &= ~(1 << 0);
317         break;
318       case 8:
319         DDRB |= (1 << 1);
320         PORTB &= ~(1 << 1);
321         break;
322       case 9:
323         DDRB |= (1 << 2);
324         PORTB &= ~(1 << 2);
325         break;
326       case 10:
327         DDRB |= (1 << 3);
328         PORTB &= ~(1 << 3);
329         break;
330       case 11:
331         DDRD |= (1 << 2);
332         PORTD &= ~(1 << 2);
333         break;
334       case 12:
335         DDRD |= (1 << 3);
336         PORTD &= ~(1 << 3);
337         break;
338       case 13:
339         DDRC |= (1 << 6);
340         PORTC &= ~(1 << 6);
341         break;
342     }
343   }
344 }