matrix.c (6982B)
1 /* 2 Copyright 2012 Jun Wako <wakojun@gmail.com> 3 Copyright 2013 Oleg Kostyuk <cub.uanic@gmail.com> 4 Copyright 2015 ZSA Technology Labs Inc (@zsa) 5 Copyright 2020 Christopher Courtney <drashna@live.com> (@drashna) 6 Copyright 2021 Gary Kong <kongkm88@gmail.com> (@garykong) 7 8 This program is free software: you can redistribute it and/or modify 9 it under the terms of the GNU General Public License as published by 10 the Free Software Foundation, either version 2 of the License, or 11 (at your option) any later version. 12 13 This program is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along 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) */ 52 extern matrix_row_t matrix[MATRIX_ROWS]; // debounced values 53 extern matrix_row_t raw_matrix[MATRIX_ROWS]; // raw values 54 55 static matrix_row_t read_cols(uint8_t row); 56 static void init_cols(void); 57 static void unselect_rows(void); 58 static void select_row(uint8_t row); 59 60 static uint8_t mcp23018_reset_loop; 61 62 void 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. 73 static 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 82 bool 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 */ 126 static 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 140 static 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 */ 172 static 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 187 static 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 236 void 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 }