qmk_firmware

QMK firmware for my keyboards (Corne, Sweep Ferris) and trackball (Ploopy Adept)
Log | Files | Refs | Submodules | LICENSE

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(&current_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 }