]> git.donarmstrong.com Git - qmk_firmware.git/blob - keyboards/ergodox_ez/matrix.c
Add 'quantum/serial_link/' from commit 'a20d513e3cdacbf6e0e70a80402497ad10166434'
[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 "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         wait_us(30);  // without this wait read unstable value.
170         matrix_row_t cols = read_cols(i);
171         if (matrix_debouncing[i] != cols) {
172             matrix_debouncing[i] = cols;
173             if (debouncing) {
174                 debug("bounce!: "); debug_hex(debouncing); debug("\n");
175             }
176             debouncing = DEBOUNCE;
177         }
178         unselect_rows();
179     }
180
181     if (debouncing) {
182         if (--debouncing) {
183             wait_us(1);
184         } else {
185             for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
186                 matrix[i] = matrix_debouncing[i];
187             }
188         }
189     }
190
191     matrix_scan_quantum();
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         // read from teensy
272         return
273             (PINF&(1<<0) ? 0 : (1<<0)) |
274             (PINF&(1<<1) ? 0 : (1<<1)) |
275             (PINF&(1<<4) ? 0 : (1<<2)) |
276             (PINF&(1<<5) ? 0 : (1<<3)) |
277             (PINF&(1<<6) ? 0 : (1<<4)) |
278             (PINF&(1<<7) ? 0 : (1<<5)) ;
279     }
280 }
281
282 /* Row pin configuration
283  *
284  * Teensy
285  * row: 7   8   9   10  11  12  13
286  * pin: B0  B1  B2  B3  D2  D3  C6
287  *
288  * MCP23018
289  * row: 0   1   2   3   4   5   6
290  * pin: A0  A1  A2  A3  A4  A5  A6
291  */
292 static void unselect_rows(void)
293 {
294     // unselect on mcp23018
295     if (mcp23018_status) { // if there was an error
296         // do nothing
297     } else {
298         // set all rows hi-Z : 1
299         mcp23018_status = i2c_start(I2C_ADDR_WRITE);    if (mcp23018_status) goto out;
300         mcp23018_status = i2c_write(GPIOA);             if (mcp23018_status) goto out;
301         mcp23018_status = i2c_write( 0xFF
302                               & ~(0<<7)
303                           );                            if (mcp23018_status) goto out;
304     out:
305         i2c_stop();
306     }
307
308     // unselect on teensy
309     // Hi-Z(DDR:0, PORT:0) to unselect
310     DDRB  &= ~(1<<0 | 1<<1 | 1<<2 | 1<<3);
311     PORTB &= ~(1<<0 | 1<<1 | 1<<2 | 1<<3);
312     DDRD  &= ~(1<<2 | 1<<3);
313     PORTD &= ~(1<<2 | 1<<3);
314     DDRC  &= ~(1<<6);
315     PORTC &= ~(1<<6);
316 }
317
318 static void select_row(uint8_t row)
319 {
320     if (row < 7) {
321         // select on mcp23018
322         if (mcp23018_status) { // if there was an error
323             // do nothing
324         } else {
325             // set active row low  : 0
326             // set other rows hi-Z : 1
327             mcp23018_status = i2c_start(I2C_ADDR_WRITE);        if (mcp23018_status) goto out;
328             mcp23018_status = i2c_write(GPIOA);                 if (mcp23018_status) goto out;
329             mcp23018_status = i2c_write( 0xFF & ~(1<<row)
330                                   & ~(0<<7)
331                               );                                if (mcp23018_status) goto out;
332         out:
333             i2c_stop();
334         }
335     } else {
336         // select on teensy
337         // Output low(DDR:1, PORT:0) to select
338         switch (row) {
339             case 7:
340                 DDRB  |= (1<<0);
341                 PORTB &= ~(1<<0);
342                 break;
343             case 8:
344                 DDRB  |= (1<<1);
345                 PORTB &= ~(1<<1);
346                 break;
347             case 9:
348                 DDRB  |= (1<<2);
349                 PORTB &= ~(1<<2);
350                 break;
351             case 10:
352                 DDRB  |= (1<<3);
353                 PORTB &= ~(1<<3);
354                 break;
355             case 11:
356                 DDRD  |= (1<<2);
357                 PORTD &= ~(1<<3);
358                 break;
359             case 12:
360                 DDRD  |= (1<<3);
361                 PORTD &= ~(1<<3);
362                 break;
363             case 13:
364                 DDRC  |= (1<<6);
365                 PORTC &= ~(1<<6);
366                 break;
367         }
368     }
369 }
370