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