aboutsummaryrefslogtreecommitdiff
path: root/keyboards/3w6/rev1/matrix.c
diff options
context:
space:
mode:
Diffstat (limited to 'keyboards/3w6/rev1/matrix.c')
-rw-r--r--keyboards/3w6/rev1/matrix.c258
1 files changed, 258 insertions, 0 deletions
diff --git a/keyboards/3w6/rev1/matrix.c b/keyboards/3w6/rev1/matrix.c
new file mode 100644
index 000000000..ae2f96bfa
--- /dev/null
+++ b/keyboards/3w6/rev1/matrix.c
@@ -0,0 +1,258 @@
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: write on pin 5 of port 0, read on rest
67 0b11011111,
68 // This means: we will write on pins 0 to 2 on port 1. read rest
69 0b11111000,
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 ports[2] = {0};
190 tca9555_status = i2c_readReg(I2C_ADDR, IREGP0, ports, 2, I2C_TIMEOUT);
191 if (tca9555_status) { // if there was an error
192 // do nothing
193 return 0;
194 } else {
195 uint8_t port0 = ports[0];
196 uint8_t port1 = ports[1];
197
198 // 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.
199 // 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.
200 // Since the pins are not ordered sequentially, we have to build the correct dataset from the two ports. Refer to the schematic to see where every pin is connected.
201 data |= ( port0 & 0x01 );
202 data |= ( port0 & 0x02 );
203 data |= ( port1 & 0x10 ) >> 2;
204 data |= ( port1 & 0x08 );
205 data |= ( port0 & 0x40 ) >> 2;
206 data = ~(data);
207
208 tca9555_status = I2C_STATUS_SUCCESS;
209 return data;
210 }
211 }
212 }
213}
214
215static void unselect_rows(void) {
216 // no need to unselect on tca9555, because the select step sets all
217 // the other row bits high, and it's not changing to a different
218 // direction
219
220 // unselect rows on microcontroller
221 pin_t matrix_row_pins_mcu[MATRIX_ROWS_PER_SIDE] = MATRIX_ROW_PINS_L;
222 for (int pin_index = 0; pin_index < MATRIX_ROWS_PER_SIDE; pin_index++) {
223 pin_t pin = matrix_row_pins_mcu[pin_index];
224 setPinInput(pin);
225 writePinLow(pin);
226 }
227}
228
229static void select_row(uint8_t row) {
230 uint8_t port0 = 0xff;
231 uint8_t port1 = 0xff;
232
233 if (row < MATRIX_ROWS_PER_SIDE) {
234 // select on atmega32u4
235 pin_t matrix_row_pins_mcu[MATRIX_ROWS_PER_SIDE] = MATRIX_ROW_PINS_L;
236 pin_t pin = matrix_row_pins_mcu[row];
237 setPinOutput(pin);
238 writePinLow(pin);
239 } else {
240 // select on tca9555
241 if (tca9555_status) { // if there was an error
242 // do nothing
243 } else {
244 switch(row) {
245 case 4: port1 &= ~(1 << 0); break;
246 case 5: port1 &= ~(1 << 1); break;
247 case 6: port1 &= ~(1 << 2); break;
248 case 7: port0 &= ~(1 << 5); break;
249 default: break;
250 }
251
252 uint8_t ports[2] = {port0, port1};
253 tca9555_status = i2c_writeReg(I2C_ADDR, OREGP0, ports, 2, I2C_TIMEOUT);
254 // 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.
255 // 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.
256 }
257 }
258}