matrix.c (6189B)
1 /* Copyright 2022 @ Keychron (https://www.keychron.com) 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 17 #include "matrix.h" 18 #include "atomic_util.h" 19 #include <string.h> 20 21 // Pin connected to DS of 74HC595 22 #define DATA_PIN C15 23 // Pin connected to SH_CP of 74HC595 24 #define CLOCK_PIN A1 25 // Pin connected to ST_CP of 74HC595 26 #define LATCH_PIN A0 27 28 #ifdef MATRIX_ROW_PINS 29 static pin_t row_pins[MATRIX_ROWS] = MATRIX_ROW_PINS; 30 #endif // MATRIX_ROW_PINS 31 #ifdef MATRIX_COL_PINS 32 static pin_t col_pins[MATRIX_COLS] = MATRIX_COL_PINS; 33 #endif // MATRIX_COL_PINS 34 35 #define ROWS_PER_HAND (MATRIX_ROWS) 36 37 #ifndef NO_PIN_NUM 38 # define NO_PIN_NUM 8 39 #endif 40 41 #ifndef NO_PIN_OFFSET 42 # define NO_PIN_OFFSET 0 43 #endif 44 45 #ifndef CLR_REG_VAL 46 # define CLR_REG_VAL 0xFF 47 #endif 48 49 static inline void gpio_atomic_set_pin_output_low(pin_t pin) { 50 ATOMIC_BLOCK_FORCEON { 51 gpio_set_pin_output(pin); 52 gpio_write_pin_low(pin); 53 } 54 } 55 56 static inline void gpio_atomic_set_pin_output_high(pin_t pin) { 57 ATOMIC_BLOCK_FORCEON { 58 gpio_set_pin_output(pin); 59 gpio_write_pin_high(pin); 60 } 61 } 62 63 static inline void gpio_atomic_set_pin_input_high(pin_t pin) { 64 ATOMIC_BLOCK_FORCEON { 65 gpio_set_pin_input_high(pin); 66 } 67 } 68 69 static inline uint8_t readMatrixPin(pin_t pin) { 70 if (pin != NO_PIN) { 71 return gpio_read_pin(pin); 72 } else { 73 return 1; 74 } 75 } 76 77 static void shiftOut(uint16_t dataOut) { 78 for (uint8_t i = 0; i < NO_PIN_NUM; i++) { 79 if (dataOut & 0x1) { 80 gpio_atomic_set_pin_output_high(DATA_PIN); 81 } else { 82 gpio_atomic_set_pin_output_low(DATA_PIN); 83 } 84 dataOut = dataOut >> 1; 85 gpio_atomic_set_pin_output_high(CLOCK_PIN); 86 gpio_atomic_set_pin_output_low(CLOCK_PIN); 87 } 88 gpio_atomic_set_pin_output_high(LATCH_PIN); 89 gpio_atomic_set_pin_output_low(LATCH_PIN); 90 } 91 92 static void shiftout_single(uint8_t data) { 93 if (data & 0x1) { 94 gpio_atomic_set_pin_output_high(DATA_PIN); 95 } else { 96 gpio_atomic_set_pin_output_low(DATA_PIN); 97 } 98 gpio_atomic_set_pin_output_high(CLOCK_PIN); 99 gpio_atomic_set_pin_output_low(CLOCK_PIN); 100 101 gpio_atomic_set_pin_output_high(LATCH_PIN); 102 gpio_atomic_set_pin_output_low(LATCH_PIN); 103 } 104 105 static bool select_col(uint8_t col) { 106 pin_t pin = col_pins[col]; 107 108 if (pin != NO_PIN) { 109 gpio_atomic_set_pin_output_low(pin); 110 return true; 111 } else { 112 if (col == NO_PIN_START) { 113 shiftout_single(0x00); 114 } else { 115 shiftout_single(0x01); 116 } 117 return true; 118 } 119 return false; 120 } 121 122 static void unselect_col(uint8_t col) { 123 pin_t pin = col_pins[col]; 124 125 if (pin != NO_PIN) { 126 #ifdef MATRIX_UNSELECT_DRIVE_HIGH 127 gpio_atomic_set_pin_output_high(pin); 128 #else 129 gpio_atomic_set_pin_input_high(pin); 130 #endif 131 } else { 132 if (col == (MATRIX_COLS - NO_PIN_OFFSET - 1)) 133 gpio_atomic_set_pin_output_high(CLOCK_PIN); 134 gpio_atomic_set_pin_output_low(CLOCK_PIN); 135 gpio_atomic_set_pin_output_high(LATCH_PIN); 136 gpio_atomic_set_pin_output_low(LATCH_PIN); 137 } 138 } 139 140 static void unselect_cols(void) { 141 for (uint8_t x = 0; x < MATRIX_COLS; x++) { 142 pin_t pin = col_pins[x]; 143 if (pin != NO_PIN) { 144 #ifdef MATRIX_UNSELECT_DRIVE_HIGH 145 gpio_atomic_set_pin_output_high(pin); 146 #else 147 gpio_atomic_set_pin_input_high(pin); 148 #endif 149 } 150 if (x == (MATRIX_COLS - NO_PIN_OFFSET - 1)) 151 // unselect shift Register 152 shiftOut(CLR_REG_VAL); 153 } 154 } 155 156 static void matrix_init_pins(void) { 157 unselect_cols(); 158 for (uint8_t x = 0; x < MATRIX_ROWS; x++) { 159 if (row_pins[x] != NO_PIN) { 160 gpio_atomic_set_pin_input_high(row_pins[x]); 161 } 162 } 163 } 164 165 static void matrix_read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col, matrix_row_t row_shifter) { 166 bool key_pressed = false; 167 168 // Select col 169 if (!select_col(current_col)) { // select col 170 return; // skip NO_PIN col 171 } 172 173 if (current_col < 10) { 174 matrix_output_select_delay(); 175 } else { 176 for (int8_t cycle = 4; cycle > 0; cycle--) { 177 matrix_output_select_delay(); // 0.25us 178 matrix_output_select_delay(); 179 matrix_output_select_delay(); 180 matrix_output_select_delay(); 181 } 182 } 183 184 // For each row... 185 for (uint8_t row_index = 0; row_index < ROWS_PER_HAND; row_index++) { 186 // Check row pin state 187 if (readMatrixPin(row_pins[row_index]) == 0) { 188 // Pin LO, set col bit 189 current_matrix[row_index] |= row_shifter; 190 key_pressed = true; 191 } else { 192 // Pin HI, clear col bit 193 current_matrix[row_index] &= ~row_shifter; 194 } 195 } 196 197 // Unselect col 198 unselect_col(current_col); 199 matrix_output_unselect_delay(current_col, key_pressed); // wait for all Row signals to go HIGH 200 } 201 202 void matrix_init_custom(void) { 203 // initialize key pins 204 matrix_init_pins(); 205 } 206 207 bool matrix_scan_custom(matrix_row_t current_matrix[]) { 208 matrix_row_t curr_matrix[MATRIX_ROWS] = {0}; 209 210 // Set col, read rows 211 matrix_row_t row_shifter = MATRIX_ROW_SHIFTER; 212 for (uint8_t current_col = 0; current_col < MATRIX_COLS; current_col++, row_shifter <<= 1) { 213 matrix_read_rows_on_col(curr_matrix, current_col, row_shifter); 214 } 215 216 bool changed = memcmp(current_matrix, curr_matrix, sizeof(curr_matrix)) != 0; 217 if (changed) memcpy(current_matrix, curr_matrix, sizeof(curr_matrix)); 218 219 return changed; 220 }