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