matrix.c (6490B)
1 /* 2 3 Copyright 2013 Oleg Kostyuk <cub.uanic@gmail.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 19 #include "matrix.h" 20 #include <stdint.h> 21 #include <stdbool.h> 22 #include <avr/io.h> 23 #include "wait.h" 24 #include "action_layer.h" 25 #include "print.h" 26 #include "debug.h" 27 #include "util.h" 28 #include "debounce.h" 29 #include "gergoplex.h" 30 31 #ifdef BALLER 32 # include <avr/interrupt.h> 33 # include "pointing_device.h" 34 #endif 35 36 #ifndef DEBOUNCE 37 # define DEBOUNCE 5 38 #endif 39 40 // ATmega pin defs 41 #define COL1 (1 << 6) 42 #define COL2 (1 << 5) 43 #define COL3 (1 << 4) 44 #define COL4 (1 << 1) 45 46 /* matrix state(1:on, 0:off) */ 47 static matrix_row_t matrix[MATRIX_ROWS]; 48 /* 49 * matrix state(1:on, 0:off) 50 * contains the raw values without debounce filtering of the last read cycle. 51 */ 52 static matrix_row_t raw_matrix[MATRIX_ROWS]; 53 54 static const pin_t col_pins[MATRIX_COLS] = MATRIX_COL_PINS; 55 // Right-hand side only pins, the left side is controlled my MCP 56 static const pin_t row_pins[MATRIX_ROWS_PER_SIDE] = MATRIX_ROW_PINS; 57 58 // Debouncing: store for each key the number of scans until it's eligible to 59 // change. When scanning the matrix, ignore any changes in keys that have 60 // already changed in the last DEBOUNCE scans. 61 62 static matrix_row_t read_cols(uint8_t row); 63 static void init_cols(void); 64 static void unselect_rows(void); 65 static void select_row(uint8_t row); 66 67 static uint8_t mcp23018_reset_loop; 68 69 __attribute__((weak)) void matrix_init_user(void) {} 70 __attribute__((weak)) void matrix_scan_user(void) {} 71 __attribute__((weak)) void matrix_scan_kb(void) { 72 matrix_scan_user(); 73 } 74 75 void matrix_init(void) { 76 // initialize row and col 77 mcp23018_status = init_mcp23018(); 78 unselect_rows(); 79 init_cols(); 80 81 // initialize matrix state: all keys off 82 for (uint8_t i = 0; i < MATRIX_ROWS; i++) { 83 matrix[i] = 0; 84 raw_matrix[i] = 0; 85 } 86 87 debounce_init(); 88 matrix_init_kb(); 89 } 90 void matrix_power_up(void) { 91 mcp23018_status = init_mcp23018(); 92 93 unselect_rows(); 94 init_cols(); 95 96 // initialize matrix state: all keys off 97 for (uint8_t i = 0; i < MATRIX_ROWS; i++) { 98 matrix[i] = 0; 99 } 100 } 101 102 // Reads and stores a row, returning 103 // whether a change occurred. 104 static inline bool store_raw_matrix_row(uint8_t index) { 105 matrix_row_t temp = read_cols(index); 106 if (raw_matrix[index] != temp) { 107 raw_matrix[index] = temp; 108 return true; 109 } 110 return false; 111 } 112 uint8_t matrix_scan(void) { 113 if (mcp23018_status) { // if there was an error 114 if (++mcp23018_reset_loop == 0) { 115 // if (++mcp23018_reset_loop >= 1300) { 116 // since mcp23018_reset_loop is 8 bit - we'll try to reset once in 255 matrix scans 117 // this will be approx bit more frequent than once per second 118 print("trying to reset mcp23018\n"); 119 mcp23018_status = init_mcp23018(); 120 if (mcp23018_status) { 121 print("left side not responding\n"); 122 } else { 123 print("left side attached\n"); 124 } 125 } 126 } 127 128 bool changed = false; 129 for (uint8_t i = 0; i < MATRIX_ROWS_PER_SIDE; i++) { 130 // select rows from left and right hands 131 uint8_t left_index = i; 132 uint8_t right_index = i + MATRIX_ROWS_PER_SIDE; 133 select_row(left_index); 134 select_row(right_index); 135 136 // we don't need a 30us delay anymore, because selecting a 137 // left-hand row requires more than 30us for i2c. 138 139 changed |= store_raw_matrix_row(left_index); 140 changed |= store_raw_matrix_row(right_index); 141 142 unselect_rows(); 143 } 144 145 debounce(raw_matrix, matrix, changed); 146 matrix_scan_kb(); 147 148 #ifdef DEBUG_MATRIX 149 for (uint8_t c = 0; c < MATRIX_COLS; c++) 150 for (uint8_t r = 0; r < MATRIX_ROWS; r++) 151 if (matrix_is_on(r, c)) xprintf("r:%d c:%d \n", r, c); 152 #endif 153 154 return 1; 155 } 156 157 inline bool matrix_is_on(uint8_t row, uint8_t col) { 158 return (matrix[row] & ((matrix_row_t)1 << col)); 159 } 160 inline matrix_row_t matrix_get_row(uint8_t row) { 161 return matrix[row]; 162 } 163 164 void matrix_print(void) { 165 print("\nr/c 0123456789ABCDEF\n"); 166 for (uint8_t row = 0; row < MATRIX_ROWS; row++) { 167 print_hex8(row); 168 print(": "); 169 print_bin_reverse16(matrix_get_row(row)); 170 print("\n"); 171 } 172 } 173 174 // Remember this means ROWS 175 static void init_cols(void) { 176 for (uint8_t col = 0; col < MATRIX_COLS; col++) { 177 gpio_set_pin_input_high(col_pins[col]); 178 } 179 } 180 181 static matrix_row_t read_cols(uint8_t row) { 182 if (row < 5) { 183 if (mcp23018_status) { // if there was an error 184 return 0; 185 } else { 186 uint8_t data = 0; 187 mcp23018_status = i2c_receive(I2C_ADDR, &data, 1, I2C_TIMEOUT); 188 #ifdef DEBUG_MATRIX 189 if (~data != 0x00) xprintf("I2C: %d\n", ~data); 190 #endif 191 return ~data; 192 } 193 } else { 194 return ~((((PINF & COL4) >> 1) | ((PINF & (COL1 | COL2 | COL3)) >> 3)) & 0xF); 195 } 196 } 197 198 // Row pin configuration 199 static void unselect_rows(void) { 200 // no need to unselect on mcp23018, because the select step sets all 201 // the other row bits high, and it's not changing to a different direction 202 203 for (uint8_t row = 0; row < MATRIX_ROWS_PER_SIDE; row++) { 204 gpio_set_pin_input(row_pins[row]); 205 gpio_write_pin_low(row_pins[row]); 206 } 207 } 208 209 static void select_row(uint8_t row) { 210 if (row < 5) { 211 // select on mcp23018 212 if (mcp23018_status) { // do nothing on error 213 } else { // set active row low : 0 // set other rows hi-Z : 1 214 uint8_t data; 215 data = 0xFF & ~(1 << (row + 1)); 216 mcp23018_status = i2c_write_register(I2C_ADDR, GPIOA, &data, 1, I2C_TIMEOUT); 217 } 218 } else { 219 gpio_set_pin_output(row_pins[row - MATRIX_ROWS_PER_SIDE]); 220 gpio_write_pin_low(row_pins[row - MATRIX_ROWS_PER_SIDE]); 221 } 222 }