ec.c (5323B)
1 /* Copyright 2023 Viktus Design LLC 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.h" 18 #include <avr/interrupt.h> 19 20 #include "analog.h" 21 //#include "debug.h" 22 23 // sensing channel definitions 24 #define A0 0 25 #define A1 1 26 #define A2 2 27 #define A3 3 28 #define A4 4 29 #define A5 5 30 #define A6 6 31 #define A7 7 32 33 // analog connection settings 34 #define DISCHARGE_PIN D3 35 #define ANALOG_PORT D4 36 37 #ifndef MUX_SEL_PIN 38 # define MUX_SEL_PINS \ 39 { D0, D1, D2 } 40 #endif 41 42 // pin connections 43 const uint8_t row_channels[] = MATRIX_ROW_PINS; 44 const uint8_t col_pins[] = MATRIX_COL_PINS; 45 const uint8_t mux_sel_pins[] = MUX_SEL_PINS; 46 47 _Static_assert(sizeof(mux_sel_pins) == 3, "invalid MUX_SEL_PINS"); 48 49 static ec_config_t config; 50 static uint16_t ec_sw_value[MATRIX_COLS][MATRIX_ROWS]; 51 52 static inline void discharge_capacitor(void) { gpio_set_pin_output(DISCHARGE_PIN); } 53 static inline void charge_capacitor(uint8_t col) { 54 gpio_set_pin_input(DISCHARGE_PIN); 55 gpio_write_pin_high(col_pins[col]); 56 } 57 58 static inline void clear_all_col_pins(void) { 59 for (int col = 0; col < sizeof(col_pins); col++) { 60 gpio_write_pin_low(col_pins[col]); 61 } 62 } 63 64 void init_mux_sel(void) { 65 for (int idx = 0; idx < sizeof(mux_sel_pins); idx++) { 66 gpio_set_pin_output(mux_sel_pins[idx]); 67 } 68 } 69 70 void select_mux(uint8_t row) { 71 uint8_t ch = row_channels[row]; 72 gpio_write_pin(mux_sel_pins[0], ch & 1); 73 gpio_write_pin(mux_sel_pins[1], ch & 2); 74 gpio_write_pin(mux_sel_pins[2], ch & 4); 75 } 76 77 void init_col(void) { 78 for (int idx = 0; idx < sizeof(col_pins); idx++) { 79 gpio_set_pin_output(col_pins[idx]); 80 gpio_write_pin_low(col_pins[idx]); 81 } 82 } 83 84 void ec_init(ec_config_t const* const ec_config) { 85 // save config 86 config = *ec_config; 87 88 // initialize discharge pin as discharge mode 89 gpio_write_pin_low(DISCHARGE_PIN); 90 gpio_set_pin_output(DISCHARGE_PIN); 91 92 // set analog reference 93 analogReference(ADC_REF_POWER); 94 95 // initialize drive lines 96 init_col(); 97 98 // initialize multiplexer select pin 99 init_mux_sel(); 100 101 // set discharge pin to charge mode 102 gpio_set_pin_input(DISCHARGE_PIN); 103 } 104 105 uint16_t ec_readkey_raw(uint8_t col, uint8_t row) { 106 uint16_t sw_value = 0; 107 108 discharge_capacitor(); 109 110 select_mux(row); 111 112 clear_all_col_pins(); 113 114 cli(); 115 116 charge_capacitor(col); 117 118 sw_value = analogReadPin(ANALOG_PORT); 119 120 sei(); 121 122 return sw_value; 123 } 124 125 bool ec_update_key(matrix_row_t* current_row, matrix_row_t col, uint16_t sw_value, uint16_t reset_pt, uint16_t actuation_pt) { 126 bool current_state = (*current_row >> col) & 1; 127 128 // press to release 129 if (current_state && sw_value < reset_pt) { 130 *current_row &= ~(MATRIX_ROW_SHIFTER << col); 131 return true; 132 } 133 134 // release to press 135 if ((!current_state) && sw_value > actuation_pt) { 136 *current_row |= (MATRIX_ROW_SHIFTER << col); 137 return true; 138 } 139 140 return false; 141 } 142 143 bool ec_matrix_scan(matrix_row_t current_matrix[]) { 144 bool updated = false; 145 146 for (int row = 0; row < sizeof(row_channels); row++) { 147 for (int col = 0; col < sizeof(col_pins); col++) { 148 uint16_t reset_pt = config.reset_pt; 149 uint16_t actuation_pt = config.actuation_pt; 150 151 switch(row) { 152 case 0: 153 switch(col) { 154 case 15: // lower threshold for split backspace: 155 case 16: // lower threshold for 2U backspace: 2U(37 rest, 62 btm) 156 reset_pt = 45; 157 actuation_pt = 50; 158 break; 159 } 160 break; 161 case 4: 162 switch(col) { 163 case 8: // Lower threshold for spacebar: 7U(37 rest, 63 btm) 164 reset_pt = 55; 165 actuation_pt = 60; 166 break; 167 case 13: // Lower threshold for right bottom mods: 1.5U(40 rest, 65 btm) 168 reset_pt = 47; 169 actuation_pt = 53; 170 break; 171 } 172 break; 173 } 174 175 ec_sw_value[col][row] = ec_readkey_raw(col, row); 176 updated |= ec_update_key(¤t_matrix[row], col, ec_sw_value[col][row], reset_pt, actuation_pt); 177 } 178 } 179 180 return updated; 181 } 182 183 // console debugging for pad values 184 /*void ec_dprint_matrix(void) { 185 for (int row = 0; row < sizeof(row_channels); row++) { 186 for (int col = 0; col < sizeof(col_pins); col++) { 187 dprintf("%5d", ec_sw_value[col][row]); 188 } 189 dprintf("\n"); 190 } 191 }*/