matrix.c (10309B)
1 /* 2 Copyright 2012-2018 Jun Wako, Jack Humbert, Yiancar 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 "atomic_util.h" 18 #include "util.h" 19 #include "wait.h" 20 #include "matrix.h" 21 #include "debounce.h" 22 #ifndef readPort 23 # include "gpio_extr.h" 24 #endif 25 26 #ifndef MATRIX_DEBUG_PIN 27 # define MATRIX_DEBUG_PIN_INIT() 28 # define MATRIX_DEBUG_SCAN_START() 29 # define MATRIX_DEBUG_SCAN_END() 30 # define MATRIX_DEBUG_DELAY_START() 31 # define MATRIX_DEBUG_DELAY_END() 32 # define MATRIX_DEBUG_GAP() 33 #else 34 # define MATRIX_DEBUG_GAP() asm volatile("nop \n nop" ::: "memory") 35 #endif 36 37 #ifndef MATRIX_IO_DELAY_ALWAYS 38 # define MATRIX_IO_DELAY_ALWAYS 0 39 #endif 40 41 #ifdef DIRECT_PINS 42 static pin_t direct_pins[MATRIX_ROWS][MATRIX_COLS] = DIRECT_PINS; 43 #elif (DIODE_DIRECTION == ROW2COL) || (DIODE_DIRECTION == COL2ROW) 44 static const pin_t row_pins[MATRIX_ROWS] = MATRIX_ROW_PINS; 45 static const pin_t col_pins[MATRIX_COLS] = MATRIX_COL_PINS; 46 # ifdef MATRIX_MUL_SELECT 47 static const pin_t col_sel[MATRIX_COLS] = MATRIX_MUL_SEL; 48 # endif 49 #endif 50 51 #ifdef MATRIX_IO_DELAY_PORTS 52 static const pin_t delay_ports[] = {MATRIX_IO_DELAY_PORTS}; 53 static const port_data_t delay_masks[] = {MATRIX_IO_DELAY_MASKS}; 54 # ifdef MATRIX_IO_DELAY_MULSEL 55 static const uint8_t delay_sel[] = {MATRIX_IO_DELAY_MULSEL}; 56 # endif 57 #endif 58 59 /* matrix state(1:on, 0:off) */ 60 extern matrix_row_t raw_matrix[MATRIX_ROWS]; // raw values 61 extern matrix_row_t matrix[MATRIX_ROWS]; // debounced values 62 63 static inline void gpio_atomic_set_pin_output_low(pin_t pin) { 64 ATOMIC_BLOCK_FORCEON { 65 gpio_set_pin_output(pin); 66 gpio_write_pin_low(pin); 67 } 68 } 69 70 static inline void gpio_atomic_set_pin_input_high(pin_t pin) { 71 ATOMIC_BLOCK_FORCEON { 72 gpio_set_pin_input_high(pin); 73 } 74 } 75 76 // matrix code 77 78 #ifdef DIRECT_PINS 79 80 static void init_pins(void) { 81 for (int row = 0; row < MATRIX_ROWS; row++) { 82 for (int col = 0; col < MATRIX_COLS; col++) { 83 pin_t pin = direct_pins[row][col]; 84 if (pin != NO_PIN) { 85 gpio_set_pin_input_high(pin); 86 } 87 } 88 } 89 } 90 91 static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row) { 92 // Start with a clear matrix row 93 matrix_row_t current_row_value = 0; 94 95 for (uint8_t col_index = 0; col_index < MATRIX_COLS; col_index++) { 96 pin_t pin = direct_pins[current_row][col_index]; 97 if (pin != NO_PIN) { 98 current_row_value |= gpio_read_pin(pin) ? 0 : (MATRIX_ROW_SHIFTER << col_index); 99 } 100 } 101 102 // If the row has changed, store the row and return the changed flag. 103 if (current_matrix[current_row] != current_row_value) { 104 current_matrix[current_row] = current_row_value; 105 return true; 106 } 107 return false; 108 } 109 110 #elif defined(DIODE_DIRECTION) 111 # if (DIODE_DIRECTION == COL2ROW) 112 113 static void select_row(uint8_t row) { 114 gpio_atomic_set_pin_output_low(row_pins[row]); 115 } 116 117 static void unselect_row(uint8_t row) { 118 gpio_atomic_set_pin_input_high(row_pins[row]); 119 } 120 121 static void unselect_rows(void) { 122 for (uint8_t x = 0; x < MATRIX_ROWS; x++) { 123 gpio_atomic_set_pin_input_high(row_pins[x]); 124 } 125 } 126 127 static void init_pins(void) { 128 # ifdef MATRIX_MUL_SELECT 129 gpio_set_pin_output(MATRIX_MUL_SELECT); 130 gpio_write_pin_low(MATRIX_MUL_SELECT); 131 # endif 132 unselect_rows(); 133 for (uint8_t x = 0; x < MATRIX_COLS; x++) { 134 gpio_atomic_set_pin_input_high(col_pins[x]); 135 } 136 } 137 138 static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row) { 139 // Start with a clear matrix row 140 matrix_row_t current_row_value = 0; 141 142 // Select row 143 select_row(current_row); 144 matrix_output_select_delay(); 145 146 // For each col... 147 for (uint8_t col_index = 0; col_index < MATRIX_COLS; col_index++) { 148 // Select the col pin to read (active low) 149 # ifdef MATRIX_MUL_SELECT 150 gpio_write_pin(MATRIX_MUL_SELECT, col_sel[col_index]); 151 waitInputPinDelay(); 152 # endif 153 uint8_t pin_state = gpio_read_pin(col_pins[col_index]); 154 155 // Populate the matrix row with the state of the col pin 156 current_row_value |= pin_state ? 0 : (MATRIX_ROW_SHIFTER << col_index); 157 } 158 159 // Unselect row 160 unselect_row(current_row); 161 # ifdef MATRIX_IO_DELAY_PORTS 162 if (current_row_value) { // wait for col signal to go HIGH 163 bool is_pressed; 164 do { 165 MATRIX_DEBUG_DELAY_START(); 166 is_pressed = false; 167 for (uint8_t i = 0; i < ARRAY_SIZE(delay_ports); i++) { 168 # ifdef MATRIX_IO_DELAY_MULSEL 169 gpio_write_pin(MATRIX_MUL_SELECT, delay_sel[i]); 170 waitInputPinDelay(); 171 # endif 172 is_pressed |= ((readPort(delay_ports[i]) & delay_masks[i]) != delay_masks[i]); 173 } 174 MATRIX_DEBUG_DELAY_END(); 175 } while (is_pressed); 176 } 177 # endif 178 # ifdef MATRIX_IO_DELAY_ADAPTIVE 179 if (current_row_value) { // wait for col signal to go HIGH 180 for (uint8_t col_index = 0; col_index < MATRIX_COLS; col_index++) { 181 MATRIX_DEBUG_DELAY_START(); 182 # ifdef MATRIX_MUL_SELECT 183 gpio_write_pin(MATRIX_MUL_SELECT, col_sel[col_index]); 184 waitInputPinDelay(); 185 # endif 186 while (gpio_read_pin(col_pins[col_index]) == 0) { 187 } 188 MATRIX_DEBUG_DELAY_END(); 189 } 190 } 191 # endif 192 # ifdef MATRIX_IO_DELAY_ADAPTIVE2 193 if (current_row_value) { // wait for col signal to go HIGH 194 pin_t state; 195 do { 196 MATRIX_DEBUG_DELAY_START(); 197 state = 0; 198 for (uint8_t col_index = 0; col_index < MATRIX_COLS; col_index++) { 199 MATRIX_DEBUG_DELAY_END(); 200 MATRIX_DEBUG_DELAY_START(); 201 # ifdef MATRIX_MUL_SELECT 202 gpio_write_pin(MATRIX_MUL_SELECT, col_sel[col_index]); 203 waitInputPinDelay(); 204 # endif 205 state |= (gpio_read_pin(col_pins[col_index]) == 0); 206 } 207 MATRIX_DEBUG_DELAY_END(); 208 } while (state); 209 } 210 # endif 211 if (MATRIX_IO_DELAY_ALWAYS || current_row + 1 < MATRIX_ROWS) { 212 MATRIX_DEBUG_DELAY_START(); 213 matrix_output_unselect_delay(current_row, current_row_value != 0); // wait for col signal to go HIGH 214 MATRIX_DEBUG_DELAY_END(); 215 } 216 217 // If the row has changed, store the row and return the changed flag. 218 if (current_matrix[current_row] != current_row_value) { 219 current_matrix[current_row] = current_row_value; 220 return true; 221 } 222 return false; 223 } 224 225 # elif (DIODE_DIRECTION == ROW2COL) 226 227 static void select_col(uint8_t col) { 228 gpio_atomic_set_pin_output_low(col_pins[col]); 229 } 230 231 static void unselect_col(uint8_t col) { 232 gpio_atomic_set_pin_input_high(col_pins[col]); 233 } 234 235 static void unselect_cols(void) { 236 for (uint8_t x = 0; x < MATRIX_COLS; x++) { 237 gpio_atomic_set_pin_input_high(col_pins[x]); 238 } 239 } 240 241 static void init_pins(void) { 242 unselect_cols(); 243 for (uint8_t x = 0; x < MATRIX_ROWS; x++) { 244 gpio_atomic_set_pin_input_high(row_pins[x]); 245 } 246 } 247 248 static bool read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col) { 249 bool matrix_changed = false; 250 bool key_pressed = false; 251 252 // Select col 253 select_col(current_col); 254 matrix_output_select_delay(); 255 256 // For each row... 257 for (uint8_t row_index = 0; row_index < MATRIX_ROWS; row_index++) { 258 // Store last value of row prior to reading 259 matrix_row_t last_row_value = current_matrix[row_index]; 260 matrix_row_t current_row_value = last_row_value; 261 262 // Check row pin state 263 if (gpio_read_pin(row_pins[row_index]) == 0) { 264 // Pin LO, set col bit 265 current_row_value |= (MATRIX_ROW_SHIFTER << current_col); 266 key_pressed = true; 267 } else { 268 // Pin HI, clear col bit 269 current_row_value &= ~(MATRIX_ROW_SHIFTER << current_col); 270 } 271 272 // Determine if the matrix changed state 273 if ((last_row_value != current_row_value)) { 274 matrix_changed |= true; 275 current_matrix[row_index] = current_row_value; 276 } 277 } 278 279 // Unselect col 280 unselect_col(current_col); 281 if (MATRIX_IO_DELAY_ALWAYS || current_col + 1 < MATRIX_COLS) { 282 matrix_output_unselect_delay(current_col, key_pressed); // wait for col signal to go HIGH 283 } 284 285 return matrix_changed; 286 } 287 288 # else 289 # error DIODE_DIRECTION must be one of COL2ROW or ROW2COL! 290 # endif 291 #else 292 # error DIODE_DIRECTION is not defined! 293 #endif 294 295 void matrix_init(void) { 296 // initialize key pins 297 init_pins(); 298 299 // initialize matrix state: all keys off 300 for (uint8_t i = 0; i < MATRIX_ROWS; i++) { 301 raw_matrix[i] = 0; 302 matrix[i] = 0; 303 } 304 305 debounce_init(); 306 307 matrix_init_kb(); 308 } 309 310 uint8_t matrix_scan(void) { 311 bool changed = false; 312 MATRIX_DEBUG_PIN_INIT(); 313 314 MATRIX_DEBUG_SCAN_START(); 315 #if defined(DIRECT_PINS) || (DIODE_DIRECTION == COL2ROW) 316 // Set row, read cols 317 for (uint8_t current_row = 0; current_row < MATRIX_ROWS; current_row++) { 318 changed |= read_cols_on_row(raw_matrix, current_row); 319 } 320 #elif (DIODE_DIRECTION == ROW2COL) 321 // Set col, read rows 322 for (uint8_t current_col = 0; current_col < MATRIX_COLS; current_col++) { 323 changed |= read_rows_on_col(raw_matrix, current_col); 324 } 325 #endif 326 MATRIX_DEBUG_SCAN_END(); 327 MATRIX_DEBUG_GAP(); 328 329 MATRIX_DEBUG_SCAN_START(); 330 debounce(raw_matrix, matrix, changed); 331 MATRIX_DEBUG_SCAN_END(); 332 MATRIX_DEBUG_GAP(); 333 334 MATRIX_DEBUG_SCAN_START(); 335 matrix_scan_kb(); 336 MATRIX_DEBUG_SCAN_END(); 337 return (uint8_t)changed; 338 }