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