qmk_firmware

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

matrix.c (9245B)


      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 "wait.h"
     18 #include "print.h"
     19 #include "debug.h"
     20 #include "util.h"
     21 #include "matrix.h"
     22 #include "debounce.h"
     23 
     24 #if (MATRIX_COLS <= 8)
     25 #    define print_matrix_header() print("\nr/c 01234567\n")
     26 #    define print_matrix_row(row) print_bin_reverse8(matrix_get_row(row))
     27 #    define ROW_SHIFTER ((uint8_t)1)
     28 #elif (MATRIX_COLS <= 16)
     29 #    define print_matrix_header() print("\nr/c 0123456789ABCDEF\n")
     30 #    define print_matrix_row(row) print_bin_reverse16(matrix_get_row(row))
     31 #    define ROW_SHIFTER ((uint16_t)1)
     32 #elif (MATRIX_COLS <= 32)
     33 #    define print_matrix_header() print("\nr/c 0123456789ABCDEF0123456789ABCDEF\n")
     34 #    define print_matrix_row(row) print_bin_reverse32(matrix_get_row(row))
     35 #    define ROW_SHIFTER ((uint32_t)1)
     36 #endif
     37 
     38 #ifdef MATRIX_MASKED
     39 extern const matrix_row_t matrix_mask[];
     40 #endif
     41 
     42 #ifdef DIRECT_PINS
     43 static pin_t direct_pins[MATRIX_ROWS][MATRIX_COLS] = DIRECT_PINS;
     44 #elif (DIODE_DIRECTION == ROW2COL) || (DIODE_DIRECTION == COL2ROW)
     45 // static const pin_t row_pins[MATRIX_ROWS] = MATRIX_ROW_PINS;
     46 static const pin_t col_pins[MATRIX_COLS] = MATRIX_COL_PINS;
     47 #endif
     48 
     49 /* matrix state(1:on, 0:off) */
     50 static matrix_row_t raw_matrix[MATRIX_ROWS]; // raw values
     51 static matrix_row_t matrix[MATRIX_ROWS];     // debounced values
     52 
     53 __attribute__((weak)) void matrix_init_kb(void) {
     54     matrix_init_user();
     55 }
     56 
     57 __attribute__((weak)) void matrix_scan_kb(void) {
     58     matrix_scan_user();
     59 }
     60 
     61 __attribute__((weak)) void matrix_init_user(void) {}
     62 
     63 __attribute__((weak)) void matrix_scan_user(void) {}
     64 
     65 inline uint8_t matrix_rows(void) {
     66     return MATRIX_ROWS;
     67 }
     68 
     69 inline uint8_t matrix_cols(void) {
     70     return MATRIX_COLS;
     71 }
     72 
     73 inline bool matrix_is_on(uint8_t row, uint8_t col) {
     74     return (matrix[row] & ((matrix_row_t)1 << col));
     75 }
     76 
     77 inline matrix_row_t matrix_get_row(uint8_t row) {
     78     // Matrix mask lets you disable switches in the returned matrix data. For example, if you have a
     79     // switch blocker installed and the switch is always pressed.
     80 #ifdef MATRIX_MASKED
     81     return matrix[row] & matrix_mask[row];
     82 #else
     83     return matrix[row];
     84 #endif
     85 }
     86 
     87 void matrix_print(void) {
     88     print_matrix_header();
     89 
     90     for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
     91         print_hex8(row);
     92         print(": ");
     93         print_matrix_row(row);
     94         print("\n");
     95     }
     96 }
     97 
     98 #ifdef DIRECT_PINS
     99 
    100 static void init_pins(void) {
    101     for (int row = 0; row < MATRIX_ROWS; row++) {
    102         for (int col = 0; col < MATRIX_COLS; col++) {
    103             pin_t pin = direct_pins[row][col];
    104             if (pin != NO_PIN) {
    105                 gpio_set_pin_input_high(pin);
    106             }
    107         }
    108     }
    109 }
    110 
    111 static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row) {
    112     matrix_row_t last_row_value = current_matrix[current_row];
    113     current_matrix[current_row] = 0;
    114 
    115     for (uint8_t col_index = 0; col_index < MATRIX_COLS; col_index++) {
    116         pin_t pin = direct_pins[current_row][col_index];
    117         if (pin != NO_PIN) {
    118             current_matrix[current_row] |= gpio_read_pin(pin) ? 0 : (ROW_SHIFTER << col_index);
    119         }
    120     }
    121 
    122     return (last_row_value != current_matrix[current_row]);
    123 }
    124 
    125 #elif (DIODE_DIRECTION == COL2ROW)
    126 /* Rows 0 - 5
    127  * These rows use a 74HC237D 3 to 8 bit demultiplexer.
    128  *                C    B    A
    129  * row / pin:    PB0  PB1  PB2
    130  * 0:             0    0    0
    131  * 1:             0    0    1
    132  * 2:             0    1    0
    133  * 3:             0    1    1
    134  * 4:             1    0    0
    135  * 5:             1    0    1
    136  */
    137 static void select_row(uint8_t col) {
    138     switch (col) {
    139         case 0:
    140             gpio_write_pin_low(B0);
    141             gpio_write_pin_low(B1);
    142             gpio_write_pin_low(B2);
    143             break;
    144         case 1:
    145             gpio_write_pin_low(B0);
    146             gpio_write_pin_low(B1);
    147             break;
    148         case 2:
    149             gpio_write_pin_low(B0);
    150             gpio_write_pin_low(B2);
    151             break;
    152         case 3:
    153             gpio_write_pin_low(B0);
    154             break;
    155         case 4:
    156             gpio_write_pin_low(B1);
    157             gpio_write_pin_low(B2);
    158             break;
    159         case 5:
    160             gpio_write_pin_low(B1);
    161             break;
    162     }
    163 }
    164 
    165 static void unselect_row(uint8_t col) {
    166     switch (col) {
    167         case 0:
    168             gpio_write_pin_high(B0);
    169             gpio_write_pin_high(B1);
    170             gpio_write_pin_high(B2);
    171             break;
    172         case 1:
    173             gpio_write_pin_high(B0);
    174             gpio_write_pin_high(B1);
    175             break;
    176         case 2:
    177             gpio_write_pin_high(B0);
    178             gpio_write_pin_high(B2);
    179             break;
    180         case 3:
    181             gpio_write_pin_high(B0);
    182             break;
    183         case 4:
    184             gpio_write_pin_high(B1);
    185             gpio_write_pin_high(B2);
    186             break;
    187         case 5:
    188             gpio_write_pin_high(B1);
    189             break;
    190     }
    191 }
    192 
    193 static void unselect_rows(void) {
    194     gpio_set_pin_output(B0);
    195     gpio_set_pin_output(B1);
    196     gpio_set_pin_output(B2);
    197     // make all pins high to select Y7, nothing is connected to that (otherwise the first row will act weird)
    198     gpio_write_pin_high(B0);
    199     gpio_write_pin_high(B1);
    200     gpio_write_pin_high(B2);
    201 }
    202 
    203 static void init_pins(void) {
    204     unselect_rows();
    205     for (uint8_t x = 0; x < MATRIX_COLS; x++) {
    206         gpio_set_pin_input_high(col_pins[x]);
    207     }
    208 }
    209 
    210 static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row) {
    211     // Store last value of row prior to reading
    212     matrix_row_t last_row_value = current_matrix[current_row];
    213 
    214     // Clear data in matrix row
    215     current_matrix[current_row] = 0;
    216 
    217     // Select row and wait for row selecton to stabilize
    218     select_row(current_row);
    219     wait_us(30);
    220 
    221     // For each col...
    222     for (uint8_t col_index = 0; col_index < MATRIX_COLS; col_index++) {
    223         // Select the col pin to read (active low)
    224         uint8_t pin_state = gpio_read_pin(col_pins[col_index]);
    225 
    226         // Populate the matrix row with the state of the col pin
    227         current_matrix[current_row] |= pin_state ? 0 : (ROW_SHIFTER << col_index);
    228     }
    229 
    230     // Unselect row
    231     unselect_row(current_row);
    232 
    233     return (last_row_value != current_matrix[current_row]);
    234 }
    235 
    236 #elif (DIODE_DIRECTION == ROW2COL)
    237 
    238 static void select_col(uint8_t col) {
    239     gpio_set_pin_output(col_pins[col]);
    240     gpio_write_pin_low(col_pins[col]);
    241 }
    242 
    243 static void unselect_col(uint8_t col) {
    244     gpio_set_pin_input_high(col_pins[col]);
    245 }
    246 
    247 static void unselect_cols(void) {
    248     for (uint8_t x = 0; x < MATRIX_COLS; x++) {
    249         gpio_set_pin_input_high(col_pins[x]);
    250     }
    251 }
    252 
    253 static void init_pins(void) {
    254     unselect_cols();
    255     for (uint8_t x = 0; x < MATRIX_ROWS; x++) {
    256         gpio_set_pin_input_high(row_pins[x]);
    257     }
    258 }
    259 
    260 static bool read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col) {
    261     bool matrix_changed = false;
    262 
    263     // Select col and wait for col selecton to stabilize
    264     select_col(current_col);
    265     wait_us(30);
    266 
    267     // For each row...
    268     for (uint8_t row_index = 0; row_index < MATRIX_ROWS; row_index++) {
    269         // Store last value of row prior to reading
    270         matrix_row_t last_row_value = current_matrix[row_index];
    271 
    272         // Check row pin state
    273         if (gpio_read_pin(row_pins[row_index]) == 0) {
    274             // Pin LO, set col bit
    275             current_matrix[row_index] |= (ROW_SHIFTER << current_col);
    276         } else {
    277             // Pin HI, clear col bit
    278             current_matrix[row_index] &= ~(ROW_SHIFTER << current_col);
    279         }
    280 
    281         // Determine if the matrix changed state
    282         if ((last_row_value != current_matrix[row_index]) && !(matrix_changed)) {
    283             matrix_changed = true;
    284         }
    285     }
    286 
    287     // Unselect col
    288     unselect_col(current_col);
    289 
    290     return matrix_changed;
    291 }
    292 
    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 
    313 #if defined(DIRECT_PINS) || (DIODE_DIRECTION == COL2ROW)
    314     // Set row, read cols
    315     for (uint8_t current_row = 0; current_row < MATRIX_ROWS; current_row++) {
    316         changed |= read_cols_on_row(raw_matrix, current_row);
    317     }
    318 #elif (DIODE_DIRECTION == ROW2COL)
    319     // Set col, read rows
    320     for (uint8_t current_col = 0; current_col < MATRIX_COLS; current_col++) {
    321         changed |= read_rows_on_col(raw_matrix, current_col);
    322     }
    323 #endif
    324 
    325     debounce(raw_matrix, matrix, changed);
    326 
    327     matrix_scan_kb();
    328     return 1;
    329 }