Fix Pointing Device code (#1934)
[jackhill/qmk/firmware.git] / quantum / matrix.c
CommitLineData
04885a3b 1/*
23839b8c 2Copyright 2012-2017 Jun Wako, Jack Humbert
04885a3b
JH
3
4This program is free software: you can redistribute it and/or modify
5it under the terms of the GNU General Public License as published by
6the Free Software Foundation, either version 2 of the License, or
7(at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License
15along with this program. If not, see <http://www.gnu.org/licenses/>.
16*/
04885a3b
JH
17#include <stdint.h>
18#include <stdbool.h>
4d4f7684 19#if defined(__AVR__)
04885a3b 20#include <avr/io.h>
4d4f7684 21#endif
aaa758f1 22#include "wait.h"
04885a3b
JH
23#include "print.h"
24#include "debug.h"
25#include "util.h"
26#include "matrix.h"
f4030289
I
27#include "timer.h"
28
29
30/* Set 0 if debouncing isn't needed */
31
32#ifndef DEBOUNCING_DELAY
33# define DEBOUNCING_DELAY 5
34#endif
35
36#if (DEBOUNCING_DELAY > 0)
37 static uint16_t debouncing_time;
38 static bool debouncing = false;
39#endif
04885a3b 40
508eddf8
I
41#if (MATRIX_COLS <= 8)
42# define print_matrix_header() print("\nr/c 01234567\n")
43# define print_matrix_row(row) print_bin_reverse8(matrix_get_row(row))
44# define matrix_bitpop(i) bitpop(matrix[i])
45# define ROW_SHIFTER ((uint8_t)1)
46#elif (MATRIX_COLS <= 16)
47# define print_matrix_header() print("\nr/c 0123456789ABCDEF\n")
48# define print_matrix_row(row) print_bin_reverse16(matrix_get_row(row))
49# define matrix_bitpop(i) bitpop16(matrix[i])
50# define ROW_SHIFTER ((uint16_t)1)
51#elif (MATRIX_COLS <= 32)
52# define print_matrix_header() print("\nr/c 0123456789ABCDEF0123456789ABCDEF\n")
53# define print_matrix_row(row) print_bin_reverse32(matrix_get_row(row))
54# define matrix_bitpop(i) bitpop32(matrix[i])
55# define ROW_SHIFTER ((uint32_t)1)
56#endif
57
17170ba7 58#ifdef MATRIX_MASKED
f4030289 59 extern const matrix_row_t matrix_mask[];
5bb7ef00
JH
60#endif
61
8cbf61c9 62#if (DIODE_DIRECTION == ROW2COL) || (DIODE_DIRECTION == COL2ROW)
13bb6b4b
JH
63static const uint8_t row_pins[MATRIX_ROWS] = MATRIX_ROW_PINS;
64static const uint8_t col_pins[MATRIX_COLS] = MATRIX_COL_PINS;
8cbf61c9 65#endif
8e88d55b
JH
66
67/* matrix state(1:on, 0:off) */
aaa758f1 68static matrix_row_t matrix[MATRIX_ROWS];
8e88d55b 69
32f88c07 70static matrix_row_t matrix_debouncing[MATRIX_ROWS];
4c696083
I
71
72
508eddf8
I
73#if (DIODE_DIRECTION == COL2ROW)
74 static void init_cols(void);
f4030289 75 static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row);
508eddf8
I
76 static void unselect_rows(void);
77 static void select_row(uint8_t row);
78 static void unselect_row(uint8_t row);
8cbf61c9 79#elif (DIODE_DIRECTION == ROW2COL)
508eddf8 80 static void init_rows(void);
f4030289 81 static bool read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col);
508eddf8
I
82 static void unselect_cols(void);
83 static void unselect_col(uint8_t col);
84 static void select_col(uint8_t col);
aaa758f1 85#endif
04885a3b 86
35a81f5b 87__attribute__ ((weak))
1a8c0dd2 88void matrix_init_quantum(void) {
13bb6b4b 89 matrix_init_kb();
641859df 90}
35a81f5b
JH
91
92__attribute__ ((weak))
1a8c0dd2 93void matrix_scan_quantum(void) {
13bb6b4b
JH
94 matrix_scan_kb();
95}
96
97__attribute__ ((weak))
98void matrix_init_kb(void) {
99 matrix_init_user();
100}
101
102__attribute__ ((weak))
103void matrix_scan_kb(void) {
104 matrix_scan_user();
105}
106
107__attribute__ ((weak))
108void matrix_init_user(void) {
109}
110
111__attribute__ ((weak))
112void matrix_scan_user(void) {
641859df 113}
35a81f5b 114
8e88d55b 115inline
aaa758f1 116uint8_t matrix_rows(void) {
04885a3b
JH
117 return MATRIX_ROWS;
118}
119
8e88d55b 120inline
aaa758f1 121uint8_t matrix_cols(void) {
04885a3b
JH
122 return MATRIX_COLS;
123}
124
215c2119 125// void matrix_power_up(void) {
508eddf8 126// #if (DIODE_DIRECTION == COL2ROW)
215c2119
JH
127// for (int8_t r = MATRIX_ROWS - 1; r >= 0; --r) {
128// /* DDRxn */
129// _SFR_IO8((row_pins[r] >> 4) + 1) |= _BV(row_pins[r] & 0xF);
130// toggle_row(r);
131// }
132// for (int8_t c = MATRIX_COLS - 1; c >= 0; --c) {
133// /* PORTxn */
134// _SFR_IO8((col_pins[c] >> 4) + 2) |= _BV(col_pins[c] & 0xF);
135// }
8cbf61c9 136// #elif (DIODE_DIRECTION == ROW2COL)
215c2119
JH
137// for (int8_t c = MATRIX_COLS - 1; c >= 0; --c) {
138// /* DDRxn */
139// _SFR_IO8((col_pins[c] >> 4) + 1) |= _BV(col_pins[c] & 0xF);
140// toggle_col(c);
141// }
142// for (int8_t r = MATRIX_ROWS - 1; r >= 0; --r) {
143// /* PORTxn */
144// _SFR_IO8((row_pins[r] >> 4) + 2) |= _BV(row_pins[r] & 0xF);
145// }
146// #endif
147// }
008c8d54 148
aaa758f1 149void matrix_init(void) {
508eddf8 150
8e88d55b 151 // To use PORTF disable JTAG with writing JTD bit twice within four cycles.
508eddf8 152 #if (defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1287__) || defined(__AVR_ATmega32U4__))
de577995
JH
153 MCUCR |= _BV(JTD);
154 MCUCR |= _BV(JTD);
155 #endif
8e88d55b
JH
156
157 // initialize row and col
508eddf8 158#if (DIODE_DIRECTION == COL2ROW)
8e88d55b
JH
159 unselect_rows();
160 init_cols();
8cbf61c9 161#elif (DIODE_DIRECTION == ROW2COL)
508eddf8
I
162 unselect_cols();
163 init_rows();
32f88c07 164#endif
508eddf8
I
165
166 // initialize matrix state: all keys off
167 for (uint8_t i=0; i < MATRIX_ROWS; i++) {
168 matrix[i] = 0;
32f88c07 169 matrix_debouncing[i] = 0;
508eddf8
I
170 }
171
1a8c0dd2 172 matrix_init_quantum();
04885a3b
JH
173}
174
8e88d55b
JH
175uint8_t matrix_scan(void)
176{
177
508eddf8
I
178#if (DIODE_DIRECTION == COL2ROW)
179
180 // Set row, read cols
4c696083 181 for (uint8_t current_row = 0; current_row < MATRIX_ROWS; current_row++) {
f4030289
I
182# if (DEBOUNCING_DELAY > 0)
183 bool matrix_changed = read_cols_on_row(matrix_debouncing, current_row);
04885a3b 184
f4030289
I
185 if (matrix_changed) {
186 debouncing = true;
187 debouncing_time = timer_read();
188 }
189
190# else
191 read_cols_on_row(matrix, current_row);
192# endif
193
194 }
508eddf8 195
8cbf61c9 196#elif (DIODE_DIRECTION == ROW2COL)
508eddf8
I
197
198 // Set col, read rows
4c696083 199 for (uint8_t current_col = 0; current_col < MATRIX_COLS; current_col++) {
f4030289
I
200# if (DEBOUNCING_DELAY > 0)
201 bool matrix_changed = read_rows_on_col(matrix_debouncing, current_col);
202 if (matrix_changed) {
203 debouncing = true;
204 debouncing_time = timer_read();
205 }
206# else
207 read_rows_on_col(matrix, current_col);
208# endif
8e88d55b 209
f4030289 210 }
508eddf8 211
8e88d55b
JH
212#endif
213
f4030289
I
214# if (DEBOUNCING_DELAY > 0)
215 if (debouncing && (timer_elapsed(debouncing_time) > DEBOUNCING_DELAY)) {
216 for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
217 matrix[i] = matrix_debouncing[i];
218 }
219 debouncing = false;
220 }
221# endif
222
aaa758f1
ET
223 matrix_scan_quantum();
224 return 1;
04885a3b
JH
225}
226
8e88d55b
JH
227bool matrix_is_modified(void)
228{
f4030289 229#if (DEBOUNCING_DELAY > 0)
8e88d55b 230 if (debouncing) return false;
f4030289 231#endif
8e88d55b 232 return true;
aaa758f1 233}
5bb7ef00 234
8e88d55b
JH
235inline
236bool matrix_is_on(uint8_t row, uint8_t col)
237{
238 return (matrix[row] & ((matrix_row_t)1<col));
239}
240
241inline
242matrix_row_t matrix_get_row(uint8_t row)
243{
17170ba7
I
244 // Matrix mask lets you disable switches in the returned matrix data. For example, if you have a
245 // switch blocker installed and the switch is always pressed.
246#ifdef MATRIX_MASKED
247 return matrix[row] & matrix_mask[row];
248#else
8e88d55b 249 return matrix[row];
17170ba7 250#endif
8e88d55b
JH
251}
252
253void matrix_print(void)
254{
508eddf8 255 print_matrix_header();
17170ba7 256
8e88d55b
JH
257 for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
258 phex(row); print(": ");
508eddf8 259 print_matrix_row(row);
8e88d55b 260 print("\n");
04885a3b 261 }
04885a3b
JH
262}
263
8e88d55b
JH
264uint8_t matrix_key_count(void)
265{
266 uint8_t count = 0;
267 for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
508eddf8 268 count += matrix_bitpop(i);
aaa758f1 269 }
8e88d55b 270 return count;
aaa758f1 271}
5bb7ef00 272
508eddf8
I
273
274
275#if (DIODE_DIRECTION == COL2ROW)
276
8e88d55b
JH
277static void init_cols(void)
278{
508eddf8
I
279 for(uint8_t x = 0; x < MATRIX_COLS; x++) {
280 uint8_t pin = col_pins[x];
281 _SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF); // IN
282 _SFR_IO8((pin >> 4) + 2) |= _BV(pin & 0xF); // HI
8e88d55b 283 }
04885a3b
JH
284}
285
f4030289 286static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row)
8e88d55b 287{
f4030289
I
288 // Store last value of row prior to reading
289 matrix_row_t last_row_value = current_matrix[current_row];
290
4c696083
I
291 // Clear data in matrix row
292 current_matrix[current_row] = 0;
5bb7ef00 293
4c696083
I
294 // Select row and wait for row selecton to stabilize
295 select_row(current_row);
296 wait_us(30);
508eddf8 297
4c696083
I
298 // For each col...
299 for(uint8_t col_index = 0; col_index < MATRIX_COLS; col_index++) {
300
301 // Select the col pin to read (active low)
302 uint8_t pin = col_pins[col_index];
303 uint8_t pin_state = (_SFR_IO8(pin >> 4) & _BV(pin & 0xF));
304
305 // Populate the matrix row with the state of the col pin
306 current_matrix[current_row] |= pin_state ? 0 : (ROW_SHIFTER << col_index);
307 }
32f88c07
I
308
309 // Unselect row
310 unselect_row(current_row);
f4030289 311
a06115df 312 return (last_row_value != current_matrix[current_row]);
04885a3b
JH
313}
314
508eddf8
I
315static void select_row(uint8_t row)
316{
317 uint8_t pin = row_pins[row];
318 _SFR_IO8((pin >> 4) + 1) |= _BV(pin & 0xF); // OUT
319 _SFR_IO8((pin >> 4) + 2) &= ~_BV(pin & 0xF); // LOW
320}
321
322static void unselect_row(uint8_t row)
323{
324 uint8_t pin = row_pins[row];
325 _SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF); // IN
326 _SFR_IO8((pin >> 4) + 2) |= _BV(pin & 0xF); // HI
327}
328
8e88d55b
JH
329static void unselect_rows(void)
330{
508eddf8
I
331 for(uint8_t x = 0; x < MATRIX_ROWS; x++) {
332 uint8_t pin = row_pins[x];
333 _SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF); // IN
334 _SFR_IO8((pin >> 4) + 2) |= _BV(pin & 0xF); // HI
aaa758f1 335 }
8e88d55b
JH
336}
337
8cbf61c9 338#elif (DIODE_DIRECTION == ROW2COL)
508eddf8
I
339
340static void init_rows(void)
8e88d55b 341{
508eddf8
I
342 for(uint8_t x = 0; x < MATRIX_ROWS; x++) {
343 uint8_t pin = row_pins[x];
344 _SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF); // IN
345 _SFR_IO8((pin >> 4) + 2) |= _BV(pin & 0xF); // HI
346 }
347}
8e88d55b 348
f4030289 349static bool read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col)
508eddf8 350{
f4030289 351 bool matrix_changed = false;
508eddf8 352
4c696083
I
353 // Select col and wait for col selecton to stabilize
354 select_col(current_col);
355 wait_us(30);
508eddf8 356
4c696083 357 // For each row...
f4030289
I
358 for(uint8_t row_index = 0; row_index < MATRIX_ROWS; row_index++)
359 {
360
361 // Store last value of row prior to reading
362 matrix_row_t last_row_value = current_matrix[row_index];
4c696083 363
32f88c07
I
364 // Check row pin state
365 if ((_SFR_IO8(row_pins[row_index] >> 4) & _BV(row_pins[row_index] & 0xF)) == 0)
366 {
367 // Pin LO, set col bit
368 current_matrix[row_index] |= (ROW_SHIFTER << current_col);
369 }
370 else
371 {
372 // Pin HI, clear col bit
373 current_matrix[row_index] &= ~(ROW_SHIFTER << current_col);
374 }
f4030289
I
375
376 // Determine if the matrix changed state
377 if ((last_row_value != current_matrix[row_index]) && !(matrix_changed))
378 {
379 matrix_changed = true;
380 }
4c696083 381 }
32f88c07
I
382
383 // Unselect col
384 unselect_col(current_col);
f4030289
I
385
386 return matrix_changed;
508eddf8
I
387}
388
389static void select_col(uint8_t col)
390{
391 uint8_t pin = col_pins[col];
392 _SFR_IO8((pin >> 4) + 1) |= _BV(pin & 0xF); // OUT
393 _SFR_IO8((pin >> 4) + 2) &= ~_BV(pin & 0xF); // LOW
394}
395
396static void unselect_col(uint8_t col)
397{
398 uint8_t pin = col_pins[col];
399 _SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF); // IN
400 _SFR_IO8((pin >> 4) + 2) |= _BV(pin & 0xF); // HI
aaa758f1 401}
508eddf8
I
402
403static void unselect_cols(void)
404{
405 for(uint8_t x = 0; x < MATRIX_COLS; x++) {
406 uint8_t pin = col_pins[x];
407 _SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF); // IN
408 _SFR_IO8((pin >> 4) + 2) |= _BV(pin & 0xF); // HI
409 }
410}
411
412#endif