matrix.c (7179B)
1 /* 2 Copyright 2012-2017 Jun Wako, Jack Humbert 3 4 This program is free software: you can redistribute it and/or modify 5 it under the terms of the GNU General Public License as published by 6 the Free Software Foundation, either version 2 of the License, or 7 (at your option) any later version. 8 9 This program is distributed in the hope that it will be useful, 10 but WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 GNU General Public License for more details. 13 14 You should have received a copy of the GNU General Public License 15 along with this program. If not, see <http://www.gnu.org/licenses/>. 16 */ 17 #include <stdint.h> 18 #include <stdbool.h> 19 #if defined(__AVR__) 20 #include <avr/io.h> 21 #endif 22 #include "wait.h" 23 #include "print.h" 24 #include "debug.h" 25 #include "util.h" 26 #include "matrix.h" 27 #include "timer.h" 28 #include "sx60.h" 29 30 31 /* Set 0 if debouncing isn't needed */ 32 33 #ifndef DEBOUNCE 34 # define DEBOUNCE 5 35 #endif 36 37 #if (DEBOUNCE > 0) 38 static uint16_t debouncing_time; 39 static bool debouncing = false; 40 #endif 41 42 #if (MATRIX_COLS <= 8) 43 # define print_matrix_header() print("\nr/c 01234567\n") 44 # define print_matrix_row(row) print_bin_reverse8(matrix_get_row(row)) 45 # define ROW_SHIFTER ((uint8_t)1) 46 #elif (MATRIX_COLS <= 16) 47 # define print_matrix_header() print("\nr/c 0123456789ABCDEF\n") 48 # define print_matrix_row(row) print_bin_reverse16(matrix_get_row(row)) 49 # define ROW_SHIFTER ((uint16_t)1) 50 #elif (MATRIX_COLS <= 32) 51 # define print_matrix_header() print("\nr/c 0123456789ABCDEF0123456789ABCDEF\n") 52 # define print_matrix_row(row) print_bin_reverse32(matrix_get_row(row)) 53 # define ROW_SHIFTER ((uint32_t)1) 54 #endif 55 56 #ifdef MATRIX_MASKED 57 extern const matrix_row_t matrix_mask[]; 58 #endif 59 60 static const uint8_t col_pins[ATMEGA_COLS] = MATRIX_COL_PINS; 61 static const uint8_t row_pins[MATRIX_ROWS] = MATRIX_ROW_PINS; 62 63 /* matrix state(1:on, 0:off) */ 64 static matrix_row_t matrix[MATRIX_ROWS]; 65 static matrix_row_t matrix_debouncing[MATRIX_ROWS]; 66 static uint8_t mcp23018_reset_loop; 67 68 69 static void init_cols(void); 70 static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row); 71 static void unselect_rows(void); 72 static void select_row(uint8_t row); 73 74 __attribute__ ((weak)) 75 void matrix_init_kb(void) { 76 matrix_init_user(); 77 } 78 79 __attribute__ ((weak)) 80 void matrix_scan_kb(void) { 81 matrix_scan_user(); 82 } 83 84 __attribute__ ((weak)) 85 void matrix_init_user(void) { 86 } 87 88 __attribute__ ((weak)) 89 void matrix_scan_user(void) { 90 } 91 92 inline 93 uint8_t matrix_rows(void) { 94 return MATRIX_ROWS; 95 } 96 97 inline 98 uint8_t matrix_cols(void) { 99 return MATRIX_COLS; 100 } 101 102 void matrix_init(void) { 103 mcp23018_status = true; 104 105 /* initialize row and col */ 106 unselect_rows(); 107 init_cols(); 108 109 /* initialize matrix state: all keys off */ 110 for (uint8_t i=0; i < MATRIX_ROWS; i++) { 111 matrix[i] = 0; 112 matrix_debouncing[i] = 0; 113 } 114 115 matrix_init_kb(); 116 } 117 118 uint8_t matrix_scan(void) 119 { 120 if (mcp23018_status) { 121 /* if there was an error */ 122 if (++mcp23018_reset_loop == 0) { 123 /* since mcp23018_reset_loop is 8 bit - we'll try to reset once in 255 matrix scans 124 this will be approx bit more frequent than once per second */ 125 print("trying to reset mcp23018\n"); 126 mcp23018_status = init_mcp23018(); 127 if (mcp23018_status) { 128 print("left side not responding\n"); 129 } else { 130 print("left side attached\n"); 131 } 132 } 133 } 134 135 /* Set row, read cols */ 136 for (uint8_t current_row = 0; current_row < MATRIX_ROWS; current_row++) { 137 # if (DEBOUNCE > 0) 138 bool matrix_changed = read_cols_on_row(matrix_debouncing, current_row); 139 140 if (matrix_changed) { 141 debouncing = true; 142 debouncing_time = timer_read(); 143 } 144 # else 145 read_cols_on_row(matrix, current_row); 146 # endif 147 } 148 149 # if (DEBOUNCE > 0) 150 if (debouncing && (timer_elapsed(debouncing_time) > DEBOUNCE)) { 151 for (uint8_t i = 0; i < MATRIX_ROWS; i++) { 152 matrix[i] = matrix_debouncing[i]; 153 } 154 debouncing = false; 155 } 156 # endif 157 158 matrix_scan_kb(); 159 return 1; 160 } 161 162 inline 163 bool matrix_is_on(uint8_t row, uint8_t col) 164 { 165 return (matrix[row] & ((matrix_row_t)1<<col)); 166 } 167 168 inline 169 matrix_row_t matrix_get_row(uint8_t row) 170 { 171 /* Matrix mask lets you disable switches in the returned matrix data. For example, if you have a 172 switch blocker installed and the switch is always pressed. */ 173 #ifdef MATRIX_MASKED 174 return matrix[row] & matrix_mask[row]; 175 #else 176 return matrix[row]; 177 #endif 178 } 179 180 void matrix_print(void) 181 { 182 print_matrix_header(); 183 184 for (uint8_t row = 0; row < MATRIX_ROWS; row++) { 185 print_hex8(row); print(": "); 186 print_matrix_row(row); 187 print("\n"); 188 } 189 } 190 191 static void init_cols(void) 192 { 193 for(uint8_t x = 0; x < ATMEGA_COLS; x++) { 194 uint8_t pin = col_pins[x]; 195 _SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF); /* IN */ 196 _SFR_IO8((pin >> 4) + 2) |= _BV(pin & 0xF); /* HI */ 197 } 198 } 199 200 static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row) 201 { 202 /* Store last value of row prior to reading */ 203 matrix_row_t last_row_value = current_matrix[current_row]; 204 205 /* Clear data in matrix row */ 206 current_matrix[current_row] = 0; 207 208 /* Select row and wait for row selecton to stabilize */ 209 select_row(current_row); 210 wait_us(30); 211 212 if (mcp23018_status) { 213 /* if there was an error */ 214 return 0; 215 } else { 216 uint8_t data = 0; 217 mcp23018_status = i2c_read_register(I2C_ADDR, GPIOA, &data, 1, I2C_TIMEOUT); 218 if (!mcp23018_status) { 219 current_matrix[current_row] |= (~((uint16_t)data) << 8); 220 } 221 } 222 223 /* For each col... */ 224 for(uint8_t col_index = 0; col_index < ATMEGA_COLS; col_index++) { 225 /* Select the col pin to read (active low) */ 226 uint8_t pin = col_pins[col_index]; 227 uint8_t pin_state = (_SFR_IO8(pin >> 4) & _BV(pin & 0xF)); 228 229 /* Populate the matrix row with the state of the col pin */ 230 current_matrix[current_row] |= pin_state ? 0 : (ROW_SHIFTER << col_index); 231 } 232 233 /* Unselect row */ 234 unselect_rows(); 235 236 return (last_row_value != current_matrix[current_row]); 237 } 238 239 static void select_row(uint8_t row) 240 { 241 if (mcp23018_status) { 242 /* if there was an error do nothing */ 243 } else { 244 /* set active row low : 0 245 set active row output : 1 246 set other rows hi-Z : 1 */ 247 uint8_t port = 0xFF & ~(1<<abs(row-4)); 248 mcp23018_status = i2c_write_register(I2C_ADDR, GPIOB, &port, 1, I2C_TIMEOUT); 249 } 250 251 uint8_t pin = row_pins[row]; 252 _SFR_IO8((pin >> 4) + 1) |= _BV(pin & 0xF); /* OUT */ 253 _SFR_IO8((pin >> 4) + 2) &= ~_BV(pin & 0xF); /* LOW */ 254 } 255 256 static void unselect_rows(void) 257 { 258 for(uint8_t x = 0; x < MATRIX_ROWS; x++) { 259 uint8_t pin = row_pins[x]; 260 _SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF); /* IN */ 261 _SFR_IO8((pin >> 4) + 2) |= _BV(pin & 0xF); /* HI */ 262 } 263 }