matrix.c (8352B)
1 /* Copyright 2018 Evy Dekkers 2 * 3 * This program is free software: you can redistribute it and/or modify 4 * it under the terms of the GNU General Public License as published by 5 * the Free Software Foundation, either version 2 of the License, or 6 * (at your option) any later version. 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU General Public License for more details. 12 * 13 * You should have received a copy of the GNU General Public License 14 * along with this program. If not, see <http://www.gnu.org/licenses/>. 15 */ 16 #include <stdint.h> 17 #include <stdbool.h> 18 #if defined(__AVR__) 19 #include <avr/io.h> 20 #endif 21 #include "wait.h" 22 #include "print.h" 23 #include "debug.h" 24 #include "util.h" 25 #include "matrix.h" 26 #include "timer.h" 27 28 29 /* Set 0 if debouncing isn't needed */ 30 #ifndef DEBOUNCE 31 # define DEBOUNCE 5 32 #endif 33 34 #define COL_SHIFTER ((uint32_t)1) 35 36 static uint16_t debouncing_time; 37 static bool debouncing = false; 38 39 40 static const uint8_t row_pins[MATRIX_ROWS] = MATRIX_ROW_PINS; 41 42 /* matrix state(1:on, 0:off) */ 43 static matrix_row_t matrix[MATRIX_ROWS]; 44 static matrix_row_t matrix_debouncing[MATRIX_ROWS]; 45 46 static void init_rows(void); 47 static bool read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col); 48 static void unselect_cols(void); 49 static void select_col(uint8_t col); 50 51 __attribute__ ((weak)) 52 void matrix_init_user(void) {} 53 54 __attribute__ ((weak)) 55 void matrix_scan_user(void) {} 56 57 __attribute__ ((weak)) 58 void matrix_init_kb(void) { 59 matrix_init_user(); 60 } 61 62 __attribute__ ((weak)) 63 void matrix_scan_kb(void) { 64 matrix_scan_user(); 65 } 66 67 inline 68 uint8_t matrix_rows(void) { 69 return MATRIX_ROWS; 70 } 71 72 inline 73 uint8_t matrix_cols(void) { 74 return MATRIX_COLS; 75 } 76 77 void matrix_init(void) { 78 unselect_cols(); 79 init_rows(); 80 81 // initialize matrix state: all keys off 82 for (uint8_t i=0; i < MATRIX_ROWS; i++) { 83 matrix[i] = 0; 84 matrix_debouncing[i] = 0; 85 } 86 87 matrix_init_kb(); 88 } 89 90 uint8_t matrix_scan(void) 91 { 92 // Set col, read rows 93 for (uint8_t current_col = 0; current_col < MATRIX_COLS; current_col++) { 94 bool matrix_changed = read_rows_on_col(matrix_debouncing, current_col); 95 if (matrix_changed) { 96 debouncing = true; 97 debouncing_time = timer_read(); 98 } 99 } 100 101 if (debouncing && (timer_elapsed(debouncing_time) > DEBOUNCE)) { 102 for (uint8_t i = 0; i < MATRIX_ROWS; i++) { 103 matrix[i] = matrix_debouncing[i]; 104 } 105 debouncing = false; 106 } 107 108 matrix_scan_kb(); 109 return 1; 110 } 111 112 inline 113 bool matrix_is_on(uint8_t row, uint8_t col) 114 { 115 return (matrix[row] & ((matrix_row_t)1<<col)); 116 } 117 118 inline 119 matrix_row_t matrix_get_row(uint8_t row) 120 { 121 return matrix[row]; 122 } 123 124 void matrix_print(void) 125 { 126 print("\nr/c 0123456789ABCDEFGHIJKLMNOPQRSTUV \n"); 127 128 for (uint8_t row = 0; row < MATRIX_ROWS; row++) { 129 print_hex8(row); print(": "); 130 print_bin_reverse32(matrix_get_row(row)); 131 print("\n"); 132 } 133 } 134 135 static bool read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col) 136 { 137 bool matrix_changed = false; 138 139 // Select col and wait for col selecton to stabilize 140 select_col(current_col); 141 wait_us(30); 142 143 // For each row... 144 for(uint8_t row_index = 0; row_index < MATRIX_ROWS; row_index++) 145 { 146 // Store last value of row prior to reading 147 matrix_row_t last_row_value = current_matrix[row_index]; 148 149 // Check row pin state 150 // Use the otherwise unused row: 3, col: 0 for caps lock 151 if (row_index == 2 && current_col == 2) { 152 // Pin E2 uses active low 153 if ((_SFR_IO8(E2 >> 4) & _BV(E2 & 0xF)) == 0) 154 { 155 // Pin LO, set col bit 156 current_matrix[row_index] |= (COL_SHIFTER << current_col); 157 } 158 else 159 { 160 // Pin HI, clear col bit 161 current_matrix[row_index] &= ~(COL_SHIFTER << current_col); 162 } 163 } 164 else { 165 if ((_SFR_IO8(row_pins[row_index] >> 4) & _BV(row_pins[row_index] & 0xF))) 166 { 167 // Pin HI, set col bit 168 current_matrix[row_index] |= (COL_SHIFTER << current_col); 169 } 170 else 171 { 172 // Pin LO, clear col bit 173 current_matrix[row_index] &= ~(COL_SHIFTER << current_col); 174 } 175 } 176 177 // Determine if the matrix changed state 178 if ((last_row_value != current_matrix[row_index]) && !(matrix_changed)) 179 { 180 matrix_changed = true; 181 } 182 } 183 184 // Unselect cols 185 unselect_cols(); 186 187 return matrix_changed; 188 } 189 190 /* Row pin configuration 191 * row: 0 1 2 3 4 192 * pin: D0 D1 D2 D3 D5 193 * 194 * Caps lock uses its own pin E2 195 */ 196 static void init_rows(void) { 197 gpio_set_pin_input(D0); 198 gpio_set_pin_input(D1); 199 gpio_set_pin_input(D2); 200 gpio_set_pin_input(D3); 201 gpio_set_pin_input(D5); 202 203 gpio_set_pin_input_high(E2); 204 } 205 206 /* Columns 0 - 16 207 * col 0: B5 208 * col 1: B6 209 * These columns use a 74HC237D 3 to 8 bit demultiplexer. 210 * A B C GL1 211 * col / pin: PF0 PF1 PC7 PC6 212 * 2: 0 0 0 1 213 * 3: 1 0 0 1 214 * 4: 0 1 0 1 215 * 5: 1 1 0 1 216 * 6: 0 0 1 1 217 * 7: 1 0 1 1 218 * 8: 0 1 1 1 219 * 9: 1 1 1 1 220 * col 10: E6 221 * col 11: B0 222 * col 12: B7 223 * col 13: D4 224 * col 14: D6 225 * col 15: D7 226 * col 16: B4 227 */ 228 static void unselect_cols(void) { 229 gpio_set_pin_output(B0); 230 gpio_set_pin_output(B4); 231 gpio_set_pin_output(B5); 232 gpio_set_pin_output(B6); 233 gpio_set_pin_output(B7); 234 gpio_write_pin_low(B0); 235 gpio_write_pin_low(B4); 236 gpio_write_pin_low(B5); 237 gpio_write_pin_low(B6); 238 gpio_write_pin_low(B7); 239 240 gpio_set_pin_output(D4); 241 gpio_set_pin_output(D6); 242 gpio_set_pin_output(D7); 243 gpio_write_pin_low(D4); 244 gpio_write_pin_low(D6); 245 gpio_write_pin_low(D7); 246 247 gpio_set_pin_output(E6); 248 gpio_write_pin_low(E6); 249 250 gpio_set_pin_output(F0); 251 gpio_set_pin_output(F1); 252 gpio_write_pin_low(F0); 253 gpio_write_pin_low(F1); 254 255 gpio_set_pin_output(C6); 256 gpio_set_pin_output(C7); 257 gpio_write_pin_low(C6); 258 gpio_write_pin_low(C7); 259 } 260 261 static void select_col(uint8_t col) 262 { 263 switch (col) { 264 case 0: 265 gpio_write_pin_high(B5); // HI 266 break; 267 case 1: 268 gpio_write_pin_high(B6); // HI 269 break; 270 case 2: 271 gpio_write_pin_high(C6); // HI 272 break; 273 case 3: 274 gpio_write_pin_high(C6); // HI 275 gpio_write_pin_high(F0); // HI 276 break; 277 case 4: 278 gpio_write_pin_high(C6); // HI 279 gpio_write_pin_high(F1); // HI 280 break; 281 case 5: 282 gpio_write_pin_high(C6); // HI 283 gpio_write_pin_high(F0); // HI 284 gpio_write_pin_high(F1); // HI 285 break; 286 case 6: 287 gpio_write_pin_high(C6); // HI 288 gpio_write_pin_high(C7); // HI 289 break; 290 case 7: 291 gpio_write_pin_high(C6); // HI 292 gpio_write_pin_high(F0); // HI 293 gpio_write_pin_high(C7); // HI 294 break; 295 case 8: 296 gpio_write_pin_high(C6); // HI 297 gpio_write_pin_high(F1); // HI 298 gpio_write_pin_high(C7); // HI 299 break; 300 case 9: 301 gpio_write_pin_high(C6); // HI 302 gpio_write_pin_high(F0); // HI 303 gpio_write_pin_high(F1); // HI 304 gpio_write_pin_high(C7); // HI 305 break; 306 case 10: 307 gpio_write_pin_high(E6); // HI 308 break; 309 case 11: 310 gpio_write_pin_high(B0); // HI 311 break; 312 case 12: 313 gpio_write_pin_high(B7); // HI 314 break; 315 case 13: 316 gpio_write_pin_high(D4); // HI 317 break; 318 case 14: 319 gpio_write_pin_high(D6); // HI 320 break; 321 case 15: 322 gpio_write_pin_high(D7); // HI 323 break; 324 case 16: 325 gpio_write_pin_high(B4); // HI 326 break; 327 } 328 }