aboutsummaryrefslogtreecommitdiff
path: root/keyboards/fc980c/matrix.c
diff options
context:
space:
mode:
Diffstat (limited to 'keyboards/fc980c/matrix.c')
-rw-r--r--keyboards/fc980c/matrix.c228
1 files changed, 228 insertions, 0 deletions
diff --git a/keyboards/fc980c/matrix.c b/keyboards/fc980c/matrix.c
new file mode 100644
index 000000000..906fec29a
--- /dev/null
+++ b/keyboards/fc980c/matrix.c
@@ -0,0 +1,228 @@
1/*
2Copyright 2017 Balz Guenat
3based on work by Jun Wako <wakojun@gmail.com>
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
19/*
20 * scan matrix
21 */
22#include <stdint.h>
23#include <stdbool.h>
24#include <util/delay.h>
25#include "print.h"
26#include "debug.h"
27#include "util.h"
28#include "timer.h"
29#include "matrix.h"
30#include "led.h"
31// #include "fc980c.h"
32
33
34// Timer resolution check
35#if (1000000/TIMER_RAW_FREQ > 20)
36# error "Timer resolution(>20us) is not enough for HHKB matrix scan tweak on V-USB."
37#endif
38
39
40/*
41 * Pin configuration for ATMega32U4
42 *
43 * Row: PD4-6, PD7(~EN)
44 * Col: PB0-3
45 * Key: PC6(pull-uped)
46 * Hys: PC7
47 */
48static inline void KEY_ENABLE(void) { (PORTD &= ~(1<<7)); }
49static inline void KEY_UNABLE(void) { (PORTD |= (1<<7)); }
50static inline bool KEY_STATE(void) { return (PINC & (1<<6)); }
51static inline void KEY_HYS_ON(void) { (PORTC |= (1<<7)); }
52static inline void KEY_HYS_OFF(void) { (PORTC &= ~(1<<7)); }
53static inline void KEY_INIT(void)
54{
55 /* Col */
56 DDRB |= 0x0F;
57 /* Key: input with pull-up */
58 DDRC &= ~(1<<6);
59 PORTC |= (1<<6);
60 /* Hys */
61 DDRC |= (1<<7);
62 /* Row */
63 DDRD |= 0xF0;
64
65 KEY_UNABLE();
66 KEY_HYS_OFF();
67}
68static inline void SET_ROW(uint8_t ROW)
69{
70 // PD4-6
71 PORTD = (PORTD & 0x8F) | ((ROW & 0x07) << 4);
72}
73static inline void SET_COL(uint8_t COL)
74{
75 // PB0-3
76 PORTB = (PORTB & 0xF0) | (COL & 0x0F);
77}
78
79static uint32_t matrix_last_modified = 0;
80
81// matrix state buffer(1:on, 0:off)
82static matrix_row_t *matrix;
83static matrix_row_t *matrix_prev;
84static matrix_row_t _matrix0[MATRIX_ROWS];
85static matrix_row_t _matrix1[MATRIX_ROWS];
86
87
88__attribute__ ((weak))
89void matrix_init_quantum(void) {
90 matrix_init_kb();
91}
92
93__attribute__ ((weak))
94void matrix_scan_quantum(void) {
95 matrix_scan_kb();
96}
97
98__attribute__ ((weak))
99void matrix_init_kb(void) {
100 matrix_init_user();
101}
102
103__attribute__ ((weak))
104void matrix_scan_kb(void) {
105 matrix_scan_user();
106}
107
108__attribute__ ((weak))
109void matrix_init_user(void) {
110}
111
112__attribute__ ((weak))
113void matrix_scan_user(void) {
114}
115
116
117void matrix_init(void)
118{
119 debug_enable = true;
120 debug_matrix = true;
121
122 KEY_INIT();
123
124 // LEDs on NumLock, CapsLock and ScrollLock(PB4, PB5, PB6)
125 DDRB |= (1<<4) | (1<<5) | (1<<6);
126 PORTB |= (1<<4) | (1<<5) | (1<<6);
127
128 // initialize matrix state: all keys off
129 for (uint8_t i=0; i < MATRIX_ROWS; i++) _matrix0[i] = 0x00;
130 for (uint8_t i=0; i < MATRIX_ROWS; i++) _matrix1[i] = 0x00;
131 matrix = _matrix0;
132 matrix_prev = _matrix1;
133 matrix_init_quantum();
134}
135
136uint8_t matrix_scan(void)
137{
138 matrix_row_t *tmp;
139
140 tmp = matrix_prev;
141 matrix_prev = matrix;
142 matrix = tmp;
143
144 uint8_t row, col;
145 for (col = 0; col < MATRIX_COLS; col++) {
146 SET_COL(col);
147 for (row = 0; row < MATRIX_ROWS; row++) {
148 //KEY_SELECT(row, col);
149 SET_ROW(row);
150 _delay_us(2);
151
152 // Not sure this is needed. This just emulates HHKB controller's behaviour.
153 if (matrix_prev[row] & (1<<col)) {
154 KEY_HYS_ON();
155 }
156 _delay_us(10);
157
158 // NOTE: KEY_STATE is valid only in 20us after KEY_ENABLE.
159 // If V-USB interrupts in this section we could lose 40us or so
160 // and would read invalid value from KEY_STATE.
161 uint8_t last = TIMER_RAW;
162
163 KEY_ENABLE();
164
165 // Wait for KEY_STATE outputs its value.
166 _delay_us(2);
167
168 if (KEY_STATE()) {
169 matrix[row] &= ~(1<<col);
170 } else {
171 matrix[row] |= (1<<col);
172 }
173
174 // Ignore if this code region execution time elapses more than 20us.
175 // MEMO: 20[us] * (TIMER_RAW_FREQ / 1000000)[count per us]
176 // MEMO: then change above using this rule: a/(b/c) = a*1/(b/c) = a*(c/b)
177 if (TIMER_DIFF_RAW(TIMER_RAW, last) > 20/(1000000/TIMER_RAW_FREQ)) {
178 matrix[row] = matrix_prev[row];
179 }
180
181 _delay_us(5);
182 KEY_HYS_OFF();
183 KEY_UNABLE();
184
185 // NOTE: KEY_STATE keep its state in 20us after KEY_ENABLE.
186 // This takes 25us or more to make sure KEY_STATE returns to idle state.
187 _delay_us(75);
188 }
189 if (matrix[row] ^ matrix_prev[row]) {
190 matrix_last_modified = timer_read32();
191 }
192 }
193 matrix_scan_quantum();
194 return 1;
195}
196
197inline
198matrix_row_t matrix_get_row(uint8_t row) {
199 return matrix[row];
200}
201
202void matrix_print(void)
203{
204#if (MATRIX_COLS <= 8)
205 print("r/c 01234567\n");
206#elif (MATRIX_COLS <= 16)
207 print("r/c 0123456789ABCDEF\n");
208#elif (MATRIX_COLS <= 32)
209 print("r/c 0123456789ABCDEF0123456789ABCDEF\n");
210#endif
211
212 for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
213
214#if (MATRIX_COLS <= 8)
215 xprintf("%02X: %08b%s\n", row, bitrev(matrix_get_row(row)),
216#elif (MATRIX_COLS <= 16)
217 xprintf("%02X: %016b%s\n", row, bitrev16(matrix_get_row(row)),
218#elif (MATRIX_COLS <= 32)
219 xprintf("%02X: %032b%s\n", row, bitrev32(matrix_get_row(row)),
220#endif
221#ifdef MATRIX_HAS_GHOST
222 matrix_has_ghost_in_row(row) ? " <ghost" : ""
223#else
224 ""
225#endif
226 );
227 }
228}