]> git.donarmstrong.com Git - qmk_firmware.git/blob - keyboard/ergodox_ez/matrix.c
Updated readme to fix a typo and list out hotkey shortcuts
[qmk_firmware.git] / keyboard / 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 <util/delay.h>
31 #include "action_layer.h"
32 #include "print.h"
33 #include "debug.h"
34 #include "util.h"
35 #include "matrix.h"
36 #include "ergodox_ez.h"
37 #include "i2cmaster.h"
38 #ifdef DEBUG_MATRIX_SCAN_RATE
39 #include  "timer.h"
40 #endif
41
42 #ifndef DEBOUNCE
43 #   define DEBOUNCE     5
44 #endif
45 static uint8_t debouncing = DEBOUNCE;
46
47 /* matrix state(1:on, 0:off) */
48 static matrix_row_t matrix[MATRIX_ROWS];
49 static matrix_row_t matrix_debouncing[MATRIX_ROWS];
50
51 static matrix_row_t read_cols(uint8_t row);
52 static void init_cols(void);
53 static void unselect_rows();
54 static void select_row(uint8_t row);
55
56 static uint8_t mcp23018_reset_loop;
57
58 #ifdef DEBUG_MATRIX_SCAN_RATE
59 uint32_t matrix_timer;
60 uint32_t matrix_scan_count;
61 #endif
62
63
64 __attribute__ ((weak))
65 void matrix_init_kb(void) {
66 }
67
68 __attribute__ ((weak))
69 void matrix_scan_kb(void) {
70 }
71
72 inline
73 uint8_t matrix_rows(void)
74 {
75     return MATRIX_ROWS;
76 }
77
78 inline
79 uint8_t matrix_cols(void)
80 {
81     return MATRIX_COLS;
82 }
83
84 void matrix_init(void)
85 {
86     // initialize row and col
87
88     mcp23018_status = init_mcp23018();
89
90
91     unselect_rows();
92     init_cols();
93
94     // initialize matrix state: all keys off
95     for (uint8_t i=0; i < MATRIX_ROWS; i++) {
96         matrix[i] = 0;
97         matrix_debouncing[i] = 0;
98     }
99
100 #ifdef DEBUG_MATRIX_SCAN_RATE
101     matrix_timer = timer_read32();
102     matrix_scan_count = 0;
103 #endif
104
105     matrix_init_kb();
106
107 }
108
109 uint8_t matrix_scan(void)
110 {
111     if (mcp23018_status) { // if there was an error
112         if (++mcp23018_reset_loop == 0) {
113             // since mcp23018_reset_loop is 8 bit - we'll try to reset once in 255 matrix scans
114             // this will be approx bit more frequent than once per second
115             print("trying to reset mcp23018\n");
116             mcp23018_status = init_mcp23018();
117             if (mcp23018_status) {
118                 print("left side not responding\n");
119             } else {
120                 print("left side attached\n");
121                 ergodox_blink_all_leds();
122             }
123         }
124     }
125
126 #ifdef DEBUG_MATRIX_SCAN_RATE
127     matrix_scan_count++;
128
129     uint32_t timer_now = timer_read32();
130     if (TIMER_DIFF_32(timer_now, matrix_timer)>1000) {
131         print("matrix scan frequency: ");
132         pdec(matrix_scan_count);
133         print("\n");
134
135         matrix_timer = timer_now;
136         matrix_scan_count = 0;
137     }
138 #endif
139
140     for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
141         select_row(i);
142         matrix_row_t cols = read_cols(i);
143         if (matrix_debouncing[i] != cols) {
144             matrix_debouncing[i] = cols;
145             if (debouncing) {
146                 debug("bounce!: "); debug_hex(debouncing); debug("\n");
147             }
148             debouncing = DEBOUNCE;
149         }
150         unselect_rows();
151     }
152
153     if (debouncing) {
154         if (--debouncing) {
155             _delay_ms(1);
156         } else {
157             for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
158                 matrix[i] = matrix_debouncing[i];
159             }
160         }
161     }
162
163
164     matrix_scan_kb();
165
166     return 1;
167 }
168
169 bool matrix_is_modified(void)
170 {
171     if (debouncing) return false;
172     return true;
173 }
174
175 inline
176 bool matrix_is_on(uint8_t row, uint8_t col)
177 {
178     return (matrix[row] & ((matrix_row_t)1<<col));
179 }
180
181 inline
182 matrix_row_t matrix_get_row(uint8_t row)
183 {
184     return matrix[row];
185 }
186
187 void matrix_print(void)
188 {
189     print("\nr/c 0123456789ABCDEF\n");
190     for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
191         phex(row); print(": ");
192         pbin_reverse16(matrix_get_row(row));
193         print("\n");
194     }
195 }
196
197 uint8_t matrix_key_count(void)
198 {
199     uint8_t count = 0;
200     for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
201         count += bitpop16(matrix[i]);
202     }
203     return count;
204 }
205
206 /* Column pin configuration
207  *
208  * Teensy
209  * col: 0   1   2   3   4   5
210  * pin: F0  F1  F4  F5  F6  F7
211  *
212  * MCP23018
213  * col: 0   1   2   3   4   5
214  * pin: B5  B4  B3  B2  B1  B0
215  */
216 static void  init_cols(void)
217 {
218     // init on mcp23018
219     // not needed, already done as part of init_mcp23018()
220
221     // init on teensy
222     // Input with pull-up(DDR:0, PORT:1)
223     DDRF  &= ~(1<<7 | 1<<6 | 1<<5 | 1<<4 | 1<<1 | 1<<0);
224     PORTF |=  (1<<7 | 1<<6 | 1<<5 | 1<<4 | 1<<1 | 1<<0);
225 }
226
227 static matrix_row_t read_cols(uint8_t row)
228 {
229     if (row < 7) {
230         if (mcp23018_status) { // if there was an error
231             return 0;
232         } else {
233             uint8_t data = 0;
234             mcp23018_status = i2c_start(I2C_ADDR_WRITE);    if (mcp23018_status) goto out;
235             mcp23018_status = i2c_write(GPIOB);             if (mcp23018_status) goto out;
236             mcp23018_status = i2c_start(I2C_ADDR_READ);     if (mcp23018_status) goto out;
237             data = i2c_readNak();
238             data = ~data;
239         out:
240             i2c_stop();
241             return data;
242         }
243     } else {
244         _delay_us(30);  // without this wait read unstable value.
245         // read from teensy
246         return
247             (PINF&(1<<0) ? 0 : (1<<0)) |
248             (PINF&(1<<1) ? 0 : (1<<1)) |
249             (PINF&(1<<4) ? 0 : (1<<2)) |
250             (PINF&(1<<5) ? 0 : (1<<3)) |
251             (PINF&(1<<6) ? 0 : (1<<4)) |
252             (PINF&(1<<7) ? 0 : (1<<5)) ;
253     }
254 }
255
256 /* Row pin configuration
257  *
258  * Teensy
259  * row: 7   8   9   10  11  12  13
260  * pin: B0  B1  B2  B3  D2  D3  C6
261  *
262  * MCP23018
263  * row: 0   1   2   3   4   5   6
264  * pin: A0  A1  A2  A3  A4  A5  A6
265  */
266 static void unselect_rows(void)
267 {
268     // unselect on mcp23018
269     if (mcp23018_status) { // if there was an error
270         // do nothing
271     } else {
272         // set all rows hi-Z : 1
273         mcp23018_status = i2c_start(I2C_ADDR_WRITE);    if (mcp23018_status) goto out;
274         mcp23018_status = i2c_write(GPIOA);             if (mcp23018_status) goto out;
275         mcp23018_status = i2c_write( 0xFF
276                               & ~(0<<7)
277                           );                            if (mcp23018_status) goto out;
278     out:
279         i2c_stop();
280     }
281
282     // unselect on teensy
283     // Hi-Z(DDR:0, PORT:0) to unselect
284     DDRB  &= ~(1<<0 | 1<<1 | 1<<2 | 1<<3);
285     PORTB &= ~(1<<0 | 1<<1 | 1<<2 | 1<<3);
286     DDRD  &= ~(1<<2 | 1<<3);
287     PORTD &= ~(1<<2 | 1<<3);
288     DDRC  &= ~(1<<6);
289     PORTC &= ~(1<<6);
290 }
291
292 static void select_row(uint8_t row)
293 {
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);        if (mcp23018_status) goto out;
302             mcp23018_status = i2c_write(GPIOA);                 if (mcp23018_status) goto out;
303             mcp23018_status = i2c_write( 0xFF & ~(1<<row)
304                                   & ~(0<<7)
305                               );                                if (mcp23018_status) goto out;
306         out:
307             i2c_stop();
308         }
309     } else {
310         // select on teensy
311         // Output low(DDR:1, PORT:0) to select
312         switch (row) {
313             case 7:
314                 DDRB  |= (1<<0);
315                 PORTB &= ~(1<<0);
316                 break;
317             case 8:
318                 DDRB  |= (1<<1);
319                 PORTB &= ~(1<<1);
320                 break;
321             case 9:
322                 DDRB  |= (1<<2);
323                 PORTB &= ~(1<<2);
324                 break;
325             case 10:
326                 DDRB  |= (1<<3);
327                 PORTB &= ~(1<<3);
328                 break;
329             case 11:
330                 DDRD  |= (1<<2);
331                 PORTD &= ~(1<<3);
332                 break;
333             case 12:
334                 DDRD  |= (1<<3);
335                 PORTD &= ~(1<<3);
336                 break;
337             case 13:
338                 DDRC  |= (1<<6);
339                 PORTC &= ~(1<<6);
340                 break;
341         }
342     }
343 }
344