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