]> git.donarmstrong.com Git - tmk_firmware.git/blob - keyboard/ergodox/matrix.c
Additional optimization, reach speed 368 scans/second
[tmk_firmware.git] / keyboard / ergodox / matrix.c
1 /*
2 Copyright 2013 Oleg Kostyuk <cub.uanic@gmail.com>
3
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 /*
19  * scan matrix
20  */
21 #include <stdint.h>
22 #include <stdbool.h>
23 #include <avr/io.h>
24 #include <util/delay.h>
25 #include "action_layer.h"
26 #include "print.h"
27 #include "debug.h"
28 #include "util.h"
29 #include "matrix.h"
30 #include "ergodox.h"
31 #include "i2cmaster.h"
32 #ifdef DEBUG_MATRIX_FREQ
33 #include  "timer.h"
34 #endif
35
36 #ifndef DEBOUNCE
37 #   define DEBOUNCE     5
38 #endif
39 static uint8_t debouncing = DEBOUNCE;
40
41 /* matrix state(1:on, 0:off) */
42 static matrix_row_t matrix[MATRIX_ROWS];
43 static matrix_row_t matrix_debouncing[MATRIX_ROWS];
44
45 static matrix_row_t read_cols(uint8_t row);
46 static void init_cols(void);
47 static void unselect_rows();
48 static void select_row(uint8_t row);
49
50 static uint8_t mcp23018_status;
51
52 #ifdef DEBUG_MATRIX_FREQ
53 uint32_t matrix_timer;
54 uint32_t matrix_scan_count;
55 #endif
56
57 inline
58 uint8_t matrix_rows(void)
59 {
60     return MATRIX_ROWS;
61 }
62
63 inline
64 uint8_t matrix_cols(void)
65 {
66     return MATRIX_COLS;
67 }
68
69 void matrix_init(void)
70 {
71     // initialize row and col
72     init_ergodox();
73     mcp23018_status = init_mcp23018();
74     unselect_rows();
75     init_cols();
76
77     // initialize matrix state: all keys off
78     for (uint8_t i=0; i < MATRIX_ROWS; i++) {
79         matrix[i] = 0;
80         matrix_debouncing[i] = 0;
81     }
82
83 #ifdef DEBUG_MATRIX_FREQ
84     matrix_timer = timer_read32();
85     matrix_scan_count = 0;
86 #endif
87 }
88
89 uint8_t matrix_scan(void)
90 {
91 #ifdef DEBUG_MATRIX_FREQ
92     matrix_scan_count++;
93
94     uint32_t timer_now = timer_read32();
95     if (TIMER_DIFF_32(timer_now, matrix_timer)>1000) {
96         print("matrix scan frequency: ");
97         pdec(matrix_scan_count);
98         print("\n");
99
100         matrix_timer = timer_now;
101         matrix_scan_count = 0;
102     }
103 #endif
104
105 #ifdef KEYMAP_CUB
106     uint8_t layer = biton32(layer_state);
107
108     if (layer == 1) {
109         ergodox_left_led_1_on();
110         ergodox_left_led_2_off();
111         ergodox_left_led_3_off();
112     } else if (layer == 2) {
113         ergodox_left_led_1_off();
114         ergodox_left_led_2_on();
115         ergodox_left_led_3_off();
116     } else if (layer == 3) {
117         ergodox_left_led_1_off();
118         ergodox_left_led_2_off();
119         ergodox_left_led_3_on();
120     } else if (layer == 4) {
121         ergodox_left_led_1_on();
122         ergodox_left_led_2_off();
123         ergodox_left_led_3_on();
124     } else if (layer == 5) {
125         ergodox_left_led_1_on();
126         ergodox_left_led_2_on();
127         ergodox_left_led_3_off();
128     } else if (layer == 6) {
129         ergodox_left_led_1_off();
130         ergodox_left_led_2_on();
131         ergodox_left_led_3_on();
132     } else if (layer == 7) {
133         ergodox_left_led_1_on();
134         ergodox_left_led_2_on();
135         ergodox_left_led_3_on();
136     } else {
137         ergodox_left_led_1_off();
138         ergodox_left_led_2_off();
139         ergodox_left_led_3_off();
140     }
141
142     // not actually needed because we already calling init_mcp23018() in next line
143     mcp23018_status = ergodox_left_leds_update();
144
145 #endif
146
147     for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
148         select_row(i);
149         matrix_row_t cols = read_cols(i);
150         if (matrix_debouncing[i] != cols) {
151             matrix_debouncing[i] = cols;
152             if (debouncing) {
153                 debug("bounce!: "); debug_hex(debouncing); debug("\n");
154             }
155             debouncing = DEBOUNCE;
156         }
157         unselect_rows();
158     }
159
160     if (debouncing) {
161         if (--debouncing) {
162             _delay_ms(1);
163         } else {
164             for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
165                 matrix[i] = matrix_debouncing[i];
166             }
167         }
168     }
169
170     return 1;
171 }
172
173 bool matrix_is_modified(void)
174 {
175     if (debouncing) return false;
176     return true;
177 }
178
179 inline
180 bool matrix_is_on(uint8_t row, uint8_t col)
181 {
182     return (matrix[row] & ((matrix_row_t)1<<col));
183 }
184
185 inline
186 matrix_row_t matrix_get_row(uint8_t row)
187 {
188     return matrix[row];
189 }
190
191 void matrix_print(void)
192 {
193     print("\nr/c 0123456789ABCDEF\n");
194     for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
195         phex(row); print(": ");
196         pbin_reverse16(matrix_get_row(row));
197         print("\n");
198     }
199 }
200
201 uint8_t matrix_key_count(void)
202 {
203     uint8_t count = 0;
204     for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
205         count += bitpop16(matrix[i]);
206     }
207     return count;
208 }
209
210 /* Column pin configuration
211  *
212  * Teensy
213  * col: 0   1   2   3   4   5
214  * pin: F0  F1  F4  F5  F6  F7 
215  *
216  * MCP23018
217  * col: 0   1   2   3   4   5
218  * pin: B5  B4  B3  B2  B1  B0 
219  */
220 static void  init_cols(void)
221 {
222     // init on mcp23018
223     // not needed, already done as part of init_mcp23018()
224
225     // init on teensy
226     // Input with pull-up(DDR:0, PORT:1)
227     DDRF  &= ~(1<<7 | 1<<6 | 1<<5 | 1<<4 | 1<<1 | 1<<0);
228     PORTF |=  (1<<7 | 1<<6 | 1<<5 | 1<<4 | 1<<1 | 1<<0);
229 }
230
231 static matrix_row_t read_cols(uint8_t row)
232 {
233     if (row < 7) {
234         if (mcp23018_status) { // if there was an error
235             return 0;
236         } else {
237             uint8_t data = 0;
238             mcp23018_status = i2c_start(I2C_ADDR_WRITE);    if (mcp23018_status) goto out;
239             mcp23018_status = i2c_write(GPIOB);             if (mcp23018_status) goto out;
240             mcp23018_status = i2c_start(I2C_ADDR_READ);     if (mcp23018_status) goto out;
241             data = i2c_readNak();
242             data = ~data;
243         out:
244             i2c_stop();
245             return data;
246         }
247     } else {
248         _delay_us(30);  // without this wait read unstable value.
249         // read from teensy
250         return
251             (PINF&(1<<0) ? 0 : (1<<0)) |
252             (PINF&(1<<1) ? 0 : (1<<1)) |
253             (PINF&(1<<4) ? 0 : (1<<2)) |
254             (PINF&(1<<5) ? 0 : (1<<3)) |
255             (PINF&(1<<6) ? 0 : (1<<4)) |
256             (PINF&(1<<7) ? 0 : (1<<5)) ;
257     }
258 }
259
260 /* Row pin configuration
261  *
262  * Teensy
263  * row: 7   8   9   10  11  12  13
264  * pin: B0  B1  B2  B3  D2  D3  C6
265  *
266  * MCP23018
267  * row: 0   1   2   3   4   5   6
268  * pin: A0  A1  A2  A3  A4  A5  A6
269  */
270 static void unselect_rows(void)
271 {
272     // unselect on mcp23018
273     if (mcp23018_status) { // if there was an error
274         // do nothing
275     } else {
276         // set all rows hi-Z : 1
277         mcp23018_status = i2c_start(I2C_ADDR_WRITE);    if (mcp23018_status) goto out;
278         mcp23018_status = i2c_write(GPIOA);             if (mcp23018_status) goto out;
279         mcp23018_status = i2c_write( 0xFF
280                               & ~(ergodox_left_led_3<<LEFT_LED_3_SHIFT)
281                           );                            if (mcp23018_status) goto out;
282     out:
283         i2c_stop();
284     }
285
286     // unselect on teensy
287     // Hi-Z(DDR:0, PORT:0) to unselect
288     DDRB  &= ~(1<<0 | 1<<1 | 1<<2 | 1<<3);
289     PORTB &= ~(1<<0 | 1<<1 | 1<<2 | 1<<3);
290     DDRD  &= ~(1<<2 | 1<<3);
291     PORTD &= ~(1<<2 | 1<<3);
292     DDRC  &= ~(1<<6);
293     PORTC &= ~(1<<6);
294 }
295
296 static void select_row(uint8_t row)
297 {
298     if (row < 7) {
299         // select on mcp23018
300         if (mcp23018_status) { // if there was an error
301             // do nothing
302         } else {
303             // set active row low  : 0
304             // set other rows hi-Z : 1
305             mcp23018_status = i2c_start(I2C_ADDR_WRITE);        if (mcp23018_status) goto out;
306             mcp23018_status = i2c_write(GPIOA);                 if (mcp23018_status) goto out;
307             mcp23018_status = i2c_write( 0xFF & ~(1<<row) 
308                                   & ~(ergodox_left_led_3<<LEFT_LED_3_SHIFT)
309                               );                                if (mcp23018_status) goto out;
310         out:
311             i2c_stop();
312         }
313     } else {
314         // select on teensy
315         // Output low(DDR:1, PORT:0) to select
316         switch (row) {
317             case 7:
318                 DDRB  |= (1<<0);
319                 PORTB &= ~(1<<0);
320                 break;
321             case 8:
322                 DDRB  |= (1<<1);
323                 PORTB &= ~(1<<1);
324                 break;
325             case 9:
326                 DDRB  |= (1<<2);
327                 PORTB &= ~(1<<2);
328                 break;
329             case 10:
330                 DDRB  |= (1<<3);
331                 PORTB &= ~(1<<3);
332                 break;
333             case 11:
334                 DDRD  |= (1<<2);
335                 PORTD &= ~(1<<3);
336                 break;
337             case 12:
338                 DDRD  |= (1<<3);
339                 PORTD &= ~(1<<3);
340                 break;
341             case 13:
342                 DDRC  |= (1<<6);
343                 PORTC &= ~(1<<6);
344                 break;
345         }
346     }
347 }
348