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