qmk_firmware

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

matrix.c (10309B)


      1 /*
      2 Copyright 2012-2018 Jun Wako, Jack Humbert, Yiancar
      3 
      4 This program is free software: you can redistribute it and/or modify
      5 it under the terms of the GNU General Public License as published by
      6 the Free Software Foundation, either version 2 of the License, or
      7 (at your option) any later version.
      8 
      9 This program is distributed in the hope that it will be useful,
     10 but WITHOUT ANY WARRANTY; without even the implied warranty of
     11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     12 GNU General Public License for more details.
     13 
     14 You should have received a copy of the GNU General Public License
     15 along with this program.  If not, see <http://www.gnu.org/licenses/>.
     16 */
     17 #include "atomic_util.h"
     18 #include "util.h"
     19 #include "wait.h"
     20 #include "matrix.h"
     21 #include "debounce.h"
     22 #ifndef readPort
     23 #    include "gpio_extr.h"
     24 #endif
     25 
     26 #ifndef MATRIX_DEBUG_PIN
     27 #    define MATRIX_DEBUG_PIN_INIT()
     28 #    define MATRIX_DEBUG_SCAN_START()
     29 #    define MATRIX_DEBUG_SCAN_END()
     30 #    define MATRIX_DEBUG_DELAY_START()
     31 #    define MATRIX_DEBUG_DELAY_END()
     32 #    define MATRIX_DEBUG_GAP()
     33 #else
     34 #    define MATRIX_DEBUG_GAP() asm volatile("nop \n nop" ::: "memory")
     35 #endif
     36 
     37 #ifndef MATRIX_IO_DELAY_ALWAYS
     38 #    define MATRIX_IO_DELAY_ALWAYS 0
     39 #endif
     40 
     41 #ifdef DIRECT_PINS
     42 static pin_t direct_pins[MATRIX_ROWS][MATRIX_COLS] = DIRECT_PINS;
     43 #elif (DIODE_DIRECTION == ROW2COL) || (DIODE_DIRECTION == COL2ROW)
     44 static const pin_t row_pins[MATRIX_ROWS] = MATRIX_ROW_PINS;
     45 static const pin_t col_pins[MATRIX_COLS] = MATRIX_COL_PINS;
     46 #    ifdef MATRIX_MUL_SELECT
     47 static const pin_t col_sel[MATRIX_COLS] = MATRIX_MUL_SEL;
     48 #    endif
     49 #endif
     50 
     51 #ifdef MATRIX_IO_DELAY_PORTS
     52 static const pin_t       delay_ports[] = {MATRIX_IO_DELAY_PORTS};
     53 static const port_data_t delay_masks[] = {MATRIX_IO_DELAY_MASKS};
     54 #    ifdef MATRIX_IO_DELAY_MULSEL
     55 static const uint8_t delay_sel[] = {MATRIX_IO_DELAY_MULSEL};
     56 #    endif
     57 #endif
     58 
     59 /* matrix state(1:on, 0:off) */
     60 extern matrix_row_t raw_matrix[MATRIX_ROWS]; // raw values
     61 extern matrix_row_t matrix[MATRIX_ROWS];     // debounced values
     62 
     63 static inline void gpio_atomic_set_pin_output_low(pin_t pin) {
     64     ATOMIC_BLOCK_FORCEON {
     65         gpio_set_pin_output(pin);
     66         gpio_write_pin_low(pin);
     67     }
     68 }
     69 
     70 static inline void gpio_atomic_set_pin_input_high(pin_t pin) {
     71     ATOMIC_BLOCK_FORCEON {
     72         gpio_set_pin_input_high(pin);
     73     }
     74 }
     75 
     76 // matrix code
     77 
     78 #ifdef DIRECT_PINS
     79 
     80 static void init_pins(void) {
     81     for (int row = 0; row < MATRIX_ROWS; row++) {
     82         for (int col = 0; col < MATRIX_COLS; col++) {
     83             pin_t pin = direct_pins[row][col];
     84             if (pin != NO_PIN) {
     85                 gpio_set_pin_input_high(pin);
     86             }
     87         }
     88     }
     89 }
     90 
     91 static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row) {
     92     // Start with a clear matrix row
     93     matrix_row_t current_row_value = 0;
     94 
     95     for (uint8_t col_index = 0; col_index < MATRIX_COLS; col_index++) {
     96         pin_t pin = direct_pins[current_row][col_index];
     97         if (pin != NO_PIN) {
     98             current_row_value |= gpio_read_pin(pin) ? 0 : (MATRIX_ROW_SHIFTER << col_index);
     99         }
    100     }
    101 
    102     // If the row has changed, store the row and return the changed flag.
    103     if (current_matrix[current_row] != current_row_value) {
    104         current_matrix[current_row] = current_row_value;
    105         return true;
    106     }
    107     return false;
    108 }
    109 
    110 #elif defined(DIODE_DIRECTION)
    111 #    if (DIODE_DIRECTION == COL2ROW)
    112 
    113 static void select_row(uint8_t row) {
    114     gpio_atomic_set_pin_output_low(row_pins[row]);
    115 }
    116 
    117 static void unselect_row(uint8_t row) {
    118     gpio_atomic_set_pin_input_high(row_pins[row]);
    119 }
    120 
    121 static void unselect_rows(void) {
    122     for (uint8_t x = 0; x < MATRIX_ROWS; x++) {
    123         gpio_atomic_set_pin_input_high(row_pins[x]);
    124     }
    125 }
    126 
    127 static void init_pins(void) {
    128 #        ifdef MATRIX_MUL_SELECT
    129     gpio_set_pin_output(MATRIX_MUL_SELECT);
    130     gpio_write_pin_low(MATRIX_MUL_SELECT);
    131 #        endif
    132     unselect_rows();
    133     for (uint8_t x = 0; x < MATRIX_COLS; x++) {
    134         gpio_atomic_set_pin_input_high(col_pins[x]);
    135     }
    136 }
    137 
    138 static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row) {
    139     // Start with a clear matrix row
    140     matrix_row_t current_row_value = 0;
    141 
    142     // Select row
    143     select_row(current_row);
    144     matrix_output_select_delay();
    145 
    146     // For each col...
    147     for (uint8_t col_index = 0; col_index < MATRIX_COLS; col_index++) {
    148         // Select the col pin to read (active low)
    149 #        ifdef MATRIX_MUL_SELECT
    150         gpio_write_pin(MATRIX_MUL_SELECT, col_sel[col_index]);
    151         waitInputPinDelay();
    152 #        endif
    153         uint8_t pin_state = gpio_read_pin(col_pins[col_index]);
    154 
    155         // Populate the matrix row with the state of the col pin
    156         current_row_value |= pin_state ? 0 : (MATRIX_ROW_SHIFTER << col_index);
    157     }
    158 
    159     // Unselect row
    160     unselect_row(current_row);
    161 #        ifdef MATRIX_IO_DELAY_PORTS
    162     if (current_row_value) { // wait for col signal to go HIGH
    163         bool is_pressed;
    164         do {
    165             MATRIX_DEBUG_DELAY_START();
    166             is_pressed = false;
    167             for (uint8_t i = 0; i < ARRAY_SIZE(delay_ports); i++) {
    168 #            ifdef MATRIX_IO_DELAY_MULSEL
    169                 gpio_write_pin(MATRIX_MUL_SELECT, delay_sel[i]);
    170                 waitInputPinDelay();
    171 #            endif
    172                 is_pressed |= ((readPort(delay_ports[i]) & delay_masks[i]) != delay_masks[i]);
    173             }
    174             MATRIX_DEBUG_DELAY_END();
    175         } while (is_pressed);
    176     }
    177 #        endif
    178 #        ifdef MATRIX_IO_DELAY_ADAPTIVE
    179     if (current_row_value) { // wait for col signal to go HIGH
    180         for (uint8_t col_index = 0; col_index < MATRIX_COLS; col_index++) {
    181             MATRIX_DEBUG_DELAY_START();
    182 #            ifdef MATRIX_MUL_SELECT
    183             gpio_write_pin(MATRIX_MUL_SELECT, col_sel[col_index]);
    184             waitInputPinDelay();
    185 #            endif
    186             while (gpio_read_pin(col_pins[col_index]) == 0) {
    187             }
    188             MATRIX_DEBUG_DELAY_END();
    189         }
    190     }
    191 #        endif
    192 #        ifdef MATRIX_IO_DELAY_ADAPTIVE2
    193     if (current_row_value) { // wait for col signal to go HIGH
    194         pin_t state;
    195         do {
    196             MATRIX_DEBUG_DELAY_START();
    197             state = 0;
    198             for (uint8_t col_index = 0; col_index < MATRIX_COLS; col_index++) {
    199                 MATRIX_DEBUG_DELAY_END();
    200                 MATRIX_DEBUG_DELAY_START();
    201 #            ifdef MATRIX_MUL_SELECT
    202                 gpio_write_pin(MATRIX_MUL_SELECT, col_sel[col_index]);
    203                 waitInputPinDelay();
    204 #            endif
    205                 state |= (gpio_read_pin(col_pins[col_index]) == 0);
    206             }
    207             MATRIX_DEBUG_DELAY_END();
    208         } while (state);
    209     }
    210 #        endif
    211     if (MATRIX_IO_DELAY_ALWAYS || current_row + 1 < MATRIX_ROWS) {
    212         MATRIX_DEBUG_DELAY_START();
    213         matrix_output_unselect_delay(current_row, current_row_value != 0); // wait for col signal to go HIGH
    214         MATRIX_DEBUG_DELAY_END();
    215     }
    216 
    217     // If the row has changed, store the row and return the changed flag.
    218     if (current_matrix[current_row] != current_row_value) {
    219         current_matrix[current_row] = current_row_value;
    220         return true;
    221     }
    222     return false;
    223 }
    224 
    225 #    elif (DIODE_DIRECTION == ROW2COL)
    226 
    227 static void select_col(uint8_t col) {
    228     gpio_atomic_set_pin_output_low(col_pins[col]);
    229 }
    230 
    231 static void unselect_col(uint8_t col) {
    232     gpio_atomic_set_pin_input_high(col_pins[col]);
    233 }
    234 
    235 static void unselect_cols(void) {
    236     for (uint8_t x = 0; x < MATRIX_COLS; x++) {
    237         gpio_atomic_set_pin_input_high(col_pins[x]);
    238     }
    239 }
    240 
    241 static void init_pins(void) {
    242     unselect_cols();
    243     for (uint8_t x = 0; x < MATRIX_ROWS; x++) {
    244         gpio_atomic_set_pin_input_high(row_pins[x]);
    245     }
    246 }
    247 
    248 static bool read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col) {
    249     bool matrix_changed = false;
    250     bool key_pressed    = false;
    251 
    252     // Select col
    253     select_col(current_col);
    254     matrix_output_select_delay();
    255 
    256     // For each row...
    257     for (uint8_t row_index = 0; row_index < MATRIX_ROWS; row_index++) {
    258         // Store last value of row prior to reading
    259         matrix_row_t last_row_value    = current_matrix[row_index];
    260         matrix_row_t current_row_value = last_row_value;
    261 
    262         // Check row pin state
    263         if (gpio_read_pin(row_pins[row_index]) == 0) {
    264             // Pin LO, set col bit
    265             current_row_value |= (MATRIX_ROW_SHIFTER << current_col);
    266             key_pressed = true;
    267         } else {
    268             // Pin HI, clear col bit
    269             current_row_value &= ~(MATRIX_ROW_SHIFTER << current_col);
    270         }
    271 
    272         // Determine if the matrix changed state
    273         if ((last_row_value != current_row_value)) {
    274             matrix_changed |= true;
    275             current_matrix[row_index] = current_row_value;
    276         }
    277     }
    278 
    279     // Unselect col
    280     unselect_col(current_col);
    281     if (MATRIX_IO_DELAY_ALWAYS || current_col + 1 < MATRIX_COLS) {
    282         matrix_output_unselect_delay(current_col, key_pressed); // wait for col signal to go HIGH
    283     }
    284 
    285     return matrix_changed;
    286 }
    287 
    288 #    else
    289 #        error DIODE_DIRECTION must be one of COL2ROW or ROW2COL!
    290 #    endif
    291 #else
    292 #    error DIODE_DIRECTION is not defined!
    293 #endif
    294 
    295 void matrix_init(void) {
    296     // initialize key pins
    297     init_pins();
    298 
    299     // initialize matrix state: all keys off
    300     for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
    301         raw_matrix[i] = 0;
    302         matrix[i]     = 0;
    303     }
    304 
    305     debounce_init();
    306 
    307     matrix_init_kb();
    308 }
    309 
    310 uint8_t matrix_scan(void) {
    311     bool changed = false;
    312     MATRIX_DEBUG_PIN_INIT();
    313 
    314     MATRIX_DEBUG_SCAN_START();
    315 #if defined(DIRECT_PINS) || (DIODE_DIRECTION == COL2ROW)
    316     // Set row, read cols
    317     for (uint8_t current_row = 0; current_row < MATRIX_ROWS; current_row++) {
    318         changed |= read_cols_on_row(raw_matrix, current_row);
    319     }
    320 #elif (DIODE_DIRECTION == ROW2COL)
    321     // Set col, read rows
    322     for (uint8_t current_col = 0; current_col < MATRIX_COLS; current_col++) {
    323         changed |= read_rows_on_col(raw_matrix, current_col);
    324     }
    325 #endif
    326     MATRIX_DEBUG_SCAN_END();
    327     MATRIX_DEBUG_GAP();
    328 
    329     MATRIX_DEBUG_SCAN_START();
    330     debounce(raw_matrix, matrix, changed);
    331     MATRIX_DEBUG_SCAN_END();
    332     MATRIX_DEBUG_GAP();
    333 
    334     MATRIX_DEBUG_SCAN_START();
    335     matrix_scan_kb();
    336     MATRIX_DEBUG_SCAN_END();
    337     return (uint8_t)changed;
    338 }