ec_switch_matrix.c (4092B)
1 /* Copyright 2020 sekigon-gonnoc 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 "ec_switch_matrix.h" 18 #include <avr/interrupt.h> 19 #include "analog.h" 20 #include "print.h" 21 22 // pin connections 23 const uint8_t row_pins[] = MATRIX_ROW_PINS; 24 const uint8_t col_channels[] = MATRIX_COL_CHANNELS; 25 const uint8_t mux_sel_pins[] = MUX_SEL_PINS; 26 27 _Static_assert(sizeof(mux_sel_pins) == 3, "invalid MUX_SEL_PINS"); 28 29 static ecsm_config_t config; 30 static uint16_t ecsm_sw_value[MATRIX_ROWS][MATRIX_COLS]; 31 32 static inline void discharge_capacitor(void) { gpio_set_pin_output(DISCHARGE_PIN); } 33 static inline void charge_capacitor(uint8_t row) { 34 gpio_set_pin_input(DISCHARGE_PIN); 35 gpio_write_pin_high(row_pins[row]); 36 } 37 38 static inline void clear_all_row_pins(void) { 39 for (int row = 0; row < sizeof(row_pins); row++) { 40 gpio_write_pin_low(row_pins[row]); 41 } 42 } 43 44 static inline void init_mux_sel(void) { 45 for (int idx = 0; idx < sizeof(mux_sel_pins); idx++) { 46 gpio_set_pin_output(mux_sel_pins[idx]); 47 } 48 } 49 50 static inline void select_mux(uint8_t col) { 51 uint8_t ch = col_channels[col]; 52 gpio_write_pin(mux_sel_pins[0], ch & 1); 53 gpio_write_pin(mux_sel_pins[1], ch & 2); 54 gpio_write_pin(mux_sel_pins[2], ch & 4); 55 } 56 57 static inline void init_row(void) { 58 for (int idx = 0; idx < sizeof(row_pins); idx++) { 59 gpio_set_pin_output(row_pins[idx]); 60 gpio_write_pin_low(row_pins[idx]); 61 } 62 } 63 64 // Initialize pins 65 int ecsm_init(ecsm_config_t const* const ecsm_config) { 66 // save config 67 config = *ecsm_config; 68 69 // initialize discharge pin as discharge mode 70 gpio_write_pin_low(DISCHARGE_PIN); 71 gpio_set_pin_output(DISCHARGE_PIN); 72 73 // set analog reference 74 analogReference(ADC_REF_POWER); 75 76 // initialize drive lines 77 init_row(); 78 79 // initialize multiplexer select pin 80 init_mux_sel(); 81 82 // set discharge pin to charge mode 83 gpio_set_pin_input(DISCHARGE_PIN); 84 85 return 0; 86 } 87 88 // Read key value of key (row, col) 89 uint16_t ecsm_readkey_raw(uint8_t row, uint8_t col) { 90 uint16_t sw_value = 0; 91 92 discharge_capacitor(); 93 94 select_mux(col); 95 96 clear_all_row_pins(); 97 98 cli(); 99 100 charge_capacitor(row); 101 102 sw_value = analogReadPin(ANALOG_PORT); 103 104 sei(); 105 106 return sw_value; 107 } 108 109 // Update press/release state of key at (row, col) 110 bool ecsm_update_key(matrix_row_t* current_row, uint8_t col, uint16_t sw_value) { 111 bool current_state = (*current_row >> col) & 1; 112 113 // press to release 114 if (current_state && sw_value < config.low_threshold) { 115 *current_row &= ~(1 << col); 116 return true; 117 } 118 119 // release to press 120 if ((!current_state) && sw_value > config.high_threshold) { 121 *current_row |= (1 << col); 122 return true; 123 } 124 125 return false; 126 } 127 128 // Scan key values and update matrix state 129 bool ecsm_matrix_scan(matrix_row_t current_matrix[]) { 130 bool updated = false; 131 132 for (int col = 0; col < sizeof(col_channels); col++) { 133 for (int row = 0; row < sizeof(row_pins); row++) { 134 ecsm_sw_value[row][col] = ecsm_readkey_raw(row, col); 135 updated |= ecsm_update_key(¤t_matrix[row], col, ecsm_sw_value[row][col]); 136 } 137 } 138 139 return updated; 140 } 141 142 // Print key values 143 void ecsm_print_matrix(void) { 144 for (int row = 0; row < sizeof(row_pins); row++) { 145 for (int col = 0; col < sizeof(col_channels); col++) { 146 xprintf("%4d", ecsm_sw_value[row][col]); 147 } 148 xprintf("\n"); 149 } 150 }