matrix.c
6982 bytes
1/*
2Copyright 2012 Jun Wako <wakojun@gmail.com>
3Copyright 2013 Oleg Kostyuk <cub.uanic@gmail.com>
4Copyright 2015 ZSA Technology Labs Inc (@zsa)
5Copyright 2020 Christopher Courtney <drashna@live.com> (@drashna)
6Copyright 2021 Gary Kong <kongkm88@gmail.com> (@garykong)
7
8This program is free software: you can redistribute it and/or modify
9it under the terms of the GNU General Public License as published by
10the Free Software Foundation, either version 2 of the License, or
11(at your option) any later version.
12
13This program is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16GNU General Public License for more details.
17
18You should have received a copy of the GNU General Public License
19along with this program. If not, see <http://www.gnu.org/licenses/>.
20*/
21
22
23/*
24 * scan matrix
25 */
26#include <stdint.h>
27#include <stdbool.h>
28#include <avr/io.h>
29#include "wait.h"
30#include "action_layer.h"
31#include "print.h"
32#include "debug.h"
33#include "util.h"
34#include "matrix.h"
35#include "debounce.h"
36#include "bajjak.h"
37
38
39/*
40 * This constant define not debouncing time in msecs, assuming eager_pr.
41 *
42 * On BAJJAK matrix scan rate is relatively low, because of slow I2C.
43 * Now it's only 317 scans/second, or about 3.15 msec/scan.
44 * According to Cherry specs, debouncing time is 5 msec.
45 *
46 * However, some switches seem to have higher debouncing requirements, or
47 * something else might be wrong. (Also, the scan speed has improved since
48 * that comment was written.)
49 */
50
51/* matrix state(1:on, 0:off) */
52extern matrix_row_t matrix[MATRIX_ROWS]; // debounced values
53extern matrix_row_t raw_matrix[MATRIX_ROWS]; // raw values
54
55static matrix_row_t read_cols(uint8_t row);
56static void init_cols(void);
57static void unselect_rows(void);
58static void select_row(uint8_t row);
59
60static uint8_t mcp23018_reset_loop;
61
62void matrix_init_custom(void) {
63 // initialize row and col
64
65 mcp23018_status = init_mcp23018();
66
67 unselect_rows();
68 init_cols();
69}
70
71// Reads and stores a row, returning
72// whether a change occurred.
73static inline bool store_raw_matrix_row(uint8_t index) {
74 matrix_row_t temp = read_cols(index);
75 if (raw_matrix[index] != temp) {
76 raw_matrix[index] = temp;
77 return true;
78 }
79 return false;
80}
81
82bool matrix_scan_custom(matrix_row_t current_matrix[]) {
83 if (mcp23018_status) { // if there was an error
84 if (++mcp23018_reset_loop == 0) {
85 print("trying to reset mcp23018\n");
86 mcp23018_status = init_mcp23018();
87 if (mcp23018_status) {
88 print("left side not responding\n");
89 } else {
90 print("left side attached\n");
91 bajjak_blink_all_leds();
92 }
93 }
94 }
95
96#ifdef LEFT_LEDS
97 mcp23018_status = bajjak_left_leds_update();
98#endif // LEFT_LEDS
99 bool changed = false;
100 for (uint8_t i = 0; i < MATRIX_ROWS_PER_SIDE; i++) {
101 // select rows from left and right hands
102 uint8_t left_index = i;
103 uint8_t right_index = i + MATRIX_ROWS_PER_SIDE;
104 select_row(left_index);
105 select_row(right_index);
106
107 changed |= store_raw_matrix_row(left_index);
108 changed |= store_raw_matrix_row(right_index);
109
110 unselect_rows();
111 }
112
113 return changed;
114}
115
116/* Column pin configuration
117 *
118 * Teensy
119 * col: 0 1 2 3 4 5
120 * pin: F0 F1 F4 F5 F6 F7
121 *
122 * MCP23018
123 * col: 0 1 2 3 4 5
124 * pin: B5 B4 B3 B2 B1 B0
125 */
126static void init_cols(void) {
127 // init on mcp23018
128 // not needed, already done as part of init_mcp23018()
129
130 // init on teensy
131 gpio_set_pin_input_high(F0);
132 gpio_set_pin_input_high(F1);
133 gpio_set_pin_input_high(F4);
134 gpio_set_pin_input_high(F5);
135 gpio_set_pin_input_high(F6);
136 gpio_set_pin_input_high(F7);
137 gpio_set_pin_input_high(D7);
138}
139
140static matrix_row_t read_cols(uint8_t row) {
141 if (row < 7) {
142 if (mcp23018_status) { // if there was an error
143 return 0;
144 } else {
145 uint8_t data = 0;
146 // reading GPIOB (column port) since in mcp23018's sequential mode
147 // it is addressed directly after writing to GPIOA in select_row()
148 mcp23018_status = i2c_receive(I2C_ADDR, &data, 1, BAJJAK_EZ_I2C_TIMEOUT);
149 return ~data;
150 }
151 } else {
152 /* read from teensy
153 * bitmask is 0b11110011, but we want those all
154 * in the lower six bits.
155 * we'll return 1s for the top two, but that's harmless.
156 */
157
158 return ~( (PINF & 0x03) | ((PINF & 0xF0) >> 2) | ((PIND & 0x80) >> 1) );
159 }
160}
161
162/* Row pin configuration
163 *
164 * Teensy
165 * row: 7 8 9 10 11 12 13
166 * pin: B0 B1 B2 B3 D2 D3 C6
167 *
168 * MCP23018
169 * row: 0 1 2 3 4 5 6
170 * pin: A0 A1 A2 A3 A4 A5 A6
171 */
172static void unselect_rows(void) {
173 // no need to unselect on mcp23018, because the select step sets all
174 // the other row bits high, and it's not changing to a different
175 // direction
176
177 // unselect on teensy
178 gpio_set_pin_input(B0);
179 gpio_set_pin_input(B1);
180 gpio_set_pin_input(B2);
181 gpio_set_pin_input(B3);
182 gpio_set_pin_input(D2);
183 gpio_set_pin_input(D3);
184 gpio_set_pin_input(C6);
185}
186
187static void select_row(uint8_t row) {
188 if (row < 7) {
189 // select on mcp23018
190 if (!mcp23018_status) {
191 // set active row low : 0
192 // set other rows hi-Z : 1
193 uint8_t data;
194 data = 0xFF & ~(1 << row);
195 mcp23018_status = i2c_write_register(I2C_ADDR, GPIOA, &data, 1, BAJJAK_EZ_I2C_TIMEOUT);
196
197 }
198 } else {
199 // select on teensy
200 // Output low(DDR:1, PORT:0) to select
201 switch (row) {
202 case 7:
203 gpio_set_pin_output(B0);
204 gpio_write_pin_low(B0);
205 break;
206 case 8:
207 gpio_set_pin_output(B1);
208 gpio_write_pin_low(B1);
209 break;
210 case 9:
211 gpio_set_pin_output(B2);
212 gpio_write_pin_low(B2);
213 break;
214 case 10:
215 gpio_set_pin_output(B3);
216 gpio_write_pin_low(B3);
217 break;
218 case 11:
219 gpio_set_pin_output(D2);
220 gpio_write_pin_low(D2);
221 break;
222 case 12:
223 gpio_set_pin_output(D3);
224 gpio_write_pin_low(D3);
225 break;
226 case 13:
227 gpio_set_pin_output(C6);
228 gpio_write_pin_low(C6);
229 break;
230 }
231 }
232}
233
234// DO NOT REMOVE
235// Needed for proper wake/sleep
236void matrix_power_up(void) {
237 mcp23018_status = init_mcp23018();
238
239 unselect_rows();
240 init_cols();
241
242 // initialize matrix state: all keys off
243 for (uint8_t i=0; i < MATRIX_ROWS; i++) {
244 matrix[i] = 0;
245 }
246
247}