]> git.donarmstrong.com Git - qmk_firmware.git/blob - keyboards/handwired/frenchdev/matrix.c
Merge pull request #1418 from npoirey/master
[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 #include "i2cmaster.h"
44 #ifdef DEBUG_MATRIX_SCAN_RATE
45 #include  "timer.h"
46 #endif
47
48 /*
49  * This constant define not debouncing time in msecs, but amount of matrix
50  * scan loops which should be made to get stable debounced results.
51  *
52  * On Ergodox matrix scan rate is relatively low, because of slow I2C.
53  * Now it's only 317 scans/second, or about 3.15 msec/scan.
54  * According to Cherry specs, debouncing time is 5 msec.
55  *
56  * And so, there is no sense to have DEBOUNCE higher than 2.
57  */
58
59 #ifndef DEBOUNCE
60 #   define DEBOUNCE     5
61 #endif
62 static uint8_t debouncing = DEBOUNCE;
63
64 /* matrix state(1:on, 0:off) */
65 static matrix_row_t matrix[MATRIX_ROWS];
66 static matrix_row_t matrix_debouncing[MATRIX_ROWS];
67
68 static matrix_row_t read_cols(uint8_t row);
69 static void init_cols(void);
70 static void unselect_rows(void);
71 static void select_row(uint8_t row);
72
73 static uint8_t mcp23018_reset_loop;
74
75 #ifdef DEBUG_MATRIX_SCAN_RATE
76 uint32_t matrix_timer;
77 uint32_t matrix_scan_count;
78 #endif
79
80
81 __attribute__ ((weak))
82 void matrix_init_user(void) {}
83
84 __attribute__ ((weak))
85 void matrix_scan_user(void) {}
86
87 __attribute__ ((weak))
88 void matrix_init_kb(void) {
89   matrix_init_user();
90 }
91
92 __attribute__ ((weak))
93 void matrix_scan_kb(void) {
94   matrix_scan_user();
95 }
96
97 inline
98 uint8_t matrix_rows(void)
99 {
100     return MATRIX_ROWS;
101 }
102
103 inline
104 uint8_t matrix_cols(void)
105 {
106     return MATRIX_COLS;
107 }
108
109 void matrix_init(void)
110 {
111     // initialize row and col
112     debug_enable = true;
113     debug_matrix = true;
114     debug_keyboard = true;
115     debug_mouse = true;
116
117     mcp23018_status = init_mcp23018();
118
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     matrix_init_quantum();
135
136 }
137
138 void matrix_power_up(void) {
139     mcp23018_status = init_mcp23018();
140
141     unselect_rows();
142     init_cols();
143
144     // initialize matrix state: all keys off
145     for (uint8_t i=0; i < MATRIX_ROWS; i++) {
146         matrix[i] = 0;
147         matrix_debouncing[i] = 0;
148     }
149
150 #ifdef DEBUG_MATRIX_SCAN_RATE
151     matrix_timer = timer_read32();
152     matrix_scan_count = 0;
153 #endif
154
155 }
156
157 uint8_t matrix_scan(void)
158 {
159     if (mcp23018_status) { // if there was an error
160         if (++mcp23018_reset_loop == 0) {
161             // since mcp23018_reset_loop is 8 bit - we'll try to reset once in 255 matrix scans
162             // this will be approx bit more frequent than once per second
163             print("trying to reset mcp23018\n");
164             mcp23018_status = init_mcp23018();
165             if (mcp23018_status) {
166                 print("left side not responding\n");
167             } else {
168                 print("left side attached\n");
169                 frenchdev_blink_all_leds();
170             }
171         }
172     }
173
174 #ifdef DEBUG_MATRIX_SCAN_RATE
175     matrix_scan_count++;
176
177     uint32_t timer_now = timer_read32();
178     if (TIMER_DIFF_32(timer_now, matrix_timer)>1000) {
179         print("matrix scan frequency: ");
180         pdec(matrix_scan_count);
181         print("\n");
182
183         matrix_timer = timer_now;
184         matrix_scan_count = 0;
185     }
186 #endif
187
188     for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
189         select_row(i);
190         wait_us(30);  // without this wait read unstable value.
191         matrix_row_t cols = read_cols(i);
192         if (matrix_debouncing[i] != cols) {
193             matrix_debouncing[i] = cols;
194             if (debouncing) {
195                 debug("bounce!: "); debug_hex(debouncing); debug("\n");
196             }
197             debouncing = DEBOUNCE;
198         }
199         unselect_rows();
200     }
201
202     if (debouncing) {
203         if (--debouncing) {
204             wait_us(1);
205             // this should be wait_ms(1) but has been left as-is at EZ's request
206         } else {
207             for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
208                 matrix[i] = matrix_debouncing[i];
209             }
210         }
211     }
212
213     matrix_scan_quantum();
214
215     return 1;
216 }
217
218 bool matrix_is_modified(void)
219 {
220     if (debouncing) return false;
221     return true;
222 }
223
224 inline
225 bool matrix_is_on(uint8_t row, uint8_t col)
226 {
227     return (matrix[row] & ((matrix_row_t)1<<col));
228 }
229
230 inline
231 matrix_row_t matrix_get_row(uint8_t row)
232 {
233     return matrix[row];
234 }
235
236 void matrix_print(void)
237 {
238     print("\nr/c 0123456789ABCDEF\n");
239     for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
240         phex(row); print(": ");
241         pbin_reverse16(matrix_get_row(row));
242         print("\n");
243     }
244 }
245
246 uint8_t matrix_key_count(void)
247 {
248     uint8_t count = 0;
249     for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
250         count += bitpop16(matrix[i]);
251     }
252     return count;
253 }
254
255 /* Column pin configuration
256  *
257  * Teensy
258  * col: 0   1   2   3   4   5
259  * pin: F0  F1  F4  F5  F6  F7
260  *
261  * MCP23018
262  * col: 0   1   2   3   4   5
263  * pin: B5  B4  B3  B2  B1  B0
264  */
265 static void  init_cols(void)
266 {
267     // init on mcp23018
268     // not needed, already done as part of init_mcp23018()
269
270     // init on teensy
271     // Input with pull-up(DDR:0, PORT:1)
272     DDRF  &= ~(1<<7 | 1<<6 | 1<<5 | 1<<4 | 1<<1 | 1<<0);
273     PORTF |=  (1<<7 | 1<<6 | 1<<5 | 1<<4 | 1<<1 | 1<<0);
274 }
275
276 static matrix_row_t read_cols(uint8_t row)
277 {
278     if (row < 8) {
279         if (mcp23018_status) { // if there was an error
280             return 0;
281         } else {
282             uint8_t data = 0;
283             mcp23018_status = i2c_start(I2C_ADDR_WRITE);    if (mcp23018_status) goto out;
284             mcp23018_status = i2c_write(GPIOB);             if (mcp23018_status) goto out;
285             mcp23018_status = i2c_start(I2C_ADDR_READ);     if (mcp23018_status) goto out;
286             data = i2c_readNak();
287             data = ~data;
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);    if (mcp23018_status) goto out;
322         mcp23018_status = i2c_write(GPIOA);             if (mcp23018_status) goto out;
323         mcp23018_status = i2c_write( 0xFF
324                               & ~(0<<8)
325                           );                            if (mcp23018_status) goto out;
326     out:
327         i2c_stop();
328     }
329
330     // unselect on teensy
331     // Hi-Z(DDR:0, PORT:0) to unselect
332     DDRB  &= ~(1<<0 | 1<<1 | 1<<2 | 1<<3);
333     PORTB &= ~(1<<0 | 1<<1 | 1<<2 | 1<<3);
334     DDRD  &= ~(1<<2 | 1<<3);
335     PORTD &= ~(1<<2 | 1<<3);
336     DDRC  &= ~(1<<6 | 1<<7);
337     PORTC &= ~(1<<6 | 1<<7);
338 }
339
340 static void select_row(uint8_t row)
341 {
342     if (row < 8) {
343         // select on mcp23018
344         if (mcp23018_status) { // if there was an error
345             // do nothing
346         } else {
347             // set active row low  : 0
348             // set other rows hi-Z : 1
349             mcp23018_status = i2c_start(I2C_ADDR_WRITE);        if (mcp23018_status) goto out;
350             mcp23018_status = i2c_write(GPIOA);                 if (mcp23018_status) goto out;
351             mcp23018_status = i2c_write( 0xFF & ~(1<<row)
352                                   & ~(0<<8)
353                               );                                if (mcp23018_status) goto out;
354         out:
355             i2c_stop();
356         }
357     } else {
358         // select on teensy
359         // Output low(DDR:1, PORT:0) to select
360         switch (row) {
361             case 8:
362                 DDRB  |= (1<<0);
363                 PORTB &= ~(1<<0);
364                 break;
365             case 9:
366                 DDRB  |= (1<<1);
367                 PORTB &= ~(1<<1);
368                 break;
369             case 10:
370                 DDRB  |= (1<<2);
371                 PORTB &= ~(1<<2);
372                 break;
373             case 11:
374                 DDRB  |= (1<<3);
375                 PORTB &= ~(1<<3);
376                 break;
377             case 12:
378                 DDRD  |= (1<<2);
379                 PORTD &= ~(1<<3);
380                 break;
381             case 13:
382                 DDRD  |= (1<<3);
383                 PORTD &= ~(1<<3);
384                 break;
385             case 14:
386                 DDRC  |= (1<<6);
387                 PORTC &= ~(1<<6);
388                 break;
389             case 15:
390                 DDRC  |= (1<<7);
391                 PORTC &= ~(1<<7);
392                 break;
393         }
394     }
395 }
396