aboutsummaryrefslogtreecommitdiff
path: root/keyboards/3w6/rev2/matrix.c
diff options
context:
space:
mode:
Diffstat (limited to 'keyboards/3w6/rev2/matrix.c')
-rw-r--r--keyboards/3w6/rev2/matrix.c256
1 files changed, 256 insertions, 0 deletions
diff --git a/keyboards/3w6/rev2/matrix.c b/keyboards/3w6/rev2/matrix.c
new file mode 100644
index 000000000..c47c24e1d
--- /dev/null
+++ b/keyboards/3w6/rev2/matrix.c
@@ -0,0 +1,256 @@
1/*
2Copyright 2013 Oleg Kostyuk <[email protected]>
3 2020 Pierre Chevalier <[email protected]>
4 2021 weteor
5
6This program is free software: you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation, either version 2 of the License, or
9(at your option) any later version.
10
11This program is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with this program. If not, see <http://www.gnu.org/licenses/>.
18*/
19
20/*
21 * This code was heavily inspired by the ergodox_ez keymap, and modernized
22 * to take advantage of the quantum.h microcontroller agnostics gpio control
23 * abstractions and use the macros defined in config.h for the wiring as opposed
24 * to repeating that information all over the place.
25 */
26
27#include QMK_KEYBOARD_H
28#include "i2c_master.h"
29
30extern i2c_status_t tca9555_status;
31#define I2C_TIMEOUT 1000
32
33// I2C address:
34// All address pins of the tca9555 are connected to the ground
35// | 0 | 1 | 0 | 0 | A2 | A1 | A0 |
36// | 0 | 1 | 0 | 0 | 0 | 0 | 0 |
37#define I2C_ADDR (0b0100000 << 1)
38
39// Register addresses
40#define IODIRA 0x06 // i/o direction register
41#define IODIRB 0x07
42#define IREGP0 0x00 // GPIO pull-up resistor register
43#define IREGP1 0x01
44#define OREGP0 0x02 // general purpose i/o port register (write modifies OLAT)
45#define OREGP1 0x03
46
47bool i2c_initialized = 0;
48i2c_status_t tca9555_status = I2C_ADDR;
49
50uint8_t init_tca9555(void) {
51 print("starting init");
52 tca9555_status = I2C_ADDR;
53
54 // I2C subsystem
55 if (i2c_initialized == 0) {
56 i2c_init(); // on pins D(1,0)
57 i2c_initialized = true;
58 wait_ms(I2C_TIMEOUT);
59 }
60
61 // set pin direction
62 // - unused : input : 1
63 // - input : input : 1
64 // - driving : output : 0
65 uint8_t conf[2] = {
66 // This means: read all pins of port 0
67 0b11111111,
68 // This means: we will write on pins 0 to 3 on port 1. read rest
69 0b11110000,
70 };
71 tca9555_status = i2c_writeReg(I2C_ADDR, IODIRA, conf, 2, I2C_TIMEOUT);
72
73 return tca9555_status;
74}
75
76/* matrix state(1:on, 0:off) */
77static matrix_row_t matrix[MATRIX_ROWS]; // debounced values
78
79static matrix_row_t read_cols(uint8_t row);
80static void init_cols(void);
81static void unselect_rows(void);
82static void select_row(uint8_t row);
83
84static uint8_t tca9555_reset_loop;
85
86void matrix_init_custom(void) {
87 // initialize row and col
88
89 tca9555_status = init_tca9555();
90
91 unselect_rows();
92 init_cols();
93
94 // initialize matrix state: all keys off
95 for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
96 matrix[i] = 0;
97 }
98}
99
100void matrix_power_up(void) {
101 tca9555_status = init_tca9555();
102
103 unselect_rows();
104 init_cols();
105
106 // initialize matrix state: all keys off
107 for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
108 matrix[i] = 0;
109 }
110}
111
112// Reads and stores a row, returning
113// whether a change occurred.
114static inline bool store_matrix_row(matrix_row_t current_matrix[], uint8_t index) {
115 matrix_row_t temp = read_cols(index);
116 if (current_matrix[index] != temp) {
117 current_matrix[index] = temp;
118 return true;
119 }
120 return false;
121}
122
123bool matrix_scan_custom(matrix_row_t current_matrix[]) {
124 if (tca9555_status) { // if there was an error
125 if (++tca9555_reset_loop == 0) {
126 // since tca9555_reset_loop is 8 bit - we'll try to reset once in 255 matrix scans
127 // this will be approx bit more frequent than once per second
128 dprint("trying to reset tca9555\n");
129 tca9555_status = init_tca9555();
130 if (tca9555_status) {
131 dprint("right side not responding\n");
132 } else {
133 dprint("right side attached\n");
134 }
135 }
136 }
137
138 bool changed = false;
139 for (uint8_t i = 0; i < MATRIX_ROWS_PER_SIDE; i++) {
140 // select rows from left and right hands
141 uint8_t left_index = i;
142 uint8_t right_index = i + MATRIX_ROWS_PER_SIDE;
143 select_row(left_index);
144 select_row(right_index);
145
146 // we don't need a 30us delay anymore, because selecting a
147 // left-hand row requires more than 30us for i2c.
148
149 changed |= store_matrix_row(current_matrix, left_index);
150 changed |= store_matrix_row(current_matrix, right_index);
151
152 unselect_rows();
153 }
154
155 return changed;
156}
157
158static void init_cols(void) {
159 // init on tca9555
160 // not needed, already done as part of init_tca9555()
161
162 // init on mcu
163 pin_t matrix_col_pins_mcu[MATRIX_COLS_PER_SIDE] = MATRIX_COL_PINS_L;
164 for (int pin_index = 0; pin_index < MATRIX_COLS_PER_SIDE; pin_index++) {
165 pin_t pin = matrix_col_pins_mcu[pin_index];
166 setPinInput(pin);
167 writePinHigh(pin);
168 }
169}
170
171static matrix_row_t read_cols(uint8_t row) {
172 if (row < MATRIX_ROWS_PER_SIDE) {
173 pin_t matrix_col_pins_mcu[MATRIX_COLS_PER_SIDE] = MATRIX_COL_PINS_L;
174 matrix_row_t current_row_value = 0;
175 // For each col...
176 for (uint8_t col_index = 0; col_index < MATRIX_COLS_PER_SIDE; col_index++) {
177 // Select the col pin to read (active low)
178 uint8_t pin_state = readPin(matrix_col_pins_mcu[col_index]);
179
180 // Populate the matrix row with the state of the col pin
181 current_row_value |= pin_state ? 0 : (MATRIX_ROW_SHIFTER << col_index);
182 }
183 return current_row_value;
184 } else {
185 if (tca9555_status) { // if there was an error
186 return 0;
187 } else {
188 uint8_t data = 0;
189 uint8_t port0 = 0;
190 tca9555_status = i2c_readReg(I2C_ADDR, IREGP0, &port0, 1, I2C_TIMEOUT);
191 if (tca9555_status) { // if there was an error
192 // do nothing
193 return 0;
194 } else {
195 port0 = ~port0;
196 // We read all the pins on GPIOA.
197 // The initial state was all ones and any depressed key at a given column for the currently selected row will have its bit flipped to zero.
198 // The return value is a row as represented in the generic matrix code were the rightmost bits represent the lower columns and zeroes represent non-depressed keys while ones represent depressed keys.
199 // the pins connected to eact columns are sequential, but in reverse order, and counting from zero down (col 5 -> GPIO04, col6 -> GPIO03 and so on).
200 data |= (port0 & 0x01) << 4;
201 data |= (port0 & 0x02) << 2;
202 data |= (port0 & 0x04);
203 data |= (port0 & 0x08) >> 2;
204 data |= (port0 & 0x10) >> 4;
205
206 tca9555_status = I2C_STATUS_SUCCESS;
207 return data;
208 }
209 }
210 }
211}
212
213static void unselect_rows(void) {
214 // no need to unselect on tca9555, because the select step sets all
215 // the other row bits high, and it's not changing to a different
216 // direction
217
218 // unselect rows on microcontroller
219 pin_t matrix_row_pins_mcu[MATRIX_ROWS_PER_SIDE] = MATRIX_ROW_PINS_L;
220 for (int pin_index = 0; pin_index < MATRIX_ROWS_PER_SIDE; pin_index++) {
221 pin_t pin = matrix_row_pins_mcu[pin_index];
222 setPinInput(pin);
223 writePinLow(pin);
224 }
225}
226
227static void select_row(uint8_t row) {
228 uint8_t port1 = 0xff;
229
230 if (row < MATRIX_ROWS_PER_SIDE) {
231 // select on atmega32u4
232 pin_t matrix_row_pins_mcu[MATRIX_ROWS_PER_SIDE] = MATRIX_ROW_PINS_L;
233 pin_t pin = matrix_row_pins_mcu[row];
234 setPinOutput(pin);
235 writePinLow(pin);
236 } else {
237 // select on tca9555
238 if (tca9555_status) { // if there was an error
239 // do nothing
240 } else {
241 switch(row) {
242 case 4: port1 &= ~(1 << 0); break;
243 case 5: port1 &= ~(1 << 1); break;
244 case 6: port1 &= ~(1 << 2); break;
245 case 7:
246 port1 &= ~(1 << 3);
247 break;
248 default: break;
249 }
250
251 tca9555_status = i2c_writeReg(I2C_ADDR, OREGP1, &port1, 1, I2C_TIMEOUT);
252 // Select the desired row by writing a byte for the entire GPIOB bus where only the bit representing the row we want to select is a zero (write instruction) and every other bit is a one.
253 // Note that the row - MATRIX_ROWS_PER_SIDE reflects the fact that being on the right hand, the columns are numbered from MATRIX_ROWS_PER_SIDE to MATRIX_ROWS, but the pins we want to write to are indexed from zero up on the GPIOB bus.
254 }
255 }
256}