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