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