aboutsummaryrefslogtreecommitdiff
path: root/quantum/matrix.c
diff options
context:
space:
mode:
Diffstat (limited to 'quantum/matrix.c')
-rw-r--r--quantum/matrix.c307
1 files changed, 307 insertions, 0 deletions
diff --git a/quantum/matrix.c b/quantum/matrix.c
new file mode 100644
index 000000000..094917025
--- /dev/null
+++ b/quantum/matrix.c
@@ -0,0 +1,307 @@
1/*
2Copyright 2012 Jun Wako
3Copyright 2014 Jack Humbert
4
5This program is free software: you can redistribute it and/or modify
6it under the terms of the GNU General Public License as published by
7the Free Software Foundation, either version 2 of the License, or
8(at your option) any later version.
9
10This program is distributed in the hope that it will be useful,
11but WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18#include <stdint.h>
19#include <stdbool.h>
20#if defined(__AVR__)
21#include <avr/io.h>
22#endif
23#include "wait.h"
24#include "print.h"
25#include "debug.h"
26#include "util.h"
27#include "matrix.h"
28
29/* Set 0 if debouncing isn't needed */
30/*
31 * This constant define not debouncing time in msecs, but amount of matrix
32 * scan loops which should be made to get stable debounced results.
33 *
34 * On Ergodox matrix scan rate is relatively low, because of slow I2C.
35 * Now it's only 317 scans/second, or about 3.15 msec/scan.
36 * According to Cherry specs, debouncing time is 5 msec.
37 *
38 * And so, there is no sense to have DEBOUNCE higher than 2.
39 */
40
41#ifndef DEBOUNCING_DELAY
42# define DEBOUNCING_DELAY 5
43#endif
44static uint8_t debouncing = DEBOUNCING_DELAY;
45
46static const uint8_t row_pins[MATRIX_ROWS] = MATRIX_ROW_PINS;
47static const uint8_t col_pins[MATRIX_COLS] = MATRIX_COL_PINS;
48
49/* matrix state(1:on, 0:off) */
50static matrix_row_t matrix[MATRIX_ROWS];
51static matrix_row_t matrix_debouncing[MATRIX_ROWS];
52
53#if DIODE_DIRECTION == ROW2COL
54 static matrix_row_t matrix_reversed[MATRIX_COLS];
55 static matrix_row_t matrix_reversed_debouncing[MATRIX_COLS];
56#endif
57
58#if MATRIX_COLS > 16
59 #define SHIFTER 1UL
60#else
61 #define SHIFTER 1
62#endif
63
64static matrix_row_t read_cols(void);
65static void init_cols(void);
66static void unselect_rows(void);
67static void select_row(uint8_t row);
68
69__attribute__ ((weak))
70void matrix_init_quantum(void) {
71 matrix_init_kb();
72}
73
74__attribute__ ((weak))
75void matrix_scan_quantum(void) {
76 matrix_scan_kb();
77}
78
79__attribute__ ((weak))
80void matrix_init_kb(void) {
81 matrix_init_user();
82}
83
84__attribute__ ((weak))
85void matrix_scan_kb(void) {
86 matrix_scan_user();
87}
88
89__attribute__ ((weak))
90void matrix_init_user(void) {
91}
92
93__attribute__ ((weak))
94void matrix_scan_user(void) {
95}
96
97inline
98uint8_t matrix_rows(void) {
99 return MATRIX_ROWS;
100}
101
102inline
103uint8_t matrix_cols(void) {
104 return MATRIX_COLS;
105}
106
107// void matrix_power_up(void) {
108// #if DIODE_DIRECTION == COL2ROW
109// for (int8_t r = MATRIX_ROWS - 1; r >= 0; --r) {
110// /* DDRxn */
111// _SFR_IO8((row_pins[r] >> 4) + 1) |= _BV(row_pins[r] & 0xF);
112// toggle_row(r);
113// }
114// for (int8_t c = MATRIX_COLS - 1; c >= 0; --c) {
115// /* PORTxn */
116// _SFR_IO8((col_pins[c] >> 4) + 2) |= _BV(col_pins[c] & 0xF);
117// }
118// #else
119// for (int8_t c = MATRIX_COLS - 1; c >= 0; --c) {
120// /* DDRxn */
121// _SFR_IO8((col_pins[c] >> 4) + 1) |= _BV(col_pins[c] & 0xF);
122// toggle_col(c);
123// }
124// for (int8_t r = MATRIX_ROWS - 1; r >= 0; --r) {
125// /* PORTxn */
126// _SFR_IO8((row_pins[r] >> 4) + 2) |= _BV(row_pins[r] & 0xF);
127// }
128// #endif
129// }
130
131void matrix_init(void) {
132 // To use PORTF disable JTAG with writing JTD bit twice within four cycles.
133 #ifdef __AVR_ATmega32U4__
134 MCUCR |= _BV(JTD);
135 MCUCR |= _BV(JTD);
136 #endif
137
138 // initialize row and col
139 unselect_rows();
140 init_cols();
141
142 // initialize matrix state: all keys off
143 for (uint8_t i=0; i < MATRIX_ROWS; i++) {
144 matrix[i] = 0;
145 matrix_debouncing[i] = 0;
146 }
147
148 matrix_init_quantum();
149}
150
151uint8_t matrix_scan(void)
152{
153
154#if DIODE_DIRECTION == COL2ROW
155 for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
156 select_row(i);
157 wait_us(30); // without this wait read unstable value.
158 matrix_row_t cols = read_cols();
159 if (matrix_debouncing[i] != cols) {
160 matrix_debouncing[i] = cols;
161 if (debouncing) {
162 debug("bounce!: "); debug_hex(debouncing); debug("\n");
163 }
164 debouncing = DEBOUNCING_DELAY;
165 }
166 unselect_rows();
167 }
168
169 if (debouncing) {
170 if (--debouncing) {
171 wait_us(1);
172 } else {
173 for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
174 matrix[i] = matrix_debouncing[i];
175 }
176 }
177 }
178#else
179 for (uint8_t i = 0; i < MATRIX_COLS; i++) {
180 select_row(i);
181 wait_us(30); // without this wait read unstable value.
182 matrix_row_t rows = read_cols();
183 if (matrix_reversed_debouncing[i] != rows) {
184 matrix_reversed_debouncing[i] = rows;
185 if (debouncing) {
186 debug("bounce!: "); debug_hex(debouncing); debug("\n");
187 }
188 debouncing = DEBOUNCING_DELAY;
189 }
190 unselect_rows();
191 }
192
193 if (debouncing) {
194 if (--debouncing) {
195 wait_us(1);
196 } else {
197 for (uint8_t i = 0; i < MATRIX_COLS; i++) {
198 matrix_reversed[i] = matrix_reversed_debouncing[i];
199 }
200 }
201 }
202 for (uint8_t y = 0; y < MATRIX_ROWS; y++) {
203 matrix_row_t row = 0;
204 for (uint8_t x = 0; x < MATRIX_COLS; x++) {
205 row |= ((matrix_reversed[x] & (1<<y)) >> y) << x;
206 }
207 matrix[y] = row;
208 }
209#endif
210
211 matrix_scan_quantum();
212
213 return 1;
214}
215
216bool matrix_is_modified(void)
217{
218 if (debouncing) return false;
219 return true;
220}
221
222inline
223bool matrix_is_on(uint8_t row, uint8_t col)
224{
225 return (matrix[row] & ((matrix_row_t)1<col));
226}
227
228inline
229matrix_row_t matrix_get_row(uint8_t row)
230{
231 return matrix[row];
232}
233
234void matrix_print(void)
235{
236 print("\nr/c 0123456789ABCDEF\n");
237 for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
238 phex(row); print(": ");
239 pbin_reverse16(matrix_get_row(row));
240 print("\n");
241 }
242}
243
244uint8_t matrix_key_count(void)
245{
246 uint8_t count = 0;
247 for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
248 count += bitpop16(matrix[i]);
249 }
250 return count;
251}
252
253static void init_cols(void)
254{
255#if DIODE_DIRECTION == COL2ROW
256 for(int x = 0; x < MATRIX_COLS; x++) {
257 int pin = col_pins[x];
258#else
259 for(int x = 0; x < MATRIX_ROWS; x++) {
260 int pin = row_pins[x];
261#endif
262 _SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF);
263 _SFR_IO8((pin >> 4) + 2) |= _BV(pin & 0xF);
264 }
265}
266
267static matrix_row_t read_cols(void)
268{
269 matrix_row_t result = 0;
270
271#if DIODE_DIRECTION == COL2ROW
272 for(int x = 0; x < MATRIX_COLS; x++) {
273 int pin = col_pins[x];
274#else
275 for(int x = 0; x < MATRIX_ROWS; x++) {
276 int pin = row_pins[x];
277#endif
278 result |= (_SFR_IO8(pin >> 4) & _BV(pin & 0xF)) ? 0 : (SHIFTER << x);
279 }
280 return result;
281}
282
283static void unselect_rows(void)
284{
285#if DIODE_DIRECTION == COL2ROW
286 for(int x = 0; x < MATRIX_ROWS; x++) {
287 int pin = row_pins[x];
288#else
289 for(int x = 0; x < MATRIX_COLS; x++) {
290 int pin = col_pins[x];
291#endif
292 _SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF);
293 _SFR_IO8((pin >> 4) + 2) |= _BV(pin & 0xF);
294 }
295}
296
297static void select_row(uint8_t row)
298{
299
300#if DIODE_DIRECTION == COL2ROW
301 int pin = row_pins[row];
302#else
303 int pin = col_pins[row];
304#endif
305 _SFR_IO8((pin >> 4) + 1) |= _BV(pin & 0xF);
306 _SFR_IO8((pin >> 4) + 2) &= ~_BV(pin & 0xF);
307}