matrix.c (13877B)
1 /* 2 Copyright 2013 Oleg Kostyuk <cub.uanic@gmail.com> 3 Copyright 2017 Erin Call <hello@erincall.com> 4 5 This program is free software: you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation, either version 2 of the License, or 8 (at your option) any later version. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program. If not, see <http://www.gnu.org/licenses/>. 17 */ 18 #include <stdint.h> 19 #include <stdbool.h> 20 #include <avr/io.h> 21 #include "wait.h" 22 #include "action_layer.h" 23 #include "print.h" 24 #include "debug.h" 25 #include "util.h" 26 #include "matrix.h" 27 #include "dactyl.h" 28 #include "i2c_master.h" 29 #include "timer.h" 30 31 32 /* Set 0 if debouncing isn't needed */ 33 34 #ifndef DEBOUNCE 35 # define DEBOUNCE 5 36 #endif 37 38 #if (DEBOUNCE > 0) 39 static uint16_t debouncing_time; 40 static bool debouncing = false; 41 #endif 42 43 #ifdef MATRIX_MASKED 44 extern const matrix_row_t matrix_mask[]; 45 #endif 46 47 #if (DIODE_DIRECTION == ROW2COL) || (DIODE_DIRECTION == COL2ROW) 48 static const uint8_t onboard_row_pins[MATRIX_ROWS] = MATRIX_ONBOARD_ROW_PINS; 49 static const uint8_t onboard_col_pins[MATRIX_COLS] = MATRIX_ONBOARD_COL_PINS; 50 static const bool col_expanded[MATRIX_COLS] = COL_EXPANDED; 51 #endif 52 53 /* matrix state(1:on, 0:off) */ 54 static matrix_row_t matrix[MATRIX_ROWS]; 55 56 static matrix_row_t matrix_debouncing[MATRIX_ROWS]; 57 58 #if (DIODE_DIRECTION == COL2ROW) 59 static const uint8_t expander_col_pins[MATRIX_COLS] = MATRIX_EXPANDER_COL_PINS; 60 static void init_cols(void); 61 static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row); 62 static void unselect_rows(void); 63 static void select_row(uint8_t row); 64 static void unselect_row(uint8_t row); 65 #elif (DIODE_DIRECTION == ROW2COL) 66 static const uint8_t expander_row_pins[MATRIX_ROWS] = MATRIX_EXPANDER_ROW_PINS; 67 static void init_rows(void); 68 static bool read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col); 69 static void unselect_cols(void); 70 static void select_col(uint8_t col); 71 static void unselect_col(uint8_t col); 72 #endif 73 74 static uint8_t expander_reset_loop; 75 uint8_t expander_status; 76 uint8_t expander_input_pin_mask; 77 bool i2c_initialized = false; 78 79 #define ROW_SHIFTER ((matrix_row_t)1) 80 81 __attribute__ ((weak)) 82 void matrix_init_user(void) {} 83 84 __attribute__ ((weak)) 85 void matrix_scan_user(void) {} 86 87 __attribute__ ((weak)) 88 void matrix_init_kb(void) { 89 matrix_init_user(); 90 } 91 92 __attribute__ ((weak)) 93 void matrix_scan_kb(void) { 94 matrix_scan_user(); 95 } 96 97 inline 98 uint8_t matrix_rows(void) 99 { 100 return MATRIX_ROWS; 101 } 102 103 inline 104 uint8_t matrix_cols(void) 105 { 106 return MATRIX_COLS; 107 } 108 109 void matrix_init(void) 110 { 111 init_expander(); 112 113 #if (DIODE_DIRECTION == COL2ROW) 114 unselect_rows(); 115 init_cols(); 116 #elif (DIODE_DIRECTION == ROW2COL) 117 unselect_cols(); 118 init_rows(); 119 #endif 120 121 // initialize matrix state: all keys off 122 for (uint8_t i=0; i < MATRIX_ROWS; i++) { 123 matrix[i] = 0; 124 matrix_debouncing[i] = 0; 125 } 126 127 matrix_init_kb(); 128 } 129 130 void init_expander(void) { 131 if (! i2c_initialized) { 132 i2c_init(); 133 wait_ms(1000); 134 } 135 136 if (! expander_input_pin_mask) { 137 #if (DIODE_DIRECTION == COL2ROW) 138 for (int col = 0; col < MATRIX_COLS; col++) { 139 if (col_expanded[col]) { 140 expander_input_pin_mask |= (1 << expander_col_pins[col]); 141 } 142 } 143 #elif (DIODE_DIRECTION == ROW2COL) 144 for (int row = 0; row < MATRIX_ROWS; row++) { 145 expander_input_pin_mask |= (1 << expander_row_pins[row]); 146 } 147 #endif 148 } 149 150 /* 151 Pin direction and pull-up depends on both the diode direction 152 and on whether the column register is GPIOA or GPIOB 153 +-------+---------------+---------------+ 154 | | ROW2COL | COL2ROW | 155 +-------+---------------+---------------+ 156 | GPIOA | input, output | output, input | 157 +-------+---------------+---------------+ 158 | GPIOB | output, input | input, output | 159 +-------+---------------+---------------+ 160 */ 161 162 #if (EXPANDER_COL_REGISTER == GPIOA) 163 # if (DIODE_DIRECTION == COL2ROW) 164 uint8_t direction[2] = { 165 expander_input_pin_mask, 166 0, 167 }; 168 # elif (DIODE_DIRECTION == ROW2COL) 169 uint8_t direction[2] = { 170 0, 171 expander_input_pin_mask, 172 }; 173 # endif 174 #elif (EXPANDER_COL_REGISTER == GPIOB) 175 # if (DIODE_DIRECTION == COL2ROW) 176 uint8_t direction[2] = { 177 0, 178 expander_input_pin_mask, 179 }; 180 # elif (DIODE_DIRECTION == ROW2COL) 181 uint8_t direction[2] = { 182 expander_input_pin_mask, 183 0, 184 }; 185 # endif 186 #endif 187 188 // set pull-up 189 // - unused : off : 0 190 // - input : on : 1 191 // - driving : off : 0 192 #if (EXPANDER_COL_REGISTER == GPIOA) 193 # if (DIODE_DIRECTION == COL2ROW) 194 uint8_t pullup[2] = { 195 expander_input_pin_mask, 196 0, 197 }; 198 # elif (DIODE_DIRECTION == ROW2COL) 199 uint8_t pullup[2] = { 200 0, 201 expander_input_pin_mask, 202 }; 203 # endif 204 #elif (EXPANDER_COL_REGISTER == GPIOB) 205 # if (DIODE_DIRECTION == COL2ROW) 206 uint8_t pullup[2] = { 207 0, 208 expander_input_pin_mask, 209 }; 210 # elif (DIODE_DIRECTION == ROW2COL) 211 uint8_t pullup[2] = { 212 expander_input_pin_mask, 213 0, 214 }; 215 # endif 216 #endif 217 218 219 expander_status = i2c_write_register(I2C_ADDR, IODIRA, direction, 2, I2C_TIMEOUT); 220 if (expander_status) return; 221 222 expander_status = i2c_write_register(I2C_ADDR, GPPUA, pullup, 2, I2C_TIMEOUT); 223 } 224 225 uint8_t matrix_scan(void) 226 { 227 if (expander_status) { // if there was an error 228 if (++expander_reset_loop == 0) { 229 // since expander_reset_loop is 8 bit - we'll try to reset once in 255 matrix scans 230 // this will be approx bit more frequent than once per second 231 print("trying to reset expander\n"); 232 init_expander(); 233 if (expander_status) { 234 print("left side not responding\n"); 235 } else { 236 print("left side attached\n"); 237 } 238 } 239 } 240 241 #if (DIODE_DIRECTION == COL2ROW) 242 for (uint8_t current_row = 0; current_row < MATRIX_ROWS; current_row++) { 243 # if (DEBOUNCE > 0) 244 bool matrix_changed = read_cols_on_row(matrix_debouncing, current_row); 245 246 if (matrix_changed) { 247 debouncing = true; 248 debouncing_time = timer_read(); 249 } 250 # else 251 read_cols_on_row(matrix, current_row); 252 # endif 253 } 254 255 #elif (DIODE_DIRECTION == ROW2COL) 256 for (uint8_t current_col = 0; current_col < MATRIX_COLS; current_col++) { 257 # if (DEBOUNCE > 0) 258 bool matrix_changed = read_rows_on_col(matrix_debouncing, current_col); 259 260 if (matrix_changed) { 261 debouncing = true; 262 debouncing_time = timer_read(); 263 } 264 # else 265 read_rows_on_col(matrix, current_col); 266 # endif 267 268 } 269 #endif 270 271 # if (DEBOUNCE > 0) 272 if (debouncing && (timer_elapsed(debouncing_time) > DEBOUNCE)) { 273 for (uint8_t i = 0; i < MATRIX_ROWS; i++) { 274 matrix[i] = matrix_debouncing[i]; 275 } 276 debouncing = false; 277 } 278 # endif 279 280 matrix_scan_kb(); 281 return 1; 282 } 283 284 inline 285 bool matrix_is_on(uint8_t row, uint8_t col) 286 { 287 return (matrix[row] & (ROW_SHIFTER << col)); 288 } 289 290 inline 291 matrix_row_t matrix_get_row(uint8_t row) 292 { 293 #ifdef MATRIX_MASKED 294 return matrix[row] & matrix_mask[row]; 295 #else 296 return matrix[row]; 297 #endif 298 } 299 300 void matrix_print(void) 301 { 302 print("\nr/c 0123456789ABCDEF\n"); 303 for (uint8_t row = 0; row < MATRIX_ROWS; row++) { 304 print_hex8(row); print(": "); 305 print_bin_reverse16(matrix_get_row(row)); 306 print("\n"); 307 } 308 } 309 310 #if (DIODE_DIRECTION == COL2ROW) 311 312 static void init_cols(void) { 313 for (uint8_t x = 0; x < MATRIX_COLS; x++) { 314 if (! col_expanded[x]) { 315 uint8_t pin = onboard_col_pins[x]; 316 _SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF); // IN 317 _SFR_IO8((pin >> 4) + 2) |= _BV(pin & 0xF); // HI 318 } 319 } 320 } 321 322 static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row) { 323 // Store last value of row prior to reading 324 matrix_row_t last_row_value = current_matrix[current_row]; 325 326 // Clear data in matrix row 327 current_matrix[current_row] = 0; 328 329 // Select row and wait for row selection to stabilize 330 select_row(current_row); 331 wait_us(30); 332 333 // Read columns from expander, unless it's in an error state 334 if (! expander_status) { 335 uint8_t state = 0; 336 expander_status = i2c_read_register(I2C_ADDR, EXPANDER_COL_REGISTER, &state, 1, I2C_TIMEOUT); 337 if (! expander_status) { 338 current_matrix[current_row] |= (~state) & expander_input_pin_mask; 339 } 340 } 341 342 // Read columns from onboard pins 343 for (uint8_t col_index = 0; col_index < MATRIX_COLS; col_index++) { 344 if (! col_expanded[col_index]) { 345 uint8_t pin = onboard_col_pins[col_index]; 346 uint8_t pin_state = (_SFR_IO8(pin >> 4) & _BV(pin & 0xF)); 347 current_matrix[current_row] |= pin_state ? 0 : (ROW_SHIFTER << col_index); 348 } 349 } 350 351 unselect_row(current_row); 352 353 return (last_row_value != current_matrix[current_row]); 354 } 355 356 static void select_row(uint8_t row) { 357 // select on expander, unless it's in an error state 358 if (! expander_status) { 359 // set active row low : 0 360 // set other rows hi-Z : 1 361 uint8_t port = 0xFF & ~(1<<row); 362 expander_status = i2c_write_register(I2C_ADDR, EXPANDER_ROW_REGISTER, &port, 1, I2C_TIMEOUT); 363 } 364 365 // select on teensy 366 uint8_t pin = onboard_row_pins[row]; 367 _SFR_IO8((pin >> 4) + 1) |= _BV(pin & 0xF); // OUT 368 _SFR_IO8((pin >> 4) + 2) &= ~_BV(pin & 0xF); // LOW 369 } 370 371 static void unselect_row(uint8_t row) 372 { 373 // No need to explicitly unselect expander pins--their I/O state is 374 // set simultaneously, with a single bitmask sent to i2c_write. When 375 // select_row selects a single pin, it implicitly unselects all the 376 // other ones. 377 378 // unselect on teensy 379 uint8_t pin = onboard_row_pins[row]; 380 _SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF); // OUT 381 _SFR_IO8((pin >> 4) + 2) |= _BV(pin & 0xF); // LOW 382 } 383 384 static void unselect_rows(void) { 385 for (uint8_t x = 0; x < MATRIX_ROWS; x++) { 386 unselect_row(x); 387 } 388 } 389 390 #elif (DIODE_DIRECTION == ROW2COL) 391 392 static void init_rows(void) 393 { 394 for (uint8_t x = 0; x < MATRIX_ROWS; x++) { 395 uint8_t pin = onboard_row_pins[x]; 396 _SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF); // IN 397 _SFR_IO8((pin >> 4) + 2) |= _BV(pin & 0xF); // HI 398 } 399 } 400 401 static bool read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col) 402 { 403 bool matrix_changed = false; 404 405 uint8_t column_state = 0; 406 407 //select col and wait for selection to stabilize 408 select_col(current_col); 409 wait_us(30); 410 411 if (current_col < 6) { 412 // read rows from expander 413 if (expander_status) { 414 // it's already in an error state; nothing we can do 415 return false; 416 } 417 418 expander_status = i2c_read_register(I2C_ADDR, EXPANDER_ROW_REGISTER, &column_state, 1, I2C_TIMEOUT); 419 420 column_state = ~column_state; 421 } else { 422 for (uint8_t current_row = 0; current_row < MATRIX_ROWS; current_row++) { 423 if ((_SFR_IO8(onboard_row_pins[current_row] >> 4) & _BV(onboard_row_pins[current_row] & 0xF)) == 0) { 424 column_state |= (1 << current_row); 425 } 426 } 427 } 428 429 for (uint8_t current_row = 0; current_row < MATRIX_ROWS; current_row++) { 430 // Store last value of row prior to reading 431 matrix_row_t last_row_value = current_matrix[current_row]; 432 433 if (column_state & (1 << current_row)) { 434 // key closed; set state bit in matrix 435 current_matrix[current_row] |= (ROW_SHIFTER << current_col); 436 } else { 437 // key open; clear state bit in matrix 438 current_matrix[current_row] &= ~(ROW_SHIFTER << current_col); 439 } 440 441 // Determine whether the matrix changed state 442 if ((last_row_value != current_matrix[current_row]) && !(matrix_changed)) 443 { 444 matrix_changed = true; 445 } 446 } 447 448 unselect_col(current_col); 449 450 return matrix_changed; 451 } 452 453 static void select_col(uint8_t col) 454 { 455 if (col_expanded[col]) { 456 // select on expander 457 if (expander_status) { // if there was an error 458 // do nothing 459 } else { 460 // set active col low : 0 461 // set other cols hi-Z : 1 462 uint8_t port = 0xFF & ~(1<<col); 463 expander_status = i2c_write_register(I2C_ADDR, EXPANDER_COL_REGISTER, &port, 1, I2C_TIMEOUT); 464 } 465 } else { 466 // select on teensy 467 uint8_t pin = onboard_col_pins[col]; 468 _SFR_IO8((pin >> 4) + 1) |= _BV(pin & 0xF); // OUT 469 _SFR_IO8((pin >> 4) + 2) &= ~_BV(pin & 0xF); // LOW 470 } 471 } 472 473 static void unselect_col(uint8_t col) 474 { 475 if (col_expanded[col]) { 476 // No need to explicitly unselect expander pins--their I/O state is 477 // set simultaneously, with a single bitmask sent to i2c_write. When 478 // select_col selects a single pin, it implicitly unselects all the 479 // other ones. 480 } else { 481 // unselect on teensy 482 uint8_t pin = onboard_col_pins[col]; 483 _SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF); // IN 484 _SFR_IO8((pin >> 4) + 2) |= _BV(pin & 0xF); // HI 485 } 486 } 487 488 static void unselect_cols(void) 489 { 490 for(uint8_t x = 0; x < MATRIX_COLS; x++) { 491 unselect_col(x); 492 } 493 } 494 #endif