]> git.donarmstrong.com Git - qmk_firmware.git/blob - keyboards/handwired/frenchdev/matrix.c
[Keyboard] Add QMK configurator JSON for Alice PCB (#6397)
[qmk_firmware.git] / keyboards / handwired / frenchdev / matrix.c
1 /*
2
3 Note to self: adapted from ergodox EZ matrix
4 The "column" and "row" in here actually refers to the opposite on the keyboard
5 see definition of KEYMAP in v1.h, the grid is transposed so that a "row" in here is actually a "column" on the physical keyboard
6 Nicolas
7
8 Copyright 2013 Oleg Kostyuk <cub.uanic@gmail.com>
9 Copyright 2013 Nicolas Poirey <nicolas.poirey@gmail.com>
10
11 This program is free software: you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation, either version 2 of the License, or
14 (at your option) any later version.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with this program.  If not, see <http://www.gnu.org/licenses/>.
23 */
24
25 /*
26  * scan matrix
27  */
28 #include <stdint.h>
29 #include <stdbool.h>
30 #include <avr/io.h>
31 #include "wait.h"
32 #include "action_layer.h"
33 #include "print.h"
34 #include "debug.h"
35 #include "util.h"
36 #include "matrix.h"
37 #include "frenchdev.h"
38 #ifdef DEBUG_MATRIX_SCAN_RATE
39 #include  "timer.h"
40 #endif
41
42 /*
43  * This constant define not debouncing time in msecs, but amount of matrix
44  * scan loops which should be made to get stable debounced results.
45  *
46  * On Ergodox matrix scan rate is relatively low, because of slow I2C.
47  * Now it's only 317 scans/second, or about 3.15 msec/scan.
48  * According to Cherry specs, debouncing time is 5 msec.
49  *
50  * And so, there is no sense to have DEBOUNCE higher than 2.
51  */
52
53 #ifndef DEBOUNCE
54 #   define DEBOUNCE     5
55 #endif
56 static uint8_t debouncing = DEBOUNCE;
57
58 /* matrix state(1:on, 0:off) */
59 static matrix_row_t matrix[MATRIX_ROWS];
60 static matrix_row_t matrix_debouncing[MATRIX_ROWS];
61
62 static matrix_row_t read_cols(uint8_t row);
63 static void init_cols(void);
64 static void unselect_rows(void);
65 static void select_row(uint8_t row);
66
67 static uint8_t mcp23018_reset_loop;
68
69 #ifdef DEBUG_MATRIX_SCAN_RATE
70 uint32_t matrix_timer;
71 uint32_t matrix_scan_count;
72 #endif
73
74
75 __attribute__ ((weak))
76 void matrix_init_user(void) {}
77
78 __attribute__ ((weak))
79 void matrix_scan_user(void) {}
80
81 __attribute__ ((weak))
82 void matrix_init_kb(void) {
83   matrix_init_user();
84 }
85
86 __attribute__ ((weak))
87 void matrix_scan_kb(void) {
88   matrix_scan_user();
89 }
90
91 inline
92 uint8_t matrix_rows(void)
93 {
94     return MATRIX_ROWS;
95 }
96
97 inline
98 uint8_t matrix_cols(void)
99 {
100     return MATRIX_COLS;
101 }
102
103 void matrix_init(void)
104 {
105     // initialize row and col
106     debug_enable = true;
107     debug_matrix = true;
108     debug_keyboard = true;
109     debug_mouse = true;
110
111     mcp23018_status = init_mcp23018();
112
113
114     unselect_rows();
115     init_cols();
116
117     // initialize matrix state: all keys off
118     for (uint8_t i=0; i < MATRIX_ROWS; i++) {
119         matrix[i] = 0;
120         matrix_debouncing[i] = 0;
121     }
122
123 #ifdef DEBUG_MATRIX_SCAN_RATE
124     matrix_timer = timer_read32();
125     matrix_scan_count = 0;
126 #endif
127
128     matrix_init_quantum();
129
130 }
131
132 void matrix_power_up(void) {
133     mcp23018_status = init_mcp23018();
134
135     unselect_rows();
136     init_cols();
137
138     // initialize matrix state: all keys off
139     for (uint8_t i=0; i < MATRIX_ROWS; i++) {
140         matrix[i] = 0;
141         matrix_debouncing[i] = 0;
142     }
143
144 #ifdef DEBUG_MATRIX_SCAN_RATE
145     matrix_timer = timer_read32();
146     matrix_scan_count = 0;
147 #endif
148
149 }
150
151 uint8_t matrix_scan(void)
152 {
153     if (mcp23018_status) { // if there was an error
154         if (++mcp23018_reset_loop == 0) {
155             // since mcp23018_reset_loop is 8 bit - we'll try to reset once in 255 matrix scans
156             // this will be approx bit more frequent than once per second
157             print("trying to reset mcp23018\n");
158             mcp23018_status = init_mcp23018();
159             if (mcp23018_status) {
160                 print("left side not responding\n");
161             } else {
162                 print("left side attached\n");
163                 frenchdev_blink_all_leds();
164             }
165         }
166     }
167
168 #ifdef DEBUG_MATRIX_SCAN_RATE
169     matrix_scan_count++;
170
171     uint32_t timer_now = timer_read32();
172     if (TIMER_DIFF_32(timer_now, matrix_timer)>1000) {
173         print("matrix scan frequency: ");
174         pdec(matrix_scan_count);
175         print("\n");
176
177         matrix_timer = timer_now;
178         matrix_scan_count = 0;
179     }
180 #endif
181
182     for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
183         select_row(i);
184         wait_us(30);  // without this wait read unstable value.
185         matrix_row_t cols = read_cols(i);
186         if (matrix_debouncing[i] != cols) {
187             matrix_debouncing[i] = cols;
188             if (debouncing) {
189                 debug("bounce!: "); debug_hex(debouncing); debug("\n");
190             }
191             debouncing = DEBOUNCE;
192         }
193         unselect_rows();
194     }
195
196     if (debouncing) {
197         if (--debouncing) {
198             wait_us(1);
199             // this should be wait_ms(1) but has been left as-is at EZ's request
200         } else {
201             for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
202                 matrix[i] = matrix_debouncing[i];
203             }
204         }
205     }
206
207     matrix_scan_quantum();
208
209     return 1;
210 }
211
212 bool matrix_is_modified(void)
213 {
214     if (debouncing) return false;
215     return true;
216 }
217
218 inline
219 bool matrix_is_on(uint8_t row, uint8_t col)
220 {
221     return (matrix[row] & ((matrix_row_t)1<<col));
222 }
223
224 inline
225 matrix_row_t matrix_get_row(uint8_t row)
226 {
227     return matrix[row];
228 }
229
230 void matrix_print(void)
231 {
232     print("\nr/c 0123456789ABCDEF\n");
233     for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
234         phex(row); print(": ");
235         pbin_reverse16(matrix_get_row(row));
236         print("\n");
237     }
238 }
239
240 uint8_t matrix_key_count(void)
241 {
242     uint8_t count = 0;
243     for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
244         count += bitpop16(matrix[i]);
245     }
246     return count;
247 }
248
249 /* Column pin configuration
250  *
251  * Teensy
252  * col: 0   1   2   3   4   5
253  * pin: F0  F1  F4  F5  F6  F7
254  *
255  * MCP23018
256  * col: 0   1   2   3   4   5
257  * pin: B5  B4  B3  B2  B1  B0
258  */
259 static void  init_cols(void)
260 {
261     // init on mcp23018
262     // not needed, already done as part of init_mcp23018()
263
264     // init on teensy
265     // Input with pull-up(DDR:0, PORT:1)
266     DDRF  &= ~(1<<7 | 1<<6 | 1<<5 | 1<<4 | 1<<1 | 1<<0);
267     PORTF |=  (1<<7 | 1<<6 | 1<<5 | 1<<4 | 1<<1 | 1<<0);
268 }
269
270 static matrix_row_t read_cols(uint8_t row)
271 {
272     if (row < 8) {
273         if (mcp23018_status) { // if there was an error
274             return 0;
275         } else {
276             uint8_t data = 0;
277             mcp23018_status = i2c_start(I2C_ADDR_WRITE, I2C_TIMEOUT);   if (mcp23018_status) goto out;
278             mcp23018_status = i2c_write(GPIOB, I2C_TIMEOUT);            if (mcp23018_status) goto out;
279             mcp23018_status = i2c_start(I2C_ADDR_READ, I2C_TIMEOUT);    if (mcp23018_status) goto out;
280             data = i2c_read_nack(I2C_TIMEOUT);                         if (mcp23018_status < 0) goto out;
281             data = ~((uint8_t)mcp23018_status);
282             mcp23018_status = I2C_STATUS_SUCCESS;
283         out:
284             i2c_stop();
285             return data;
286         }
287     } else {
288         // read from teensy
289         return
290             (PINF&(1<<0) ? 0 : (1<<0)) |
291             (PINF&(1<<1) ? 0 : (1<<1)) |
292             (PINF&(1<<4) ? 0 : (1<<2)) |
293             (PINF&(1<<5) ? 0 : (1<<3)) |
294             (PINF&(1<<6) ? 0 : (1<<4)) |
295             (PINF&(1<<7) ? 0 : (1<<5)) ;
296     }
297 }
298
299 /* Row pin configuration
300  *
301  * Teensy
302  * row: 7   8   9   10  11  12  13
303  * pin: B0  B1  B2  B3  D2  D3  C6
304  *
305  * MCP23018
306  * row: 0   1   2   3   4   5   6
307  * pin: A0  A1  A2  A3  A4  A5  A6
308  */
309 static void unselect_rows(void)
310 {
311     // unselect on mcp23018
312     if (mcp23018_status) { // if there was an error
313         // do nothing
314     } else {
315         // set all rows hi-Z : 1
316         mcp23018_status = i2c_start(I2C_ADDR_WRITE, I2C_TIMEOUT);    if (mcp23018_status) goto out;
317         mcp23018_status = i2c_write(GPIOA, I2C_TIMEOUT);             if (mcp23018_status) goto out;
318         mcp23018_status = i2c_write( 0xFF & ~(0<<8), I2C_TIMEOUT);   if (mcp23018_status) goto out;
319     out:
320         i2c_stop();
321     }
322
323     // unselect on teensy
324     // Hi-Z(DDR:0, PORT:0) to unselect
325     DDRB  &= ~(1<<0 | 1<<1 | 1<<2 | 1<<3);
326     PORTB &= ~(1<<0 | 1<<1 | 1<<2 | 1<<3);
327     DDRD  &= ~(1<<2 | 1<<3);
328     PORTD &= ~(1<<2 | 1<<3);
329     DDRC  &= ~(1<<6 | 1<<7);
330     PORTC &= ~(1<<6 | 1<<7);
331 }
332
333 static void select_row(uint8_t row)
334 {
335     if (row < 8) {
336         // select on mcp23018
337         if (mcp23018_status) { // if there was an error
338             // do nothing
339         } else {
340             // set active row low  : 0
341             // set other rows hi-Z : 1
342             mcp23018_status = i2c_start(I2C_ADDR_WRITE, I2C_TIMEOUT);                          if (mcp23018_status) goto out;
343             mcp23018_status = i2c_write(GPIOA, I2C_TIMEOUT);                                   if (mcp23018_status) goto out;
344             mcp23018_status = i2c_write( 0xFF & ~(1<<row) & ~(0<<8), I2C_TIMEOUT);             if (mcp23018_status) goto out;
345         out:
346             i2c_stop();
347         }
348     } else {
349         // select on teensy
350         // Output low(DDR:1, PORT:0) to select
351         switch (row) {
352             case 8:
353                 DDRB  |= (1<<0);
354                 PORTB &= ~(1<<0);
355                 break;
356             case 9:
357                 DDRB  |= (1<<1);
358                 PORTB &= ~(1<<1);
359                 break;
360             case 10:
361                 DDRB  |= (1<<2);
362                 PORTB &= ~(1<<2);
363                 break;
364             case 11:
365                 DDRB  |= (1<<3);
366                 PORTB &= ~(1<<3);
367                 break;
368             case 12:
369                 DDRD  |= (1<<2);
370                 PORTD &= ~(1<<3);
371                 break;
372             case 13:
373                 DDRD  |= (1<<3);
374                 PORTD &= ~(1<<3);
375                 break;
376             case 14:
377                 DDRC  |= (1<<6);
378                 PORTC &= ~(1<<6);
379                 break;
380             case 15:
381                 DDRC  |= (1<<7);
382                 PORTC &= ~(1<<7);
383                 break;
384         }
385     }
386 }