]> git.donarmstrong.com Git - qmk_firmware.git/blob - keyboards/kmac/matrix.c
00da96604d38c14165065cec36dfe2317c36e8ad
[qmk_firmware.git] / keyboards / kmac / matrix.c
1 /*
2 Copyright 2017 Mathias Andersson <wraul@dbox.se>
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 #include <stdint.h>
18 #include <stdbool.h>
19 #if defined(__AVR__)
20 #include <avr/io.h>
21 #endif
22 #include "wait.h"
23 #include "print.h"
24 #include "debug.h"
25 #include "util.h"
26 #include "matrix.h"
27 #include "timer.h"
28
29
30 /* Set 0 if debouncing isn't needed */
31 #ifndef DEBOUNCE
32 #   define DEBOUNCE 5
33 #endif
34
35 #define COL_SHIFTER ((uint32_t)1)
36
37 static uint16_t debouncing_time;
38 static bool debouncing = false;
39
40
41 static const uint8_t row_pins[MATRIX_ROWS] = MATRIX_ROW_PINS;
42
43 /* matrix state(1:on, 0:off) */
44 static matrix_row_t matrix[MATRIX_ROWS];
45 static matrix_row_t matrix_debouncing[MATRIX_ROWS];
46
47 static void init_rows(void);
48 static bool read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col);
49 static void unselect_cols(void);
50 static void select_col(uint8_t col);
51
52 inline
53 uint8_t matrix_rows(void) {
54     return MATRIX_ROWS;
55 }
56
57 inline
58 uint8_t matrix_cols(void) {
59     return MATRIX_COLS;
60 }
61
62 void matrix_init(void) {
63     unselect_cols();
64     init_rows();
65
66     // initialize matrix state: all keys off
67     for (uint8_t i=0; i < MATRIX_ROWS; i++) {
68         matrix[i] = 0;
69         matrix_debouncing[i] = 0;
70     }
71
72     matrix_init_quantum();
73 }
74
75 uint8_t matrix_scan(void)
76 {
77     // Set col, read rows
78     for (uint8_t current_col = 0; current_col < MATRIX_COLS; current_col++) {
79         bool matrix_changed = read_rows_on_col(matrix_debouncing, current_col);
80         if (matrix_changed) {
81             debouncing = true;
82             debouncing_time = timer_read();
83         }
84     }
85
86     if (debouncing && (timer_elapsed(debouncing_time) > DEBOUNCE)) {
87         for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
88             matrix[i] = matrix_debouncing[i];
89         }
90         debouncing = false;
91     }
92
93     matrix_scan_quantum();
94     return 1;
95 }
96
97 inline
98 bool matrix_is_on(uint8_t row, uint8_t col)
99 {
100     return (matrix[row] & ((matrix_row_t)1<<col));
101 }
102
103 inline
104 matrix_row_t matrix_get_row(uint8_t row)
105 {
106     return matrix[row];
107 }
108
109 void matrix_print(void)
110 {
111     print("\nr/c 0123456789ABCDEFGHIJKLMNOPQRSTUV\n");
112
113     for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
114         phex(row); print(": ");
115         print_bin_reverse32(matrix_get_row(row));
116         print("\n");
117     }
118 }
119
120 uint8_t matrix_key_count(void)
121 {
122     uint8_t count = 0;
123     for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
124         count += bitpop32(matrix[i]);
125     }
126     return count;
127 }
128
129 static bool read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col)
130 {
131     bool matrix_changed = false;
132
133     // Select col and wait for col selecton to stabilize
134     select_col(current_col);
135     wait_us(30);
136
137     // For each row...
138     for(uint8_t row_index = 0; row_index < MATRIX_ROWS; row_index++)
139     {
140         // Store last value of row prior to reading
141         matrix_row_t last_row_value = current_matrix[row_index];
142
143         // Check row pin state
144         // Use the otherwise unused row: 3, col: 0 for caps lock
145         if (row_index == 3 && current_col == 0) {
146             // Pin E2 uses active low
147             if ((_SFR_IO8(E2 >> 4) & _BV(E2 & 0xF)) == 0)
148             {
149                 // Pin LO, set col bit
150                 current_matrix[row_index] |= (COL_SHIFTER << current_col);
151             }
152             else
153             {
154                 // Pin HI, clear col bit
155                 current_matrix[row_index] &= ~(COL_SHIFTER << current_col);
156             }
157         }
158         else {
159             if ((_SFR_IO8(row_pins[row_index] >> 4) & _BV(row_pins[row_index] & 0xF)))
160             {
161                 // Pin HI, set col bit
162                 current_matrix[row_index] |= (COL_SHIFTER << current_col);
163             }
164             else
165             {
166                 // Pin LO, clear col bit
167                 current_matrix[row_index] &= ~(COL_SHIFTER << current_col);
168             }
169         }
170
171         // Determine if the matrix changed state
172         if ((last_row_value != current_matrix[row_index]) && !(matrix_changed))
173         {
174             matrix_changed = true;
175         }
176     }
177
178     // Unselect cols
179     unselect_cols();
180
181     return matrix_changed;
182 }
183
184 /* Row pin configuration
185  * row: 0   1   2   3   4   5
186  * pin: D0  D1  D2  D3  D5  B7
187  *
188  * Caps lock uses its own pin E2
189  */
190 static void init_rows(void)
191 {
192     DDRD  &= ~((1<<0)| (1<<1) | (1<<2) | (1<<3) | (1<<5)); // IN
193     PORTD &= ~((1<<0)| (1<<1) | (1<<2) | (1<<3) | (1<<5)); // LO
194     DDRB  &= ~(1<<7); // IN
195     PORTB &= ~(1<<7); // LO
196
197     DDRE &= ~(1<<2); // IN
198     PORTE |= (1<<2); // HI
199 }
200
201 /* Columns 0 - 15
202  * These columns uses two 74HC237D 3 to 8 bit demultiplexers.
203  * col / pin:    PC6  PB6  PF0  PF1  PC7
204  * 0:             1    0    0    0    0
205  * 1:             1    0    1    0    0
206  * 2:             1    0    0    1    0
207  * 3:             1    0    1    1    0
208  * 4:             1    0    0    0    1
209  * 5:             1    0    1    0    1
210  * 6:             1    0    0    1    1
211  * 7:             1    0    1    1    1
212  * 8:             0    1    0    0    0
213  * 9:             0    1    1    0    0
214  * 10:            0    1    0    1    0
215  * 11:            0    1    1    1    0
216  * 12:            0    1    0    0    1
217  * 13:            0    1    1    0    1
218  * 14:            0    1    0    1    1
219  * 15:            0    1    1    1    1
220  *
221  * col: 16
222  * pin: PB5
223  */
224 static void unselect_cols(void)
225 {
226     DDRB  |= (1<<5) | (1<<6); // OUT
227     PORTB &= ~((1<<5) | (1<<6)); // LO
228
229     DDRC  |= (1<<6) | (1<<7); // OUT
230     PORTC &= ~((1<<6) | (1<<7)); // LO
231
232     DDRF  |= (1<<0) | (1<<1); // OUT
233     PORTF &= ~((1<<0) | (1<<1)); // LO
234 }
235
236 static void select_col(uint8_t col)
237 {
238     switch (col) {
239         case 0:
240             PORTC |= (1<<6); // HI
241             break;
242         case 1:
243             PORTC |= (1<<6); // HI
244             PORTF |= (1<<0); // HI
245             break;
246         case 2:
247             PORTC |= (1<<6); // HI
248             PORTF |= (1<<1); // HI
249             break;
250         case 3:
251             PORTC |= (1<<6); // HI
252             PORTF |= (1<<0) | (1<<1); // HI
253             break;
254         case 4:
255             PORTC |= (1<<6); // HI
256             PORTC |= (1<<7); // HI
257             break;
258         case 5:
259             PORTC |= (1<<6); // HI
260             PORTF |= (1<<0); // HI
261             PORTC |= (1<<7); // HI
262             break;
263         case 6:
264             PORTC |= (1<<6); // HI
265             PORTF |= (1<<1); // HI
266             PORTC |= (1<<7); // HI
267             break;
268         case 7:
269             PORTC |= (1<<6); // HI
270             PORTF |= (1<<0) | (1<<1); // HI
271             PORTC |= (1<<7); // HI
272             break;
273         case 8:
274             PORTB |= (1<<6); // HI
275             break;
276         case 9:
277             PORTB |= (1<<6); // HI
278             PORTF |= (1<<0); // HI
279             break;
280         case 10:
281             PORTB |= (1<<6); // HI
282             PORTF |= (1<<1); // HI
283             break;
284         case 11:
285             PORTB |= (1<<6); // HI
286             PORTF |= (1<<0) | (1<<1); // HI
287             break;
288         case 12:
289             PORTB |= (1<<6); // HI
290             PORTC |= (1<<7); // HI
291             break;
292         case 13:
293             PORTB |= (1<<6); // HI
294             PORTF |= (1<<0); // HI
295             PORTC |= (1<<7); // HI
296             break;
297         case 14:
298             PORTB |= (1<<6); // HI
299             PORTF |= (1<<1); // HI
300             PORTC |= (1<<7); // HI
301             break;
302         case 15:
303             PORTB |= (1<<6); // HI
304             PORTF |= (1<<0) | (1<<1); // HI
305             PORTC |= (1<<7); // HI
306             break;
307         case 16:
308             PORTB |= (1<<5); // HI
309             break;
310     }
311 }